2012-11-06 11 views
2

기본 모양에 텍스처를 추가하기 위해 Android's example OpenGL 2.0 project 위에 비교적 간단한 확장을 추가하려고했습니다. 이 처럼 보이지만 특정 장치 (Samsung Nexus S, LG Optimus 3D, Samsung Galaxy S)에서는 텍스처가 렌더링되지 않습니다.GLES20 텍스처가 일부 장치에서 작동하지 않습니다.

이것은 실제로 더 큰 프로젝트에서 발생하는 문제이지만 아래의 간단한 프로젝트를 통해 다른 사람이 내 코드가 문제를 제시하는 아이디어를 갖고 있다는 희망에서 재현 할 수있었습니다. 이러한 장치에 대한 GL 텍스처를 구체적으로 설계하는 방법 (장치에 문제가있을 수 있습니다). GLSurfaceView.Renderer의 onSurfaceCreated 방법 나는 Square() 객체를 인스턴스화하고하고 방법에 내가 광장의 draw() 메소드를 호출하고 있습니다 :

이 객체를 사용하는 방법에 대한 아이디어를 제공합니다. 그러나 텍스처 처리 관련 코드는 모두이 Square 클래스에 표시되어야합니다.이 클래스는 Google의 예와 거의 동일합니다.

이 문제를 해결하는 사람에게 미리 감사드립니다.

class Square { 

private final String vertexShaderCode = 
    // This matrix member variable provides a hook to manipulate 
    // the coordinates of the objects that use this vertex shader 
    "uniform mat4 uMVPMatrix;" + 

    "attribute vec4 vPosition;" + 
    "attribute vec2 a_TexCoordinate;" + 

    "varying vec2 v_TexCoordinate;" + 

    "void main() {" + 
    // the matrix must be included as a modifier of gl_Position 
    " gl_Position = vPosition * uMVPMatrix;" + 
    " v_TexCoordinate = a_TexCoordinate;" + 
    "}"; 

private final String fragmentShaderCode = 
    "precision mediump float;" + 

    "uniform sampler2D u_Texture;" + 

    "varying vec2 v_TexCoordinate;" + 

    "void main() {" + 
    " gl_FragColor = texture2D(u_Texture, v_TexCoordinate);" + 
    "}"; 

private final FloatBuffer vertexBuffer; 
private final FloatBuffer textureBuffer; 
private final ShortBuffer drawListBuffer; 
private final int mProgram; 
private int mPositionHandle; 
private int mColorHandle; 
private int mMVPMatrixHandle; 

// number of coordinates per vertex in this array 
static final int COORDS_PER_VERTEX = 3; 
static float squareCoords[] = { -0.5f, 0.5f, 0.0f, // top left 
           -0.5f, -0.5f, 0.0f, // bottom left 
           0.5f, -0.5f, 0.0f, // bottom right 
           0.5f, 0.5f, 0.0f }; // top right 

final float[] previewTextureCoordinateData = 
    { 
     0.0f, 1.0f, 
     0.0f, 0.0f, 
     1.0f, 1.0f, 
     1.0f, 0.0f 
    }; 

private int textureDataHandle; 
private int textureUniformHandle; 
private int textureCoordinateHandle; 

private final short drawOrder[] = { 0, 1, 2, 0, 2, 3 }; // order to draw vertices 

private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex 

// Set color with red, green, blue and alpha (opacity) values 
float color[] = { 0.2f, 0.709803922f, 0.898039216f, 1.0f }; 

private int loadTexture(final Context context, final int resourceId) 
{ 
    final int[] textureHandle = new int[1]; 

    GLES20.glGenTextures(1, textureHandle, 0); 

    if (textureHandle[0] != 0) 
    { 
     final BitmapFactory.Options options = new BitmapFactory.Options(); 
     options.inScaled = false; // No pre-scaling 

     // Read in the resource 
     final Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resourceId, options); 

     // Bind to the texture in OpenGL 
     GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]); 

     // Set filtering 
     GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST); 
     GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST); 

     // Load the bitmap into the bound texture. 
     GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0); 

     // Recycle the bitmap, since its data has been loaded into OpenGL. 
     bitmap.recycle(); 
    } 

    if (textureHandle[0] == 0) 
    { 
     throw new RuntimeException("Error loading texture."); 
    } 

    return textureHandle[0]; 
} 

public Square(Context context) { 
    // initialize vertex byte buffer for shape coordinates 
    ByteBuffer bb = ByteBuffer.allocateDirect(
    // (# of coordinate values * 4 bytes per float) 
      squareCoords.length * 4); 
    bb.order(ByteOrder.nativeOrder()); 
    vertexBuffer = bb.asFloatBuffer(); 
    vertexBuffer.put(squareCoords); 
    vertexBuffer.position(0); 

    // initialize byte buffer for the draw list 
    ByteBuffer dlb = ByteBuffer.allocateDirect(
    // (# of coordinate values * 2 bytes per short) 
      drawOrder.length * 2); 
    dlb.order(ByteOrder.nativeOrder()); 
    drawListBuffer = dlb.asShortBuffer(); 
    drawListBuffer.put(drawOrder); 
    drawListBuffer.position(0); 


    ByteBuffer texCoordinates = ByteBuffer.allocateDirect(previewTextureCoordinateData.length * 4); 
    texCoordinates.order(ByteOrder.nativeOrder()); 
    textureBuffer = texCoordinates.asFloatBuffer(); 
    textureBuffer.put(previewTextureCoordinateData); 
    textureBuffer.position(0); 

    // prepare shaders and OpenGL program 
    int vertexShader = MyGLRenderer.loadShader(GLES20.GL_VERTEX_SHADER, 
               vertexShaderCode); 
    int fragmentShader = MyGLRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER, 
               fragmentShaderCode); 

    textureDataHandle = loadTexture(context, R.drawable.color_texture); 

    mProgram = GLES20.glCreateProgram();    // create empty OpenGL Program 
    GLES20.glAttachShader(mProgram, vertexShader); // add the vertex shader to program 
    GLES20.glAttachShader(mProgram, fragmentShader); // add the fragment shader to program 
    GLES20.glLinkProgram(mProgram);     // create OpenGL program executables 
} 

public void draw(float[] mvpMatrix) { 
    // Add program to OpenGL environment 
    GLES20.glUseProgram(mProgram); 

    // get handle to vertex shader's vPosition member 
    mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition"); 

    // Enable a handle to the triangle vertices 
    GLES20.glEnableVertexAttribArray(mPositionHandle); 

    // Prepare the triangle coordinate data 
    GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, 
           GLES20.GL_FLOAT, false, 
           vertexStride, vertexBuffer); 

    textureCoordinateHandle = GLES20.glGetAttribLocation(mProgram, "a_TexCoordinate"); 
    GLES20.glVertexAttribPointer(textureCoordinateHandle, 2, GLES20.GL_FLOAT, false, 
      0, textureBuffer); 
    GLES20.glEnableVertexAttribArray(textureCoordinateHandle); 

    textureUniformHandle = GLES20.glGetUniformLocation(mProgram, "u_Texture"); 
    MyGLRenderer.checkGlError("glGetUniformLocation"); 
    GLES20.glActiveTexture(GLES20.GL_TEXTURE0); 
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureDataHandle); 
    GLES20.glUniform1i(textureUniformHandle, 0);  

    // get handle to shape's transformation matrix 
    mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix"); 
    MyGLRenderer.checkGlError("glGetUniformLocation"); 

    // Apply the projection and view transformation 
    GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0); 
    MyGLRenderer.checkGlError("glUniformMatrix4fv"); 

    // Draw the square 
    GLES20.glDrawElements(GLES20.GL_TRIANGLES, drawOrder.length, 
          GLES20.GL_UNSIGNED_SHORT, drawListBuffer); 

    // Disable vertex array 
    GLES20.glDisableVertexAttribArray(mPositionHandle); 
} 
} 

답변

4

나는 이것이 Power-of-two 문제라고 생각합니다. 기본적

glTexParameterGL_TEXTURE_WRAP 설정 GL_REPEAT로 설정되고, GL_REPEAT마스트를 사용하여 텍스처 2 제곱 크기 일 :

마찬가지로 경우 텍스처 이미지의 너비 또는 높이 두없는 힘이 있으며 어느 GL_TEXTURE_MIN_FILTER 밉맵 또는 GL_TEXTURE_WRAP_S 또는 GL_TEXTURE_WRAP_T을 요구하는 기능들 중 하나에 설정되고, GL_CLAMP_TO_EDGE을 위해 그 텍스처 화상 부 w 설정되지 잘못된 반환 (R, G, B, A) = (0, 0, 0, 1).

당신은 전원의 - 두 개의 텍스처로 시작할 수 있습니다,하지만 당신은 비트 맵을 생성하는 BitmapFactory.decodeResource를 사용하는 경우, 그것은 유용하게 (?) 장치의 밀도에 따라이를 확장 할 수 있습니다. 예를 들어, HDPI 장치의 drawable 폴더에있는 512 * 512 소스 텍스처를로드하는 경우 1.5x로 크기가 조정되므로 Po2가 아닌 값이 남습니다.

이렇게하면 불규칙한 텍스처 크기를 생성하는 밀도가 있기 때문에 많은 수의 장치에서 텍스처가 작동하지 않는다는 결과를 얻을 수 있습니다.

이 경우 솔루션은 밀도 기반의 크기 조정을 방지하는 리소스 폴더 drawable-nodpi에 원본 텍스처를 배치하는 것입니다. 그 중 하나 또는 CLAMP_TO_EDGE, 어떤 Po2 상관 없어 사용하십시오.

+0

* 조사 중 ... * –

+0

이것은 실제로 문제를 해결합니다! 이제는 들어오는 카메라 피드 이미지에 이것을 적용하는 방법을 알아야합니다 ... 많은 휴대폰에서 Po2가되는 것을 거의 막을 것입니다. GL_CLAMP_TO_EDGE에 대한 자세한 내용을 읽고 nPo2 인 텍스처를 가장 효과적으로 사용하는 방법을 알아 봅니다. –

+1

texcoord 포장을 필요로하지 않는 한 NPO2 재질로 잘되어 있어야합니다. 특별히 기능을 필요로하지 않는 한 모든 것을 CLAMP_TO_EDGE로 설정했습니다. – Tim