最简单的解决方案是直接在标准化设备坐标中定义四边形并将 z 值设置为 1。然后您不需要投影四边形,它将填充屏幕并在其他任何东西之后 - 除了也在 z 处的东西=1 投影和透视分割后。
这几乎是屏幕对齐四边形的标准过程,除了通常不需要将四边形放在 z=1 处,这无关紧要。通常,全屏四边形仅用于每个像素至少处理一次片段,通常是片段和像素的 1:1 映射。延迟着色、后期处理 fx 或图像处理通常是常见的问题。由于您在大多数情况下仅渲染四边形(仅此而已),因此深度值是无关紧要的,只要它在单位立方体内并且没有被深度测试丢弃,例如当您将它放在 z=1 和您的深度函数时是LESS
。
编辑:我犯了一个小错误。NDC 是在左手坐标系中定义的,这意味着近平面映射到 -1,远平面映射到 1。因此,您需要在 NDC 中定义四边形,z 值为 1,并将其设置DepthFunc
为LEQUAL
。或者,您可以保持深度函数不变,只需从 1.f 中减去一个非常小的值:
float maxZ = 1.f - std::numeric_limits<float>::epsilon();
EDIT2:假设您要渲染一个屏幕对齐的四边形,该四边形绘制在其他所有内容的后面并具有适当的纹理坐标。请注意:我在桌面上,所以我正在编写不直接映射到 GLES 2.0 的核心 GL 代码。但是,在我的示例中,没有什么是 GLES 和 GLSL ES 2.0 不能做的。
您可以像这样定义四边形的顶点属性(不会弄乱深度函数):
GLfloat maxZ = 1.f - std::numeric_limits<GLfloat>::epsilon ();
// interleaved positions an tex coords
GLfloat quad[] = {-1.f, -1.f, maxZ, 1.f, // v0
0.f, 0.f, 0.f, 0.f, // t0
1.f, -1.f, maxZ, 1.f, // ...
1.f, 0.f, 0.f, 0.f,
1.f, 1.f, maxZ, 1.f,
1.f, 1.f, 0.f, 0.f,
-1.f, 1.f, maxZ, 1.f,
0.f, 1.f, 0.f, 0.f};
GLubyte indices[] = {0, 1, 2, 0, 2, 3};
相应地设置 VAO 和缓冲区:
// generate and bind a VAO
gl::GenVertexArrays (1, &vao);
gl::BindVertexArray (vao);
// setup our VBO
gl::GenBuffers (1, &vbo);
gl::BindBuffer (gl::ARRAY_BUFFER, vbo);
gl::BufferData (gl::ARRAY_BUFFER, sizeof(quad), quad, gl::STATIC_DRAW);
// setup out index buffer
gl::GenBuffers (1, &ibo);
gl::BindBuffer (gl::ELEMENT_ARRAY_BUFFER, ibo);
gl::BufferData (gl::ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, gl::STATIC_DRAW);
// setup our vertex arrays
gl::VertexAttribPointer (0, 4, gl::FLOAT, gl::FALSE_, 8 * sizeof(GLfloat), 0);
gl::VertexAttribPointer (1, 4, gl::FLOAT, gl::FALSE_, 8 * sizeof(GLfloat), (GLvoid*)(4 * sizeof(GLfloat)));
gl::EnableVertexAttribArray (0);
gl::EnableVertexAttribArray (1);
着色器代码是一个非常非常简单的直通顶点着色器,为了简单起见,一个片段着色器在我的示例中只是导出插值的 tex 坐标:
// Vertex Shader
#version 430 core
layout (location = 0) in vec4 Position;
layout (location = 1) in vec4 TexCoord;
out vec2 vTexCoord;
void main()
{
vTexCoord = TexCoord.xy;
// you don't need to project, you're already in NDCs!
gl_Position = Position;
}
//Fragment Shader
#version 430 core
in vec2 vTexCoord;
out vec4 FragColor;
void main()
{
FragColor = vec4(vTexCoord, 0.0, 1.0);
}
如您所见,写入的值gl_Position
只是传递给着色器调用的顶点位置。没有投影发生,因为投影和透视分割的结果只不过是标准化的设备坐标。由于我们已经在 NDC 中,我们不需要投影和透视划分,因此只需通过原样的位置。
最终深度非常接近深度范围的最大值,因此四边形将出现在场景中其他物体的后面。
您可以像往常一样使用 texcoords。
我希望你能明白。除了 GLES 2.0 不支持的显式属性位置(即用 BindAttribLocation() 调用替换这些东西)之外,您不需要做任何事情。