OpenGL 在延迟渲染器中实现天空盒

OpenGL implementing skybox in a deferred renderer

我正在尝试弄清楚如何在延迟渲染器中渲染天空盒,以便它可以包含在 post 处理效果中,但是我的几何阶段正在查看 space 不幸的是这个阶段的天空盒会像任何物体一样受到它相对于光的位置的影响(它的行为就像距离光源很远的大盒子并且看起来很暗)。 我的设置没有尝试将天空盒合并到 post 处理中,如下所示:

1:(bind FBO) Render Geometry to color, normal, position FBO texture attachments (unbind FBO).

2:(绑定FBO)渲染场景并计算屏幕光照space。(取消绑定FBO)

3:(绑定FBO)应用post处理效果(解除绑定FBO)

4: 将 Geometry FBO 的深度缓冲区 blit 到默认帧缓冲区

5:渲染天空盒。

我试过将第 5 步换成第 3 步 像这样:

2:(绑定FBO)渲染场景并计算屏幕光照space.

5:渲染天空盒

(解绑FBO)

3:(绑定FBO)应用post处理效果(解除绑定FBO)

4: 将 Geometry FBO 的深度缓冲区 blit 到默认帧缓冲区

但显然天空盒没有关于场景的深度信息并且渲染在光照阶段的顶部。如果我尝试在 2 到 5 之间进行任何深度 blitting,我相信我正在进行无效的 GL 调用,因为我在调用

时已经绑定到 FBO
 GL30.glBindFramebuffer(GL30.GL_READ_FRAMEBUFFER, DeferredFBO.fbo_handle);
 GL30.glBindFramebuffer(GL30.GL_DRAW_FRAMEBUFFER, 0); // Write to default
                                                            // framebuffer or a skybox framebuffer    


    GL30.glBlitFramebuffer(0, 0, DisplayManager.Width,
            DisplayManager.Height, 0, 0, DisplayManager.Width,
            DisplayManager.Height, GL11.GL_DEPTH_BUFFER_BIT,
            GL11.GL_NEAREST);

然后给它缺少的深度信息。

当您在步骤 1 中渲染场景时,您使用了深度缓冲区。因此,当您绘制天空盒时,您需要一个使用相同深度缓冲区的 FBO。但是这个FBO还需要使用你在第2步中渲染的彩色图像。

现在,此 FBO 不能 与您在第 2 步中使用的 FBO 相同。为什么?

因为那将是 undefined behavior。据推测,第 2 步从您的深度缓冲区读取以重建位置(如果不是这种情况,那么您可以将深度缓冲区附加到第 2 步中的 FBO。但是话又说回来,您也在浪费 的性能)。但是那个深度缓冲区也连接到 FBO。这使它成为未定义的行为。即使你不写到深度,它在OpenGL下仍然是未定义的。

因此您将需要另一个 FBO,它具有步骤 1 的深度缓冲区和步骤 2 的颜色缓冲区。

除非您有权访问 OpenGL 4.5/ARB_texture_barrier/NV_texture_barrier. With that feature, it becomes defined behavior if you use write masks 以关闭对深度缓冲区的写入。您需要做的就是在执行第 2 步之前发出 glTextureBarrier。因此,如果您有另一个 FBO,则不需要。

在任何一种情况下,在渲染天空盒时保持启用深度测试,但 turn off depth writing。这将允许你的现实世界后面的碎片被剔除,但天空盒碎片的深度将无限远。

所以我想出了一个非常简单的 hacky 解决方案来解决这个问题,而无需合并任何纹理障碍或弄乱深度或颜色缓冲区。

我实际上在延迟渲染过程的几何通道中渲染天空盒几何体,我渲染天空盒并在片段着色器中设置一个标志来为我的天空盒着色,记得修改视图矩阵以删除与另一个的平移顶点着色器中的统一标志。在片段着色器中,我设置了天空盒颜色。这是一个基本摘要,没有粘贴所有代码。

layout (binding = 4) uniform samplerCube cubeMap;
uniform float SkyRender;
void main(){
if(SkyRender){
vec4 SkyColor = texture(cubeMap, skyTexCoords);
gAlbedoSpec.rgb = SkyColor.rgb;
gAlbedoSpec.a = -1;
}else{
gAlbedoSpec.rgb = texture(DiffuseTexture, TexCoords);
gAlbedoSpec.a =   texture(SpecularTexture, TexCoords).r;
}

我将颜色缓冲区中天空盒的 alpha 分量设置为我的光照通道的标志。这里我设置为-1.

在我的光照通道中,如果我的 gAlbedoSpec alpha 值为 -1,我只是选择使用仅漫反射为我的盒子着色,而不是添加光照计算。

if(Diffuse.a > -1){
FragColor = SphereNormal * vec4(Dlighting, 1.0)+vec4(Slighting, 1.0);
}else{
FragColor = Diffuse ;
}

它相当简单,不需要太多代码就可以完成工作。