根据软件渲染器生成的 2D 视觉填充深度缓冲区
Populating the depth buffer based on a 2D visual produced from a software renderer
我的情况是这样的:作为 2D 纹理的 2D 图像是从实际说明“3D”视觉效果的软件渲染器生成的。 OpenGL 基本上只用于显示此 2D 纹理。因此,尽管渲染了看似 3D 视觉效果的内容,但无论我使用着色器渲染深度缓冲区可能做出的任何努力,都无法完成,因为那里实际上什么也没有。我想访问深度缓冲区以启用此类着色器。
所以,我想以某种方式根据我的图像填充深度缓冲区。我认为这是可行的,因为所讨论的软件渲染器可以生成 "depth map" 图像及其 "regular" 图像作为渲染模式——深度图图像看起来就像深度缓冲区的渲染(灰度,靠近相机的物体是黑色的)。所以我想我的问题是:我是否可以将表示深度的 "pre-rendered" 图像转换为深度缓冲区?我该怎么做呢?
编辑:如果这有帮助,我正在专门使用 OpenGL 3.3。
编辑 2:继续研究我在这里可以做的事情,我发现 this discussion 这表明我 "either use framebuffer objects or a fragment shader which writes to 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 的目标是将像素绘制到 window(或内部帧缓冲区)中。 window 是一个二维颜色容器。每种颜色都是 {0,1}
范围内的 4 值 (RGBA)(它会以某种方式转换为 {0,255}
范围)。
因为多个 基元(点、线或三角形)可能绘制在相同的 {x,y} 位置,所以第 3 个坐标(z
又名 "depth") 被使用,并存储在所谓的 "depth buffer".
当 片段着色器 输出具有 {x,y,z} 坐标的像素时,深度测试 完成根据深度缓冲区中的当前值对 z 值进行片段化。根据用于此测试的函数,此当前值会被 z 值替换或不替换。例如,这种方式允许的典型情况是像素靠近相机 "survive",其余像素为 "occluded"(阅读:忘记)。
一个纹理只不过是一个缓冲区,它的特点是它的值可以通过坐标而不是索引来获取。这个过程叫做"sampling".
纹理可以是 1/2/3 维缓冲区,每个维度在 {0, 1} 范围内。您可以指定当样本坐标与纹理中的 "cell" 不完全匹配时要执行的操作。这称为 "minification/magnification"。
作为缓冲区,纹理可以存储许多不同类型的值,从单个 'byte' 到组合的 'RGBA' 值。可以存储 深度分量 ,但不要将它与 帧深度缓冲区 混淆。
您必须说明纹理是如何填充的(例如读取 4 个浮点值,其他例如读取 1 个字节)以及它们是如何在内部存储和采样的。参见 doc。
现在我们正在接近解决您的问题。您可以拥有一个存储颜色的 2D 纹理和另一个存储 z 值的 2D 纹理。在片段着色器中,您 采样 并为 {x,y} 颜色和 gl_FragDepth
.
写入输出
任何数据都可能来自顶点到片段插值器,或来自纹理,或来自其他中间着色器或其他缓冲区。上面有两个纹理的段落只是一个例子。
重点是您知道数据的存储内容和存储位置,以及如何检索和使用它来输出 {x,y,z} 值。
编辑,在你的第 3 版之后
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,..., fb->depth)
GL_RGBA
类型应匹配(或至少易于转换)fb->depth
数据。例如,如果您有 'float' 值,则可以将它们内部存储在纹理的 'red' 通道中,宽度为 32 位:
glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F,..., fb->depth)
fb->depth
中的 float
值意味着 TEX_FORMAT
应该是唯一的频道,例如 GL_RED
和 TEX_TYPE
是 GL_FLOAT
.
如果您有整数值(例如在 {0, 255} 范围内),请使用不同的参数或只是 标准化 它们:除以 255 以获得 {0,1} 范围值。
在片段着色器中读取您在 glTexImage2D
中设置的相同通道。所以,对于 fb->depth:
gl_FragDepth = texture(tex1, uv).r;
不要忘记定义 uv
纹理坐标的获取方式。可能它们是顶点着色器的"out",FS中的"in"。
我想指出 Ripi2 的回答确实引导我解决了这个问题,但是我想我应该写一个答案来解决我的问题、我最终需要做什么以及我的问题有什么问题,现在已经找到了解决这个问题的方法。
首先,我的问题有什么问题?我对 OpenGL 纹理有一些误解,但最根本的是。我将纹理误解为图像的 "container",我现在的理解是它是一个缓冲区并且可以包含除简单 "an image" 之外的信息(例如,纹理可以存储 z 深度数据)。
据我所知,我的问题仍然存在:我有两张预渲染图像,一张说明颜色数据,另一张说明深度缓冲区数据。为了解决这个问题,首先我必须了解如何管理两个纹理:一个包含颜色数据,一个包含深度数据,这样我就可以对它们进行采样。
我的 OpenGL 代码(来自我问题中的第三次编辑)基本上缺少以下内容:
// get the uniform variables location
depthValueTextureLocation = glGetUniformLocation(program, "DepthValueTexture");
colorValueTextureLocation = glGetUniformLocation(program, "ColorValueTexture");
// specify the shader program to use
glUseProgram(program);
// bind the uniform variables locations
glUniform1i(depthValueTextureLocation, 0);
glUniform1i(colorValueTextureLocation, 1);
然后我的片段着色器采样器最终看起来像这样匹配:
uniform sampler2D ColorValueTexture;
uniform sampler2D DepthValueTexture;
只有在这一点上,我 A) 现在不仅有了纹理,而且了解了如何在我的着色器和 B)[ 中对其进行采样=34=] 将我的数据放在正确的位置,这样我就可以了解我在绘图时到底发生了什么。我看到一个令人困惑的结果,其中一个纹理的数据似乎出现在另一个纹理中,我也能够通过将我的 "drawing phase" 分成两个较小的阶段来解决这个问题:
首先我使用颜色纹理绘制:
// select the color value binding
glActiveTexture(GL_TEXTURE0 + 1);
glBindTexture(GL_TEXTURE_2D, texture);
// draw
glDrawArrays(GL_TRIANGLES, 0, 3);
然后我使用深度纹理绘制:
// select the depth value binding
glActiveTexture(GL_TEXTURE0 + 0);
glBindTexture(GL_TEXTURE_2D, depth_texture);
// draw
glEnable(GL_DEPTH_TEST);
glDrawArrays(GL_TRIANGLES, 0, 3);
glDisable(GL_DEPTH_TEST);
请务必注意,我专门只在使用深度纹理时启用了深度测试!
我的情况是这样的:作为 2D 纹理的 2D 图像是从实际说明“3D”视觉效果的软件渲染器生成的。 OpenGL 基本上只用于显示此 2D 纹理。因此,尽管渲染了看似 3D 视觉效果的内容,但无论我使用着色器渲染深度缓冲区可能做出的任何努力,都无法完成,因为那里实际上什么也没有。我想访问深度缓冲区以启用此类着色器。
所以,我想以某种方式根据我的图像填充深度缓冲区。我认为这是可行的,因为所讨论的软件渲染器可以生成 "depth map" 图像及其 "regular" 图像作为渲染模式——深度图图像看起来就像深度缓冲区的渲染(灰度,靠近相机的物体是黑色的)。所以我想我的问题是:我是否可以将表示深度的 "pre-rendered" 图像转换为深度缓冲区?我该怎么做呢?
编辑:如果这有帮助,我正在专门使用 OpenGL 3.3。
编辑 2:继续研究我在这里可以做的事情,我发现 this discussion 这表明我 "either use framebuffer objects or a fragment shader which writes to 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 的目标是将像素绘制到 window(或内部帧缓冲区)中。 window 是一个二维颜色容器。每种颜色都是 {0,1}
范围内的 4 值 (RGBA)(它会以某种方式转换为 {0,255}
范围)。
因为多个 基元(点、线或三角形)可能绘制在相同的 {x,y} 位置,所以第 3 个坐标(z
又名 "depth") 被使用,并存储在所谓的 "depth buffer".
当 片段着色器 输出具有 {x,y,z} 坐标的像素时,深度测试 完成根据深度缓冲区中的当前值对 z 值进行片段化。根据用于此测试的函数,此当前值会被 z 值替换或不替换。例如,这种方式允许的典型情况是像素靠近相机 "survive",其余像素为 "occluded"(阅读:忘记)。
一个纹理只不过是一个缓冲区,它的特点是它的值可以通过坐标而不是索引来获取。这个过程叫做"sampling".
纹理可以是 1/2/3 维缓冲区,每个维度在 {0, 1} 范围内。您可以指定当样本坐标与纹理中的 "cell" 不完全匹配时要执行的操作。这称为 "minification/magnification"。
作为缓冲区,纹理可以存储许多不同类型的值,从单个 'byte' 到组合的 'RGBA' 值。可以存储 深度分量 ,但不要将它与 帧深度缓冲区 混淆。
您必须说明纹理是如何填充的(例如读取 4 个浮点值,其他例如读取 1 个字节)以及它们是如何在内部存储和采样的。参见 doc。
现在我们正在接近解决您的问题。您可以拥有一个存储颜色的 2D 纹理和另一个存储 z 值的 2D 纹理。在片段着色器中,您 采样 并为 {x,y} 颜色和 gl_FragDepth
.
任何数据都可能来自顶点到片段插值器,或来自纹理,或来自其他中间着色器或其他缓冲区。上面有两个纹理的段落只是一个例子。
重点是您知道数据的存储内容和存储位置,以及如何检索和使用它来输出 {x,y,z} 值。
编辑,在你的第 3 版之后
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,..., fb->depth)
GL_RGBA
类型应匹配(或至少易于转换)fb->depth
数据。例如,如果您有 'float' 值,则可以将它们内部存储在纹理的 'red' 通道中,宽度为 32 位:
glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F,..., fb->depth)
fb->depth
中的 float
值意味着 TEX_FORMAT
应该是唯一的频道,例如 GL_RED
和 TEX_TYPE
是 GL_FLOAT
.
如果您有整数值(例如在 {0, 255} 范围内),请使用不同的参数或只是 标准化 它们:除以 255 以获得 {0,1} 范围值。
在片段着色器中读取您在 glTexImage2D
中设置的相同通道。所以,对于 fb->depth:
gl_FragDepth = texture(tex1, uv).r;
不要忘记定义 uv
纹理坐标的获取方式。可能它们是顶点着色器的"out",FS中的"in"。
我想指出 Ripi2 的回答确实引导我解决了这个问题,但是我想我应该写一个答案来解决我的问题、我最终需要做什么以及我的问题有什么问题,现在已经找到了解决这个问题的方法。
首先,我的问题有什么问题?我对 OpenGL 纹理有一些误解,但最根本的是。我将纹理误解为图像的 "container",我现在的理解是它是一个缓冲区并且可以包含除简单 "an image" 之外的信息(例如,纹理可以存储 z 深度数据)。
据我所知,我的问题仍然存在:我有两张预渲染图像,一张说明颜色数据,另一张说明深度缓冲区数据。为了解决这个问题,首先我必须了解如何管理两个纹理:一个包含颜色数据,一个包含深度数据,这样我就可以对它们进行采样。
我的 OpenGL 代码(来自我问题中的第三次编辑)基本上缺少以下内容:
// get the uniform variables location
depthValueTextureLocation = glGetUniformLocation(program, "DepthValueTexture");
colorValueTextureLocation = glGetUniformLocation(program, "ColorValueTexture");
// specify the shader program to use
glUseProgram(program);
// bind the uniform variables locations
glUniform1i(depthValueTextureLocation, 0);
glUniform1i(colorValueTextureLocation, 1);
然后我的片段着色器采样器最终看起来像这样匹配:
uniform sampler2D ColorValueTexture;
uniform sampler2D DepthValueTexture;
只有在这一点上,我 A) 现在不仅有了纹理,而且了解了如何在我的着色器和 B)[ 中对其进行采样=34=] 将我的数据放在正确的位置,这样我就可以了解我在绘图时到底发生了什么。我看到一个令人困惑的结果,其中一个纹理的数据似乎出现在另一个纹理中,我也能够通过将我的 "drawing phase" 分成两个较小的阶段来解决这个问题:
首先我使用颜色纹理绘制:
// select the color value binding
glActiveTexture(GL_TEXTURE0 + 1);
glBindTexture(GL_TEXTURE_2D, texture);
// draw
glDrawArrays(GL_TRIANGLES, 0, 3);
然后我使用深度纹理绘制:
// select the depth value binding
glActiveTexture(GL_TEXTURE0 + 0);
glBindTexture(GL_TEXTURE_2D, depth_texture);
// draw
glEnable(GL_DEPTH_TEST);
glDrawArrays(GL_TRIANGLES, 0, 3);
glDisable(GL_DEPTH_TEST);
请务必注意,我专门只在使用深度纹理时启用了深度测试!