opengl - 根据软件渲染器生成的 2D 视觉效果填充深度缓冲区

标签 opengl depth-buffer

我的情况是这样的:2D 图像作为 2D 纹理,是由软件渲染器生成的,该软件渲染器实际上说明了“3D”视觉效果。 OpenGL 的主要用途就是显示该 2D 纹理。因此,尽管渲染了看似 3D 视觉效果的内容,无论我如何使用着色器来渲染深度缓冲区,它都无法完成,因为那里实际上什么也没有。我想访问深度缓冲区以启用此类着色器。

所以,我想以某种方式根据我的图像填充深度缓冲区。我认为这是可行的,因为所讨论的软件渲染器可以生成“深度图”图像及其“常规”图像作为渲染模式 - 深度图图像看起来与深度缓冲区的渲染完全相同(灰度,靠近相机的物体是黑色的)。所以我想我的问题是:我是否可以将表示深度的“预渲染”图像转换为深度缓冲区?我怎样才能做到这一点?

编辑:如果这有帮助,我正在专门使用 OpenGL 3.3。


编辑2:继续研究我可以在这里做什么,我发现了this discussion这建议我“要么使用帧缓冲区对象,要么使用写入 gl_FragDepth 的片段着色器”。然而,讨论很快就变得有点难以消化,我想我理解了写入 gl_FragDepth 的片段着色器的概念,但这在实践中实际上是如何工作的?

我想我会做类似以下伪代码的事情?

program = createProgram(); //write to gl_FragDepth in the frag shader
glUseProgram(program);

glColorMask(GL_FALSE,GL_FALSE,GL_FALSE,GL_FALSE);
glEnable(GL_DEPTH_TEST);
glGenTextures(1, &depth_texture);
glBindTexture(GL_TEXTURE_2D, depth_texture);

glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, depth->width, depth->height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, depth->pixels)
glDisable(GL_DEPTH_TEST);
glBindTexture(GL_TEXTURE_2D, 0);

我需要启用深度测试吗?


编辑3:

如果我理解正确,在做了更多阅读后,我认为我需要做如下的事情,但是我不能完全让它工作。这里有什么东西看起来明显不正确吗?我发现发生的情况是在碎片着色器中,sampler2Ds tex0tex1 以某种方式包含相同的值,因此,我可以将颜色值写入gl_FragDepth 或颜色的深度值,这会产生有趣但无用的结果。

碎片着色器总结:

out vec4 color;
uniform sampler2D tex0; // color values
uniform sampler2D tex1; // depth values

void main(void) {
    color = texture(tex0, uv);
    gl_FragDepth = texture(tex1, uv).z;
}

OpenGL 总结:

// declarations
static GLuint vao;
static GLuint texture = 1;
static GLuint depth_texture = 2;

// set up shaders
program = createProgram();
glUseProgram(program); //verified that this is working

// enable depth testing
glEnable(GL_DEPTH_TEST);

// prepare dummy VAO
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);

// prepare texture for color values
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);

// prepare texture for depth values
glActiveTexture(GL_TEXTURE1);
glGenTextures(1, &depth_texture);
glBindTexture(GL_TEXTURE_2D, depth_texture);

// disable depth mask while working with color values
glDepthMask(GL_FALSE);

// select GL_TEXTURE0 and bind the color values
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);

// specify texture image for colorvalues
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_width, tex_height, 0, TEX_FORMAT, TEX_TYPE, fb->pixels);

// enable depth mask while working with depth values
glDepthMask(GL_TRUE);

// select GL_TEXTURE1 and bind the depth values
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, depth_texture);

// specify texture image for depth values
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_width, tex_height, 0, TEX_FORMAT, TEX_TYPE, fb->depth);

// draw
glViewport(win_x, win_y, win_width, win_height);
glDrawArrays(GL_TRIANGLES, 0, 3);

最佳答案

我认为您对纹理有点困惑。这不是一个教程网站,因此我不会进行太多描述。

OpenGL 的目标是将像素绘制到窗口(或内部帧缓冲区)中。窗口是一个 2D 颜色容器。每种颜色都是 {0,1} 范围内的 4 值 (RGBA)(它将以某种方式转换为 {0,255} 范围)。

因为多个基元(点、线或三角形)可以绘制在相同的 {x,y} 位置,第三个坐标(z 又名“深度”)被使用,并存储在所谓的“深度缓冲区”中。

片段着色器输出具有 {x,y,z} 坐标的像素时,深度测试将根据当前值对片段 z 值进行在深度缓冲区中。根据此测试所使用的函数,当前值是否替换为 z 值。例如,这种方式允许出现以下典型情况:靠近相机的像素“幸存”,而其余像素被“遮挡”(读作:被遗忘)。

纹理只不过是一个缓冲区,它的特点是可以通过坐标而不是索引获取其值。这个过程称为“采样”。

纹理可以是 1/2/3 维缓冲区,每个维度都在 {0, 1} 范围内。您可以指定当样本坐标与纹理中的“单元格”不完全匹配时要执行的操作。这称为“缩小/放大”。

作为缓冲区,纹理可以存储许多不同类型的值,从单个“字节”到组合的“RGBA”值。可以存储深度分量,但不要将其与帧深度缓冲区混淆。
您必须告诉纹理如何填充(例如读取 4 个浮点值,其他例如读取 1 个字节)以及它们如何在内部存储和采样。请参阅doc .

现在我们即将解决您的问题。您可以使用一个存储颜色的 2D 纹理和另一个存储 z 值的 2D 纹理。在片段着色器中,您对两者进行采样并写入 {x,y} 颜色和 gl_FragDepth 的输出。

任何数据都可能来自顶点到片段插值器、纹理、其他中间着色器或其他缓冲区。上面有两个纹理的段落只是一个例子。
关键在于,您知道数据的存储内容和位置,以及如何检索和使用它来输出 {x,y,z} 值。


编辑,第三版之后

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,..., fb->depth)

GL_RGBA 类型应匹配(或至少易于转换)fb->深度 数据。例如,如果您有“ float ”值,则可以将它们内部存储在纹理的“红色” channel 中,宽度为 32 位:

glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F,..., fb->depth)

fb->深度中的float值意味着TEX_FORMAT应该是唯一的 channel ,例如GL_RED > 和 TEX_TYPEGL_FLOAT
如果您有整数值(例如在 {0, 255} 范围内),请使用不同的参数或将它们标准化:除以 255 以获得 {0,1} 范围值。

在片段着色器中读取您在 glTexImage2D 中设置的相同 channel 。所以,对于fb->深度:

gl_FragDepth = texture(tex1, uv).r;

不要忘记定义如何获取 uv 纹理坐标。它们可能是顶点着色器的“出”,在 FS 中“入”。

关于opengl - 根据软件渲染器生成的 2D 视觉效果填充深度缓冲区,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51267272/

相关文章:

performance - 使用 GLSL 创建深度缓冲区直方图纹理

JavafX 8 3D Z 顺序。重叠形状行为是错误的。

delphi - GLScene 中的 GLFlatText 分辨率问题

c++ - QT 和 OpenGL 的奇怪行为

opengl - 如何在片段着色器中使用 gl_FragCoord.z 在现代 OpenGL 中线性渲染深度?

c++ - 错误的深度缓冲区(到纹理)输出?

c++ - Open GL ES 2.0 多个drawElements和绘制顺序

opengl - 在片段着色器中使用textureCube访问环境贴图失败

user-interface - 如何安装 opengl 才能运行

linux - 在linux中用mingw编译opengl