首页 > 解决方案 > 根据软件渲染器生成的 2D 视觉填充深度缓冲区

问题描述

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

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

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


编辑 2:继续研究我可以在这里做什么我发现这个讨论建议我“使用帧缓冲区对象或写入 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:

如果我理解正确,在做了更多阅读之后,我认为我需要做以下事情,但是我不能让它工作。这里的某些东西看起来明显不正确吗?我发现正在发生的事情是在片段着色器中 sampler2Dstex0tex1以某种方式包含相同的值,因此,我要么能够将颜色值写入颜色,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);

标签: opengldepth-buffer

解决方案


我想指出 Ripi2 的回答真正引导我完成了这个问题,但是我想我会写一个答案来解决我的问题,我最终需要做什么,我的问题出了什么问题,现在找到了我的方式通过这个问题。

首先,我的问题有什么问题?我对 OpenGL 纹理有几个误解——但最根本的是。我将纹理误解为图像的“容器”,我现在的理解是它是一个缓冲区,并且可以包含除了简单的“图像”之外的信息(例如,纹理可以存储 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);

我的 Frag 着色器采样器最终看起来像这样匹配:

 uniform sampler2D ColorValueTexture;
 uniform sampler2D DepthValueTexture;

只是在这一点上,我A)现在不仅拥有纹理,而且还了解如何在我的着色器中对它们进行采样,并且B)将我的数据放在正确的位置,这样我就可以了解我在绘图时到底发生了什么。我看到了一个令人困惑的结果,其中一个纹理的数据似乎出现在另一个纹理中,我也能够通过将“绘图阶段”分成两个较小的阶段来解决这个问题,如下所示:

首先我使用颜色纹理绘制:

// 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);

重要的是要注意,我只在使用深度纹理时才启用深度测试!


推荐阅读