平移测试在翻译时起作用,但在指定z坐标时不起作用(2D渲染)

时间:2016-09-17 08:42:49

标签: android opengl-es depth-buffer opengl-es-3.0

问题

似乎我在Android OpenGL ES 3.0中发现了深度测试的问题。 要不然,或者我有某种实施缺陷。我注意到,当我通过修改模型矩阵来翻译几何体时,深度测试工作正常;但是,当我尝试通过在几何体中指定位置数据来执行相同操作时,深度测试失败。最后渲染的几何体显示在先前渲染的几何体后面。

<小时/> 我的目标是执行2D渲染,使得每个像素对应于世界空间中的1个单位。要执行此操作,我会调用glViewportMatrix.orthoM来设置投影矩阵:

GLES30.glViewport(0, 0, width, height);
Matrix.orthoM(projectionMatrix, 0, 0, width, 0, height, 0, 10.0f);

这会导致投影使用TextureView的整个宽度和高度,并提供10个单位深度(z轴)的剪辑空间。

在曲面创建过程中,我确保启用深度测试(使用默认深度函数):

GLES30.glEnable(GLES30.GL_DEPTH_TEST);

最后但同样重要的是,我还确保清除每个并条机的深度缓冲区:

GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT | GLES30.GL_DEPTH_BUFFER_BIT);

以上调用应设置深度缓冲。剩下的就是定义一个视图矩阵,它在渲染任何几何体之前在每个绘制框架中完成:

Matrix.setLookAtM(viewMatrix, 0, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);

参数指定远离屏幕的eyePosition = { 0.0f, 0.0f, 1.0f}(朝向观察者),眼睛正在看centerPosition = { 0.0f, 0.0f, 0.0f},这是世界的起源。此视图矩阵应仅在不旋转的情况下将相机移离场景(因为我在2D中渲染)。

<小时/>

使用模型矩阵转换几何体:

通过使用模型矩阵转换几何图形,我可以有效地使深度测试正常工作。几何图形根据指定的z-index按顺序呈现。

在绘图功能中,对于我想绘制的每个矩形(钢琴键)执行以下代码:

Matrix.setIdentityM(modelMatrix, 0);
if (keys[index].keyType == WHITE_KEY) {
    Matrix.translateM(modelMatrix, 0, 0.0f, 0.0f, keys[index].zIndex);
} else {
    Matrix.translateM(modelMatrix, 0, 0.0f, 0.0f, keys[index].zIndex);
}
Matrix.translateM(modelMatrix, 0, translateX, 0.0f, 0.0f);
GLES30.glUniformMatrix4fv(GLES30.glGetUniformLocation(shaderProgram, "model"), 1, false, modelMatrix, 0);
GLES30.glUniformMatrix4fv(GLES30.glGetUniformLocation(shaderProgram, "view"), 1, false, viewMatrix, 0);
GLES30.glUniformMatrix4fv(GLES30.glGetUniformLocation(shaderProgram, "projection"), 1, false, projectionMatrix, 0);

keys[index].draw();

这给出了正确的结果。请注意,即使所有按键按从左到右的顺序渲染,所有黑键都会显示在顶部。

Depth Test Working

使用位置数据转换几何图形:

我希望在矩形的实际顶点数据中指定z-index。因此,我使用以下代码而不是上面的渲染代码:

Matrix.setIdentityM(modelMatrix, 0);
Matrix.translateM(modelMatrix, 0, translateX, 0.0f, 0.0f);
GLES30.glUniformMatrix4fv(GLES30.glGetUniformLocation(shaderProgram, "model"), 1, false, modelMatrix, 0);
GLES30.glUniformMatrix4fv(GLES30.glGetUniformLocation(shaderProgram, "view"), 1, false, viewMatrix, 0);
GLES30.glUniformMatrix4fv(GLES30.glGetUniformLocation(shaderProgram, "projection"), 1, false, projectionMatrix, 0);

keys[index].draw();

请注意,唯一的区别是我不再根据z-index值翻译几何体。相反,我在实际顶点数据中指定z-index:

float[] vertexData = new float[] {
        x, y, zIndex, //Specify z-index in vertex data.
        0, 0, //Texture coordinates.
        x + width, y, zIndex, //Specify z-index in vertex data.
        1, 0, //Texture coordinates.
        x, y + height, zIndex, //Specify z-index in vertex data.
        0, 1, //Texture coordinates.
        x + width, y + height, zIndex, //Specify z-index in vertex data.
        1, 1  //Texture coordinates.
};

int[] indexData = new int[] {
        0, 1, 3,
        0, 3, 2
};

//Set up VAO, VBO, and EBO with the data above (works properly, but is
//provided for the sake of completion).
FloatBuffer vertexBuffer = ByteBuffer.allocateDirect(vertexData.length * 4)
        .order(ByteOrder.nativeOrder()).asFloatBuffer();
vertexBuffer.put(vertexData).position(0);

IntBuffer indexBuffer = ByteBuffer.allocateDirect(indexData.length * 4)
        .order(ByteOrder.nativeOrder()).asIntBuffer();
indexBuffer.put(indexData).position(0);

GLES30.glGenVertexArrays(1, vao, 0);
GLES30.glGenBuffers(1, vbo, 0);
GLES30.glGenBuffers(1, ebo, 0);

GLES30.glBindVertexArray(vao[0]);

GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, vbo[0]);
GLES30.glBufferData(GLES30.GL_ARRAY_BUFFER, vertexData.length * 4, vertexBuffer, GLES30.GL_STATIC_DRAW);
GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER, ebo[0]);
GLES30.glBufferData(GLES30.GL_ELEMENT_ARRAY_BUFFER, indexData.length * 4, indexBuffer, GLES30.GL_STATIC_DRAW);

//Point to vertex positions (stride = size of vertex in bytes = 5 components *4 bytes per float = 20)
GLES30.glEnableVertexAttribArray(0);
GLES30.glVertexAttribPointer(0, 2, GLES30.GL_FLOAT, false, VERTEX_STRIDE, 0);

GLES30.glEnableVertexAttribArray(1);
GLES30.glVertexAttribPointer(1, 2, GLES30.GL_FLOAT, false, VERTEX_STRIDE, VERTEX_POSITION_COMPONENTS * 4);

GLES30.glBindVertexArray(0);

删除翻译后,我会收到以下结果。请注意,尽管我们从左到右渲染它们,但最后一个键在前面的键后面呈现。另请注意,zIndex = -1.0f表示白键,而zIndex = 0.0f表示黑键。与黑键相比,这应该使白键进一步进入屏幕。两个键都应该在提供给Matrix.orthoM的剪切空间内可见(因为视图矩阵从屏幕上移开了1个单位,有效的 zNear zFar 值分别为1.0f-9.0f

Depth Test Not Working

<小时/>

问题

在获得正确的深度测试结果的同时,如何在顶点数据中指定zIndex,我需要做什么?

<小时/>

代码

顶点着色器

#version 300 es

layout (location = 0) in vec3 position;
layout (location = 1) in vec2 texCoord;

out vec2 TexCoord;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

void main()
{
    gl_Position = projection * view * model * vec4(position, 1.0f);

    //Pass texture coordinate to fragment shader.
    TexCoord = texCoord;
}

片段着色器

#version 300 es

in vec2 TexCoord;

out vec4 color;

uniform sampler2D texture;

void main()
{
    vec2 flippedTexCoord = vec2(TexCoord.x, 1.0 - TexCoord.y);
    color = texture(texture, flippedTexCoord);
}

1 个答案:

答案 0 :(得分:2)

您正在将您的位置属性设置为只有两个组件:

GLES30.glVertexAttribPointer(0, 2, GLES30.GL_FLOAT, false, VERTEX_STRIDE, 0);

第二个参数指定组件数。所以这应该是:

GLES30.glVertexAttribPointer(0, 3, GLES30.GL_FLOAT, false, VERTEX_STRIDE, 0);

或者,既然你似乎有一个为此目的定义的常量,你也可以在这里使用它:

GLES30.glVertexAttribPointer(0, VERTEX_POSITION_COMPONENTS, GLES30.GL_FLOAT, false, VERTEX_STRIDE, 0);