OpenGL - 帧缓冲区深度纹理与颜色深度纹理不同
我正在 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”时,深度会因某些比例和某些常数而有所不同。
当我在这个采样深度中添加一些软糖因子数字时,我可以让它发挥作用,但这真的很困难,而且感觉很糟糕。
我真的不知道出了什么问题,从技术上讲,采样时两个纹理应该是相同的。由于 RGB 的准确性,我无法继续使用“color_texture”。我确实需要切换,但我一生都无法弄清楚为什么深度纹理给出不同的值。
我之前已经多次编程过阴影贴图,这对我来说并不是一个新概念。
任何人都可以阐明这一点吗?
I'm doing shadow mapping in OpenGL - as such I've created a frame buffer object where I render the depth of the scene from the view of a light.
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);
This then renders the scene from the light perspective as normal, all as you would expect. The only addition is I'm using a custom shader to render the depth of the scene also to the "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);
}
I can write these two textures "color_texture" and "depth_texture" to the screen using a full screen quad. Both are indeed depth maps and look correct. Now for the weird bit.
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.
When I added some fudge factor numbers to this sampled depth I could sort of get it to work, but it was really difficult and it just felt horrible.
I really can't tell what is wrong, technically the two textures should be identical when sampled. I can't carry on using "color_texture" due to the accuracy of RGB. I really need to switch but I can't for the life of me work out why the depth texture gives a different value.
I've programmed shadow mapping several times before and it isn't a concept that is new to me.
Can anyone shed any light on this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您的着色器存在一些问题。首先,
screen_position
不是屏幕位置;这是剪辑空间顶点位置。屏幕空间与您的显示器相关,因此如果您移动窗口,屏幕空间就会发生变化。你永远无法获得任何东西的屏幕空间位置; OpenGL 只进入窗口空间(相对于窗口的位置)。其次,这:
不计算深度。它计算标准化设备坐标 (NDC) 空间 Z 位置,范围为 [-1, 1]。 Depth 是一个窗口空间值,它是在使用视口变换(由 glViewport 和 glDepthRange 指定)对 NDC 空间值进行变换之后出现的。此变换将深度置于 [0, 1] 范围内。
第三,最重要的是,这一切都是你手动完成的;让 GLSL 为您做:
看到了吗?好多了。
现在:
当然是。那是因为您认为深度是 NDC Z 值。 OpenGL 将实际窗口空间 Z 值写入深度。所以你需要使用窗口空间。 OpenGL 足够好,可以为片段着色器提供一些统一,使这一切变得更容易。您可以使用这些制服将 NDC 空间 Z 值转换为窗口空间 Z 值。
There are some issues with your shader. First,
screen_position
is not a screen position; that's the clip-space vertex position. Screen space would be relative to your monitor, and therefore would change if you moved the window around. You never get screen-space positions of anything; OpenGL only goes down to window space (relative to the window's location).Second, this:
does not compute depth. It computes the normalized-device coordinate (NDC) space Z position, which ranges from [-1, 1]. Depth is a window-space value, which comes after the NDC space value is transformed with the viewport transform (specified by glViewport and glDepthRange). This transform puts the depth on the [0, 1] range.
Most importantly third, you're doing this all manually; let GLSL do it for you:
See? Much better.
Now:
Of course it is. That's because you believed that the depth was the NDC Z-value. OpenGL writes the actual window-space Z value as the depth. So you need to work with window space. OpenGL is nice enough to provide some uniforms to your fragment shader to make this easier. You can use those uniforms to transform NDC-space Z values to window space Z values.