200+篇教程总入口,欢迎收藏:
放牛的星星:[教程汇总+持续更新]Unity从入门到入坟——收藏这一篇就够了zhuanlan.zhihu.com本文重点内容:
1、渲染到HDR纹理
2、减少Bloom萤火虫
3、增加Bloom散射
4、支持多种色调映射模式
这是有关创建自定义脚本渲染管道的系列教程的第12部分。它增加了对高动态范围渲染,基于散射的光晕和色调映射的支持。
本教程是CatLikeCoding系列的一部分,原文地址见文章底部。
本教程使用Unity 2019.4.8f1制作。
1 高动态范围
到目前为止,渲染摄像机时,我们已经在低动态色彩范围(简称LDR)中进行了设置,这是默认设置。这意味着每个颜色通道均使用固定为0–1的值表示。在此模式下,(0,0,0)代表黑色,(1,1,1)代表白色。尽管我们的着色器可能会产生超出此范围的结果,但GPU会在存储它们时限制颜色,就好像我们在每个片段函数的末尾使用了饱和一样。
(1,1,1)真的是白色吗?
它是理论上的白点,但其实际观察到的颜色取决于显示器及其配置。调整显示器的亮度会改变其白点。此外,你的眼睛会根据所看物体的整体亮度进行调整,从而移动自己的相对白点。例如,即使你观察到的强度发生了变化,如果你降低房间的照明水平,你仍将以相同的方式解释颜色。你还可以补偿照明的色相偏移。当照明突然改变时,这是很明显的,因为调整是逐渐的。
可以使用帧调试器检查每个DrawCall的渲染目标的类型。普通相机的目标描述为B8G8R8A8_SRGB。这意味着它是一个RGBA缓冲区,每个通道有8位,因此每个像素32位。同样,RGB通道存储在sRGB色彩空间中。当我们在线性色彩空间中工作时,GPU在读取和写入缓冲区时会自动在两个空间之间进行转换。渲染完成后,缓冲区将发送到显示器,后者将其解释为sRGB颜色数据。
那么HDR显示呢?
Unity当前不支持HDR显示。假定所有显示均为LDR sRGB。
只要光强度不超过每个颜色通道的1,就可以正常工作。但是入射光的强度没有固有的上限。太阳就是非常明亮的光源的一个例子,这也是为什么你不应该直接看它的原因。它的强度远大于我们在眼睛受损之前所能感知的强度。但是许多常规光源也会产生强度超过观察者极限的光,尤其是近距离观察时。为了正确地使用这种强度,我们需要渲染高动态范围的HDR缓冲区,该缓冲区支持大于1的值。
1.1 HDR反射探针
HDR渲染需要HDR render targets。这不仅适用于普通相机,对于反射探针也是如此。可以通过其HDR切换选项(默认启用)控制反射探针是否包含HDR或LDR数据。
当反射探针使用HDR时,它可以包含高强度颜色,这些颜色大多数是它捕获的镜面反射。你可以通过它们在场景中引起的反射间接观察它们。不完美的反射会削弱探针的颜色,从而使HDR值突出。
1.2 HDR相机
摄像机还具有HDR配置选项,但它本身无法执行任何操作。可以将其设置为Off或Use Graphics Settings。
Use Graphics Settings模式仅表示相机允许HDR渲染。是否发生这种情况取决于RP。我们将通过向CustomRenderPipelineAsset添加一个切换开关来允许HDR,并将其传递给管道构造函数来进行控制。
让CustomRenderPipeline追踪它,并将其与其他选项一起传递给相机渲染器。
然后,CameraRenderer追踪是否应使用HDR,这是在摄像机和RP都允许的情况下。
1.3 HDR渲染纹理
HDR渲染仅与后处理结合使用才有意义,因为我们无法更改最终的帧缓冲区格式。因此,当我们在CameraRenderer.Setup中创建自己的中间帧缓冲区时,我们将在适当的时候使用默认的HDR格式,而不是LDR的常规默认格式。
帧调试器将显示默认的HDR格式为R16G16B16A16_SFloat,这意味着它是RGBA缓冲区,每通道16位,因此每像素64位,是LDR缓冲区大小的两倍。在这种情况下,每个值都是线性空间中的有符号的float,而不是固定为0~1。
我们可以使用不同的渲染纹理格式吗?
是的,但是你需要确保目标平台支持它。在本教程中,我们使用默认的HDR格式,该格式将始终有效。
逐步执行DrawCall时,你会注意到场景看起来比最终结果要暗。发生这种情况是因为这些步骤存储在HDR纹理中。由于线性颜色数据按原样显示,因此看起来很暗,它错误地解释为sRGB。
为什么亮度会变化?
sRGB格式使用非线性传递函数。显示器会为此调整,执行所谓的伽马校正。伽玛调节函数通常用c的2.2次方和c原色近似,但实际传递函数略有不同。