在 opengl 场景的背景中绘制纹理四边形



代码流如下:

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

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

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

最简单的解决方案是直接在规范化设备坐标中定义四边形,并将 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:假设您要渲染一个屏幕对齐的四边形,该四边形绘制在其他所有内容后面并具有适当的纹理坐标。请注意:我在这里的桌面上,所以我正在编写核心 GL 代码,它不会直接映射到 GLES 2.0。但是,在我的考试中,没有什么是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()调用替换这些内容)之外,您不必做任何事情。

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

glEnable(DEPTH_TEST);

然后通过使用

glDepthFunc(GL_GREATER);

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

相关内容

  • 没有找到相关文章

最新更新