我的情况是这样的: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 tex0
和 tex1
以某种方式包含相同的值,因此,我可以将颜色值写入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_TYPE
是 GL_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/