OPENGL ES 2.0。 Android系统。深度缓冲区的奇怪行为

时间:2014-12-18 15:47:47

标签: android opengl-es

我的Android应用程序显示PowerVR SGX 544MP的意外行为。

  • 如果渲染设置为“RENDERMODE_WHEN_DIRTY”,它似乎就是 但是,如果模式设置,深度缓冲区不起作用 “RENDERMODE_CONTINUOUSLY”图纸右图:

错误的结果:

Wrong

正确的结果:

Proper

<小时/> 模拟器在两种情况下都是正确的。

  • 设备的默认缓冲区为24位,将缓冲区设置为相同 范围作为模拟器(16位)未更改的绘图。我尝试了各种各样的情况 投影矩阵的近和远值但不成功。

  • 我的矩阵中只有一个对近平面进行了修改 martix可能会在深度缓冲区中生成错误数据。我关掉了 在使用此矩阵绘制之前在深度缓冲区中写入。在那里面 在我调用之前,我设置了“GLES20.glDepthMask(false)” “glDrawElements”。


初始化OPENGL ES和与VBO一起工作对我来说是新的,所以也许我对麻烦的误解比我看起来更深。

  • 我发送统一的不同矩阵值并用相同的VBO绘制。
  • 我只对全局属性执行“启用”一次,之后我不再使用“禁用”。
    //MyGLSurfaceView
   public MyGLSurfaceView(Context context) {
        super(context);
        setEGLContextClientVersion(2);
    //    super.setEGLConfigChooser(8,8,8,8,16,0); // same result
        mRenderer = new MyGLRenderer(context);
        setRenderer(mRenderer);
        setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
   }

//MyGLRenderer
@Override
  public void onSurfaceCreated(GL10 unused, EGLConfig config) {
        GLES20.glClearColor(0.1f, 0.2f, 0.3f, 1.0f);
        GLES20.glEnable(GLES20.GL_BLEND);
        GLES20.glBlendEquation(GLES20.GL_FUNC_ADD);
        GLES20.glEnable(GLES20.GL_DEPTH_TEST);
        GLES20.glDepthRangef(0.f, 1.f);
        GLES20.glClearDepthf(1.f);
        GLES20.glEnable(GLES20.GL_CULL_FACE);
        GLES20.glFrontFace(GLES20.GL_CCW);
        GLES20.glDepthFunc(GLES20.GL_LEQUAL);
}
@Override
    public void onSurfaceChanged(GL10 unused, int width, int height) {
        // Adjust the viewport based on geometry changes,
        // such as screen rotation
        GLES20.glViewport(0, 0, width, height);
        float ratio = (float) width / height;
        perspectiveFieldOfViewRH(mProjectionMatrix, 0, 28.4f, ratio, 0.4f, 28.f);
}
 @Override
    public void onDrawFrame(GL10 unused) {
        GLES20.glDepthMask( true );
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
        int i,j;
        // turn off the writing. Only read
        GLES20.glDepthMask( false );
        GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ZERO);
        GLES20.glUseProgram(prg_shaderCube);
        // draw with modified projection matrix:
        for (i = 0; i < 4; i++){
            for (j = 0; j < 6; j++){
                System.arraycopy(arrFacesMatrices[i][j], 0, mModelMatrix, 0, 16);
                mModelMatrix[14] = translations[i];
                Matrix.multiplyMM(mMirrorFlankWithClippingMVP, 0, mMirrorFlankViewProjectionWithClippingMatrix, 0, mModelMatrix, 0);
                GLES20.glUniformMatrix4fv(u_changematrixCube, 1, false, mMirrorFlankWithClippingMVP, 0);
                GLES20.glUniformMatrix4fv(u_modelmatrixCube, 1, false, mModelMatrix, 0);
                GLES20.glCullFace(GLES20.GL_BACK);
                switch(pattern[i][j]){
                    case 0:
                        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vbo[0]);
                        GLES20.glVertexAttribPointer(attr_position_cube, 3, GLES20.GL_FLOAT, false, STRIDE_IN_FLAT, 0);
                        GLES20.glVertexAttribPointer(attr_color_cube, 3, GLES20.GL_FLOAT, false, STRIDE_IN_FLAT, 12);
                        GLES20.glVertexAttribPointer(attr_normal_cube, 3, GLES20.GL_FLOAT, false, STRIDE_IN_FLAT, 24);
                        GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, ibo[0]);
                        GLES20.glDrawElements(GLES20.GL_TRIANGLES, capacityFlat1, GLES20.GL_UNSIGNED_SHORT, 0);
                        break;
                    case 1:
                        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vbo[1]);
                        ....
                        break;
                        ....
                        ....
                }
            }
        }
        // others
        GLES20.glDepthMask( true );
        for (i = 3; i >= 0; i--){
            for (j = 0; j < 6; j++){
                System.arraycopy(arrFacesMatrices[i][j], 0, mModelMatrix, 0, 16);
                mModelMatrix[14] = translations[i];
                Matrix.multiplyMM(mMirrorFlankMVP, 0, mMirrorFlankViewProjectionMatrix, 0, mModelMatrix, 0);
                Matrix.multiplyMM(mMirrorDownMVP, 0, mMirrorDownViewProjectionMatrix, 0, mModelMatrix, 0);
                Matrix.multiplyMM(mMVP, 0, mViewMatrix, 0, mModelMatrix, 0);
                GLES20.glUniformMatrix4fv(u_modelmatrixCube, 1, false, mModelMatrix, 0);
                switch(pattern[i][j]){
                    case 0:
                        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vbo[0]);
                        GLES20.glVertexAttribPointer(attr_position_cube, 3, GLES20.GL_FLOAT, false, STRIDE_IN_FLAT, 0);
                        GLES20.glVertexAttribPointer(attr_color_cube, 3, GLES20.GL_FLOAT, false, STRIDE_IN_FLAT, 12);
                        GLES20.glVertexAttribPointer(attr_normal_cube, 3, GLES20.GL_FLOAT, false, STRIDE_IN_FLAT, 24);
                        GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, ibo[0]);
                        GLES20.glCullFace(GLES20.GL_FRONT);
                        GLES20.glUniformMatrix4fv(u_changematrixCube, 1, false, mMirrorFlankMVP, 0);
                        GLES20.glDrawElements(GLES20.GL_TRIANGLES, capacityFlat1, GLES20.GL_UNSIGNED_SHORT, 0);
                        GLES20.glUniformMatrix4fv(u_changematrixCube, 1, false, mMirrorDownMVP, 0);
                        GLES20.glDrawElements(GLES20.GL_TRIANGLES, capacityFlat1, GLES20.GL_UNSIGNED_SHORT, 0);
                        GLES20.glCullFace(GLES20.GL_BACK);
                        GLES20.glUniformMatrix4fv(u_changematrixCube, 1, false, mMVP, 0);
                        GLES20.glDrawElements(GLES20.GL_TRIANGLES, capacityFlat1, GLES20.GL_UNSIGNED_SHORT, 0);
                        break;
                    case 1:
                        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vbo[1]);
                        ....
                        break;
                        ....
                        ....
                }
            }
        }
}

我更喜欢使用模式RENDERMODE_WHEN_DIRTY,我想了解深度缓冲区发生了什么?

2 个答案:

答案 0 :(得分:0)

以下并不像我通常喜欢的答案那样具有决定性。特别是,我没有解释为什么RENDERMODE_WHEN_DIRTYRENDERMODE_CONTINUOUSLY之间的行为会有所不同。但无论如何,你的问题中有一点值得解释。

  

我的矩阵中只有一个修改了近平面。矩阵可能会在深度缓冲区中产生错误的数据。

你必须在这里非常小心。近平面和远平面之间的范围被映射到深度缓冲区的范围。因此,如果您使用标准投影矩阵并更改近平面,则此映射将更改。

换句话说,假设您使用给定z值(在眼睛坐标中)的顶点进行渲染,而投影矩阵的设置值接近near1。现在,您将投影矩阵设置为接近值near2,并使用具有相同 z值的顶点。此顶点现在将映射到不同的深度缓冲区值。因此,根据您的投影,相同的顶点将映射到不同的深度缓冲区值。或者,距离相机较远的顶点最终可以使用较小(较近)的深度缓冲值,因为您更改了投影矩阵。

您可以尝试通过相应地设置深度范围来弥补这一点。但是如果使用透视投影,即使这看起来也很棘手,因为眼睛空间深度的映射是深度缓冲值不是线性的。

如果你需要剪掉一些几何体的近似部分,你可能最好不要保持投影矩阵不变,并明确剪裁。 OpenGL ES不支持任意剪辑平面,因此最简单的方法是将距离传递给片段着色器,并丢弃那里的剪切片段。或者,无论如何,在应用程序代码中使用逻辑以避免渲染将被剪裁的几何体。

答案 1 :(得分:0)

添加调用glSurfaceView.requestRender()可以提高性能。我对深度缓冲的关注拖累了问题的真正原因。