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

Posted

技术标签:

【中文标题】OpenGL 在延迟渲染器中实现天空盒【英文标题】:OpenGL implementing skybox in a deferred renderer 【发布时间】:2015-12-19 22:46:16 【问题描述】:

我试图弄清楚如何在延迟渲染器中渲染天空盒,以便它可以包含在后期处理效果中,但是我的几何阶段在视图空间中,不幸的是,这个阶段的天空盒会受到它的位置的影响像任何物体一样相对于光(它的行为就像离光源很远的大盒子,并且显示得很暗)。 我没有尝试在后期处理中加入天空盒的设置如下:

1:(绑定 FBO)将几何体渲染到颜色、法线、位置 FBO 纹理附件(取消绑定 FBO)。

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

3:(绑定FBO)应用后期处理效果(取消绑定FBO)

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

5:渲染天空盒。

我尝试将第 5 步与第 3 步切换 像这样:

2:(绑定FBO)渲染场景并计算屏幕空间的光照。

5:渲染天空盒

(解除绑定FBO)

3:(绑定FBO)应用后期处理效果(取消绑定FBO)

4:将几何 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);

【问题讨论】:

嗯,“模型视图”空间不是坐标空间。这是一个从模型转换到(世界到)视图空间的矩阵。这里有趣的是,GL 倾向于跳过的中间部分是延迟着色的方便坐标空间,可能会对您有所帮助。 抱歉,已编辑。 【参考方案1】:

所以我想出了一个非常简单的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 分量设置为我的 Lighting pass 的标志。在这里,我将其设置为 -1。

在我的光照通道中,如果我的 gAlbedoSpec alpha 值为 -1,我只需选择使用 Diffuse Only 为我的框着色,而不是添加光照计算。

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

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

【讨论】:

确保在评估这个“-1”标志时,你只做 一次 例如仅在定向光的 l-pass 中 - 而不是每个点/点/...光,因为您可能设置了“加法”混合模式,因此由于添加了多个光源,您的天空盒会过于明亮最终结果。【参考方案2】:

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

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

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

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

因此您将需要另一个 FBO,其中包含第 1 步中的深度缓冲区和第 2 步中的颜色缓冲区。

除非您有权访问OpenGL 4.5/ARB_texture_barrier/NV_texture_barrier。使用该功能,如果您使用 write masks 关闭对深度缓冲区的写入,它将成为定义的行为。您需要做的就是在执行第 2 步之前发出glTextureBarrier。因此,如果您有另一个 FBO,则不需要。

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

【讨论】:

以上是关于OpenGL 在延迟渲染器中实现天空盒的主要内容,如果未能解决你的问题,请参考以下文章

怎么使用深空盒子材质

OpenGL:渲染天空盒立方体贴图问题

批处理渲染器 (OpenGL) 的索引问题

2022-02-15 U3D全栈班 007-制作设置天空盒资源

OpenGL ES - 如何在 Blender Cycles Render 中实现光泽着色器?

透明天空盒+透明高度图的OpenGL混合问题