c - OpenGL - 帧缓冲区深度纹理不同于颜色深度纹理

标签 c opengl graphics rendering glsl

我在 OpenGL 中进行阴影贴图 - 因此我创建了一个帧缓冲区对象,我在其中从光线的角度渲染场景的深度。

glBindRenderbuffer(GL_RENDERBUFFER, color_buffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, color_buffer);

glBindRenderbuffer(GL_RENDERBUFFER, depth_buffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth_buffer);  

glGenTextures(1, &color_texture);
glBindTexture(GL_TEXTURE_2D, color_texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color_texture, 0);

glGenTextures(1, &depth_texture);
glBindTexture(GL_TEXTURE_2D, depth_texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_texture, 0);

然后,这会正常地从光线透视图渲染场景,正如您所期望的那样。唯一的补充是我使用自定义着色器将场景的深度也渲染到“color_texture”。

varying vec4 screen_position;

void main()
{
  screen_position = gl_ModelViewProjectionMatrix * gl_Vertex;
  gl_Position = screen_position;
}

--------------

varying vec4 screen_position;

void main()
{
  float depth = screen_position.z / screen_position.w;
  gl_FragColor = vec4(depth, depth, depth, 1.0);
}

我可以使用全屏四边形将这两个纹理“color_texture”和“depth_texture”写入屏幕。两者确实都是深度图并且看起来正确。现在来看奇怪的一点。

当实际渲染对象上的阴影时,采样“color_texture”深度效果很好,但当我切换到采样“depth_texture”时,深度因比例和常数而不同。

当我向这个采样深度添加一些软糖因子数字时,我可以让它工作,但这真的很困难,而且感觉很糟糕。

我真的不知道哪里出了问题,从技术上讲,这两个纹理在采样时应该是相同的。由于 RGB 的准确性,我无法继续使用“color_texture”。我真的需要切换,但我一辈子都弄不明白为什么深度纹理会给出不同的值。

我之前编写过多次阴影贴图,这对我来说并不是一个新概念。

任何人都可以阐明这一点吗?

最佳答案

您的着色器存在一些问题。首先,screen_position 不是屏幕位置;那是裁剪空间的顶点位置。屏幕空间将相对于您的显示器,因此如果您四处移动窗口,屏幕空间就会发生变化。你永远不会得到任何东西的屏幕空间位置; OpenGL 仅下降到窗口空间(相对于窗口的位置)。

第二,这个:

float depth = screen_position.z / screen_position.w;

不计算深度。它计算标准化设备坐标 (NDC) 空间 Z 位置,范围从 [-1, 1]。深度是一个窗口空间值,它是在 NDC 空间值通过视口(viewport)变换(由 glViewport 和 glDepthRange 指定)进行变换之后得到的。此转换将深度置于 [0, 1] 范围内。

最重要的第三点,你是手动完成这一切;让 GLSL 为你做:

void main()
{
  gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}

--------------

void main()
{
  gl_FragColor = vec4(gl_FragCoord.zzz, 1.0);
}

看到了吗?好多了。

现在:

When it comes to actually rendering the shadows on objects sampling the "color_texture" depth works fine, but when I switch to sampling "depth_texture", the depth is different by some scale and some constant.

当然可以。那是因为您认为深度是 NDC Z 值。 OpenGL 将实际的窗口空间 Z 值写入深度。所以你需要使用窗口空间。 OpenGL 足以提供一些 uniforms to your fragment shader使这更容易。您可以使用这些制服将 NDC 空间 Z 值转换为窗口空间 Z 值。

关于c - OpenGL - 帧缓冲区深度纹理不同于颜色深度纹理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6768602/

相关文章:

opengl - VBO 与立即模式性能

matlab - 沿曲线移动点(3D 动画图)

c - 在 C 中实现链表会发出警告,并且运行代码不会显示任何内容

javascript - 转换 flex/bison 解析器以在浏览器中使用

c++ - 尝试使用MAPI检索Outlook联系人。但是,仅返回具有电子邮件地址的联系人。有人知道我在做什么错吗?

java - 如何从 GUI 启动 Jzy3d 图?

c++ - 现代 OpenGL 仅 MacOS 黑屏

.net - 设置 ZedGraph 库中图形的最大值和最小值

linux - 用破折号绘制线段

c - 解析网络和解析文件之间有什么区别吗?