2011-12-21 2 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(...), двигаться glBindTexture и glTexImage2D инициализировать функцию, изменять размер текстуры до 32 х 32, но ни один из них не работает.

Может ли кто-нибудь помочь мне понять, почему отображение текстур происходит не на реальных устройствах? Есть ли ограничение по графику или что-то еще?

EDIT: Я попробовал предложение Spoon и нашел настоящую проблему. Независимо от того, какую текстуру я связываю, устройство использует текстуру с именем для рендеринга квадрациклов, поэтому glBindTexture(GL_TEXTURE_2D, 0) отлично работает, но glBindTexture(GL_TEXTURE_2D, 1) и все, что возвращается glGenTextures(...). Это означает, что я могу сохранить только одну текстуру, но мне нужно использовать 2 или более.

ответ

0

Белый блок означает, что текстурирование работает, но текстуры не загружены должным образом.

Если фактическое сопоставление было проблемой, вы увидели бы текстуры, но все цвета были искажены или испорчены.

Проверить фактические значения, указанные glGenTextures(). Я обнаружил, что при использовании openGL-es 1.x в более поздних версиях android (2.2+), что glGenTextures() выбрасывает некоторые действительно случайные числа, а не дает идентификаторы 0,1,2,3 и т. Д. Возможно, вам приходится вручную поставлять ваши собственные идентификаторы, а не использовать glGenTextures()

В качестве альтернативы, проверьте правильность загрузки данных из файла. Пустые белые текстуры могут появляться, если у вас есть неправильное имя файла или файл отсутствует, но в него была включена некоторая обработка ошибок, которая позволяет продолжить приложение. И/или не забудьте обновить Рез папки или даже очистить проект, когда вы добавляете новые текстуры

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, и он сработал! В соответствии с [документацией] (http://www.khronos.org/opengles/documentation/opengles1_0/html/glBindTexture.html) 0 представляется зарезервированным именем текстуры, которое _представляет текстуру по умолчанию для каждой целевой текстуры и _если связаны к ним при инициализации, поэтому я сначала попробовал 1, но не смог. –

+0

Все еще есть проблемы, см. EDIT. –

+0

В 'init()' вы должны вызвать 'glBindTexture()' после 'glGenTexture' (или вручную назначить идентификатор), а затем установить параметры текстуры. Вероятно, поэтому он не работает, поскольку вы не устанавливаете параметры текстуры, кроме первой текстуры. Добавил мою реализацию к моему ответу. Моя все в джаве, но это не имеет значения. Работы по разгоревшему огню 2.3.4. –

0

Я переместил свои собственные методы JNI в отдельный класс-оболочку, аналогичный примеру gl2-jni в Android NDK, затем проблема решена. Я не знаю, почему внедрение статического native-кода в классе-оболочке делает различия, но в любом случае это работает.

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 
Смежные вопросы