2011-12-21 102 views
0

我試過一個簡單的程序,它動態生成紋理並使用NDK將其映射到四邊形。在模擬器上一切正常,但在真實設備上失敗。 這裏是我的代碼:無法在真實設備上使用OpenGL ES映射紋理

private static class Renderer implements GLSurfaceView.Renderer 
{ 
    @Override 
    public void onDrawFrame(GL10 gl) 
    { 
     nativeDrawFrame(); 
    } 

    @Override 
    public void onSurfaceChanged(GL10 gl, int width, int height) 
    { 
     nativeInit(width, height); 
    } 

    @Override 
    public void onSurfaceCreated(GL10 gl, EGLConfig config) 
    { 
     // do nothing... 
    } 
} 

和本地代碼:

const static GLfloat vertices_f[4][2] = 
{ 
    { 0.0f, 0.0f }, 
    { 100.0f, 0.0f }, 
    { 100.0f, 100.0f }, 
    { 0.0f, 100.0f } 
}; 

const static GLfloat texCoords_f[4][2] = 
{ 
    { 0.0f, 0.0f }, 
    { 1.0f, 0.0f }, 
    { 1.0f, 1.0f }, 
    { 0.0f, 1.0f } 
}; 

JNIEXPORT void JNICALL Java_com_sangfor_gltest_GLView_nativeInit(JNIEnv * env, jobject obj, jint width, jint height) 
{ 
    if (!bitmap) 
    { 
     // allocate dynamic texture memory 
     bitmap = memalign(16, 1024*1024); 
     if (!bitmap) 
     { 
      __android_log_print(ANDROID_LOG_ERROR, "native-render", "failed allocation."); 
      return; 
     } 
    } 

    glViewport(0, 0, width, height); 
    //glMatrixMode(GL_PROJECTION); 
    //glLoadIdentity(); 
    //glOrthox(0, 0x10000, 0, 0x10000, 0x10000, -0x10000); 
    //glClearColorx(0, 0, 0, 0); 
    glGenTextures(1, &texture); 
    __android_log_print(ANDROID_LOG_INFO, "native-render", "texture = %d", texture); 
    // glVertexPointer(2, GL_FIXED, 0, vertices); 
    // glTexCoordPointer(2, GL_FIXED, 0, texCoords); 
    //glEnableClientState(GL_COLOR_ARRAY); 
    glColor4x(0x10000, 0x10000, 0x10000, 0x10000); 
    glEnable(GL_TEXTURE_2D); 
    glDisable(GL_BLEND); 
    glDisable(GL_ALPHA_TEST); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); 
} 

JNIEXPORT void JNICALL Java_com_sangfor_gltest_GLView_nativeDrawFrame(JNIEnv * env, jobject obj) 
{ 
    struct timeval tv; 
    unsigned char color_value; 

    glClear(GL_COLOR_BUFFER_BIT); 

    // fill texture according to current timestamp 
    gettimeofday(&tv, NULL); 
    color_value = (unsigned char)(tv.tv_usec * 0.000255f); 
    memset(bitmap, color_value, 1024*1024); 
    __android_log_print(ANDROID_LOG_INFO, "native-render", "color_value = %d", color_value); 

    glBindTexture(GL_TEXTURE_2D, texture); 
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 256, 256, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, bitmap); 

    glBindTexture(GL_TEXTURE_2D, texture); 
    glEnableClientState(GL_TEXTURE_COORD_ARRAY); 
    glEnableClientState(GL_VERTEX_ARRAY); 

    glTexCoordPointer(2, GL_FLOAT, 0, texCoords_f); 
    glVertexPointer(2, GL_FLOAT, 0, vertices_f); 

    glMatrixMode(GL_MODELVIEW); 
    glLoadIdentity(); 
    glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 
    glFlush(); 
} 

在模擬器上它只是工作如我所料:在屏幕上的面積不斷改變其顏色。但是,當我在真實設備(Samsung Galaxy S 2.3.3和Asus Transformer TF101 3.2.1)上運行它時,它只顯示白色塊並且紋理映射似乎不起作用。

我試圖添加和註釋出投影變換,通過調用glEnable(GL_TEXTURE_2D)啓用紋理映射,通過調用glDisable(...)禁用alpha混合和測試,移動glBindTextureglTexImage2D到INIT功能,改變紋理尺寸爲32×32,但沒有這些工作。

任何人都可以幫助我找出爲什麼紋理映射僅在真實設備上失敗?是否有GPU限制或什麼?

編輯:我試過勺子的建議,發現真正的問題。無論我綁定哪個紋理,設備都會使用名爲的紋理來渲染四邊形,因此glBindTexture(GL_TEXTURE_2D, 0)可以正常工作,但glBindTexture(GL_TEXTURE_2D, 1)和任何由glGenTextures(...)返回的內容均會失敗。這意味着我只能保存一個紋理,但我必須使用2個或更多。

回答

0

白色塊意味着紋理正在工作,但紋理未正確加載。

如果實際的映射是一個問題,你會看到紋理,但所有的顏色扭曲或混亂。

檢查由glGenTextures()給出的實際值。我發現當在較新版本的android(2.2+)上使用openGL-es 1.x時,glGenTextures()丟棄了一些非常隨機的數字,而不是給出0,1,2,3等的id。可能需要手動提供您自己的ID而不使用glGenTextures()

或者,檢查像素數據是否正確地從文件加載。如果您的文件名錯誤或文件丟失,但已放入一些允許應用程序繼續的錯誤處理,則可能會顯示空白的白色紋理。和/或不要忘記刷新RES文件夾,甚至清理項目,當您添加新的紋理

UPDATE:

這是我做的:

public class Texture{ 

private int textureId = -1; 
// initialise to -1 

public int getTextureId(){ 
    return textureId; 
} 

public void loadTexture(GL10 gl, Context context){ 

    String[] filenamesplit = filename.split("\\."); 

    name = filenamesplit[filenamesplit.length-2]; 

    int[] textures = new int[1]; 
    //Generate one texture pointer... 
    //GLES20.glGenTextures(1, textures, 0);    
    textures[0] = ((IridianGraphicsEngine)context).texturecount; 
    ((IridianGraphicsEngine)context).texturecount++; 

    //...and bind it to our array 
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]); 

    //Create Nearest Filtered Texture 
    GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST); 
    GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); 

    //Different possible texture parameters, e.g. GLES20.GL_CLAMP_TO_EDGE 
    GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT); 
    GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT); 

    Bitmap bitmap = FileUtil.openBitmap(name, context); 

    GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0); 

    bitmap.recycle(); 

    textureId = textures[0]; 

} 
} 

然後繪製時:

public class Mesh{ 

private Texture texture; 

public void draw(GL10 gl){ 

    gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); 

    // Pass the vertex buffer in 
    gl.glVertexPointer(3, GL10.GL_FLOAT, 0, 
          vertices); 

    int textureId = texture.getTextureId(); 

    if(textureID>=0){ 

     // Enable Textures 
     gl.glEnable(GL10.GL_TEXTURE_2D); 

     // Get specific texture. 
     gl.glBindTexture(GL10.GL_TEXTURE_2D, textureID); 

     // Use UV coordinates. 
     gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY); 

     // Pass in texture coordinates   
     gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureCoordinates); 

    } 

    // Pass in vertex normals 
    gl.glNormalPointer(GL10.GL_FLOAT, 0, normals); 

    gl.glEnableClientState(GL10.GL_NORMAL_ARRAY); 

    gl.glDrawElements(GL10.GL_TRIANGLES, numindices,GL10.GL_UNSIGNED_SHORT, indices); 

    gl.glDisableClientState(GL10.GL_NORMAL_ARRAY); 

    if(textureID>=0){ 
     // Disable buffers   
     gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY); 
    } 

    gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); 

} 

然而,這是所有在java和使用OpenGL-ES 2.0紋理加載和OpenGL-ES 1.1的怪異混合用於繪製

+0

感謝您的答覆。我檢查了'glGenTextures()'返回的值。它確實拋出了大於100,000的隨機數。我用手動提供的數字0,它的工作!根據[documentation](http://www.khronos.org/opengles/documentation/opengles1_0/html/glBindTexture.html),0似乎是一個保留的紋理名稱,它表示每個紋理target_和__的默認紋理在初始化時給他們,所以我最初嘗試了1但失敗了。 – 2011-12-23 02:43:48

+0

仍然有問題,請參閱編輯。 – 2011-12-28 11:00:30

+0

在'init()'中,應該在'glGenTexture'(或手動分配一個ID)之後調用'glBindTexture()',然後設置紋理參數。這可能是它不工作的原因,因爲除了第一個紋理外,您不設置紋理參數。將我的實現添加到我的答案中。我的全部都是用java編寫的,但它不應該成爲問題。運行在2.3.4的點燃火上。 – 2011-12-28 13:31:08

0

我將我的JNI本地方法移動到單獨的包裝類,類似於Android NDK中的gl2-jni示例,然後解決了問題。我不知道爲什麼在包裝類中實現靜態本機代碼會產生差異,但無論如何,它都可以工作。

GLJNILib.java

// Wrapper for native library 
public class GLJNILib { 

    static { 
     System.loadLibrary("gljni"); 
    } 

    /** 
    * @param width the current view width 
    * @param height the current view height 
    */ 
    public static native void init(int width, int height); 
    public static native void step(); 
} 

GLJNIView.java

// some other stuff 

private class Renderer implements GLSurfaceView.Renderer { 
    private static final String TAG = "Renderer"; 
    public void onDrawFrame(GL10 gl) { 
     GLJNILib.step(); 
    } 

    public void onSurfaceChanged(GL10 gl, int width, int height) { 
     GLJNILib.init(width, height); 
    } 

    public void onSurfaceCreated(GL10 gl, EGLConfig config) { 
     // Do nothing. 
    } 
} 

// some other stuff