不确定我是否理解问题所在,但这里有一些带有很多假设的想法。
你正在考虑做这样的事情吗?:
- 使用您想要的背景颜色清除 gbuffer 中的漫反射附件(但是……您不想使用此值清除其他纹理,例如法线!)
- 填充 gbuffer 后,几何体未覆盖的任何内容仍应具有背景颜色(在您的漫反射附件中)
- 如果没有为片段定义法线,则在最后阶段手动编写硬编码颜色。
我假设您的渲染器正在执行以下操作:
- 填充 gbuffer(带有多个附件的 FBO 中的漫反射、法线、深度等)
- 对于每个灯光,您将全屏四边形叠加混合渲染到单独的 FBO(灯光累积缓冲区)。
- 最后,将 gbuffer 中的漫反射附件与光累积缓冲区结合起来,将最终结果渲染到屏幕上。
您的着色器确实没有理由像这样负责编写背景颜色。我实际上也会渲染背景中的内容,并始终使用 0 值清除 gbuffer。我想当你在最后一个阶段结合漫反射和光时,事情可能会出错,所以使用进一步解释的模板方法可能更简单。我个人将材质索引存储在漫反射颜色的 alpha 通道中,然后将所有材质属性上传到纹理中。
在我的材料中,我有两个标量(以及更多......):
结合漫反射缓冲区和光缓冲区时(大大简化):
FinalColor = Diffuse * AmbientWeight + Diffuse * Light * LightWeight
如果您的背景使用材质 0 且 AmbientWeight = 1 和 LightWeight = 0,则 FinalColor 将始终是漫反射缓冲区中的原始值。
许多简单的延迟渲染器只是这样计算最终结果:
FinalColor = Diffuse * Light
(来自漫反射缓冲区的片段 * 来自光缓冲区的片段)
在您的情况下,这当然会导致您的背景颜色消失,因为这些片段永远不会被点亮。(Diffuse * 0
始终是结果)您可以使用漫反射缓冲区中的 alpha 通道作为 AmbientWeight 以获得一些快速结果。
FinalColor = Diffuse * Diffuse.a + Diffuse * Light
在性能方面:
这真的很难预测。跳过着色器中的最终光照计算可能会给您带来一些好处,但在您到达此阶段之前,您已经完成了所有 gbuffer 读取和解包。无论着色器返回什么,您最终都会通过混合操作影响整个灯光缓冲区,并且您会读取每个灯光的整个 gbuffer。检查法线缓冲区中的所有组件是否为 0 只会触发没有几何图形的区域。当每盏灯使用全屏四边形时,您将遇到很多瓶颈。
从读取位置缓冲区(或从深度缓冲区重建位置)开始,然后确定您的点光是否无法到达片段并在执行任何其他操作之前将其丢弃可能会有所帮助。对于较小的灯光,您最终不会从每个片段的 gbuffer 中读取所有内容。这实际上取决于您的 gbuffer 的大小、渲染的内容、灯光的大小以及渲染的灯光数量。
动态分支也可以降低性能,但有时可能是“较小的邪恶”。我尽量避免。
额外的 :
当谈到“背景颜色”时,我个人使用模板缓冲区用天空盒或类似的东西填充背景。在编写漫反射缓冲区时构建模板蒙版,在使用反向蒙版渲染背景时,只有背景片段受到影响(没有深度测试或深度写入)。如果我的整个场景都被几何体覆盖,那么就不会写入任何片段。这假设您正在将最终结果写入使用与 gbuffer 相同深度附件的第三个 FBO。(Depth24 + Stencil8 缓冲区)
除了使用全屏四边形(带有混合)绘制每个灯光之外,您还可以使用带有灯光信息的 UBO 发送数组。然后用一个全屏四边形绘制所有点光源。您最终会进行相同数量的光计算,但读写量始终是恒定的。(不过 UBO 仍然有大小限制)
您可能还会发现感兴趣的 Tiled Deferreed Shading 作为潜在的下一步:
http ://www.cse.chalmers.se/~olaolss/main_frame.php
?contents=publication&id=tiled_shading (您只从 gbuffer 中读取一次并且只写入一个用于光通道的片段)
论文:http ://www.cse.chalmers.se/~uffe/tiled_shading_preprint.pdf