似乎我在Android OpenGL ES 3.0中发现了深度测试的问题。 要不然,或者我有某种实施缺陷。我注意到,当我通过修改模型矩阵来翻译几何体时,深度测试工作正常;但是,当我尝试通过在几何体中指定位置数据来执行相同操作时,深度测试失败。最后渲染的几何体显示在先前渲染的几何体后面。
<小时/> 我的目标是执行2D渲染,使得每个像素对应于世界空间中的1个单位。要执行此操作,我会调用glViewport
和Matrix.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();
这给出了正确的结果。请注意,即使所有按键按从左到右的顺序渲染,所有黑键都会显示在顶部。
我希望在矩形的实际顶点数据中指定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
。
在获得正确的深度测试结果的同时,如何在顶点数据中指定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);
}
答案 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);