1

代码流程如下:

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
renderScene();
renderTexturedQuadForBackground();
presentRenderbuffer();

尽管场景首先渲染,我有什么方法可以让纹理四边形渲染代码在场景后面显示?假设我无法更改背景纹理四边形的渲染将在我呈现渲染缓冲区之前直接发生。

改写:我无法更改渲染顺序。本质上,我想要的是每个仅由 glClearColor 着色的像素,而是由这个带纹理的四边形着色。

4

2 回答 2

4

最简单的解决方案是直接在标准化设备坐标中定义四边形并将 z 值设置为 1。然后您不需要投影四边形,它将填充屏幕在其他任何东西之后 - 除了也在 z 处的东西=1 投影和透视分割后。

这几乎是屏幕对齐四边形的标准过程,除了通常不需要将四边形放在 z=1 处,这无关紧要。通常,全屏四边形仅用于每个像素至少处理一次片段,通常是片段和像素的 1:1 映射。延迟着色、后期处理 fx 或图像处理通常是常见的问题。由于您在大多数情况下仅渲染四边形(仅此而已),因此深度值是无关紧要的,只要它在单位立方体内并且没有被深度测试丢弃,例如当您将它放在 z=1 和您的深度函数时是LESS

编辑:我犯了一个小错误。NDC 是在左手坐标系中定义的,这意味着近平面映射到 -1,远平面映射到 1。因此,您需要在 NDC 中定义四边形,z 值为 1,并将其设置DepthFuncLEQUAL。或者,您可以保持深度函数不变,只需从 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() 调用替换这些东西)之外,您不需要做任何事情。

于 2013-09-18T09:53:09.713 回答
0

有一种方法,但你必须把四边形放在幕后。如果您的四边形构造正确,您可以使用 DEPTH_TEST 启用

glEnable(DEPTH_TEST);

然后通过使用

glDepthFunc(GL_GREATER);

在渲染背景之前。您的四边形将在场景后面渲染。但正如我所说,这仅在您的几何图形实际上位于场景后面时才有效。

于 2013-09-18T09:52:24.157 回答