ios - 在OpenGL场景背景中绘制纹理四边形

标签 ios opengl-es opengl-es-2.0 opengl-es-1.1

代码流如下:

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不支持的显式attrib位置(即用BindAttribLocation()调用代替东西)之外,您无需执行任何操作。

关于ios - 在OpenGL场景背景中绘制纹理四边形,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18868844/

相关文章:

c++ - 获取 QOpenGLFramebufferObject 抗锯齿纹理的替代方法,而不是多重采样 + blitting

java - Libgdx Android - GL 线程(NullPointerException)和丢失类文件

ios - 如何仅重新加载 UICollectionView 的数据部分?

ios - SwiftUI - 更改 KVKCalendar 的 CalendarType

objective-c - 将 base64 解码的 NSData 转换为 NSString

android - 如何对加载到 OpenGL 纹理中的 Android 资源位图使用高质量渲染?

ios - 什么是 iOS OpenGL ES 2.0 离屏帧缓冲区对象?

javascript - 由samplerCube引起的GL_INVALID_OPERATION

Android OpenGL ES 2.0 光照?

iphone - 如何重新定位尺寸动态变化的 UILabel 和 UIImageView?