反射探针与你
Unity的反射探针系统起初可能有些令人困惑和复杂。对新手来说,看似良好的尝试,最终往往会变成可怕的错误。在多年的教学与辅助后,我决定将其汇总到一个页面中。
我将介绍反射探针是如何工作的,更重要的是,应该如何在世界中使用它们。
作者:Silent
文章原址:Reflection Probes and You | VRCLibrary
注意:当前文档尚未经过翻译校对,部分内容可能存在谬误。
1. 反射探针的基础知识
反射探针捕捉其周围世界的图像,并将其存储到一个“立方图”中——一个六面的纹理,可以填充立方体的每一个面。
每个纹理的面都是正方形,且具有相同的分辨率。这意味着“512”分辨率的探针是六个512x512纹理,紧凑地组合在一起。这将占用2MB的空间和2MB的内存。
反射探针还会存储它们纹理的低分辨率版本。这些低分辨率副本被模糊处理,允许真实地表现粗糙或不平整的表面。
当场景中的物体被渲染时,它们会询问Unity“我在哪个反射探针中?”——Unity将为它们提供最接近其锚点位置的两个探针的纹理和位置,着色器将在它们之间进行混合。如果只有一个探针可用,Unity将只发送一个。
除了反射探针对象之外,每个场景都有一个“环境反射”,当附近没有反射探针时提供。这通常是从天空盒材质生成的,但可以手动覆盖。
一个反射探针纹理的示意
在这张图像中,您可以看到一个反射探针的内容。通常,反射探针以未压缩的形式存储,所有面就像这样展开,但Unity在导入它们或任何其他以同样方式排列的立方图纹理时,将自动组合它们。您可以看到这个示例中的探针包含了一座建筑物,上方的天空,以及一个外部区域。尽管探针每边只有512像素,它仍然非常清晰,并包含了实时中看起来准确和清晰的反射。
动态对象如何工作,比如玩家?
动态对象使用最接近其网格上锚点位置的探针。
在这张图像中,您可以看到一个对象的锚点。它位于对象的根部,而不是您可能期望的中间。
实际上,这个对象的锚点是红箭头指向的位置——尽管中心在别处。Unity将使用该位置为模型选择反射探针。这个位置默认是网格的“原点”——每个顶点都围绕的(0, 0, 0)点。
您可以通过在网格渲染器上设置一个GameObject在“锚点覆盖”字段中来覆盖这一点。
静态对象如何工作,比如地图?
它们的工作方式与动态对象相同。然而,这可能会导致一些问题。
Unity有静态批处理,它将多个模型合并成一个网格,并在一个绘制调用中渲染它们。
然而,Unity不会合并受不同探针影响的对象。
您可以通过锚点覆盖部分解决这个问题。使用相同锚点覆盖的对象有时会被批处理在一起。尽管Unity经常无法将它们批处理在一起,因此在这些情况下,您将需要手动合并网格以恢复性能。
着色器如何处理反射探针?
在大多数情况下,着色器将遵循Unity标准着色器的做法。Unity提供了一些功能,让任何着色器使用标准的部分来提供与标准相同的反射,或者访问数据以自行完成。
如前所述,Unity将为它们提供最接近其锚点位置的两个探针的纹理和位置,着色器将使用Unity提供的一些方便功能在它们之间进行混合,大多数着色器都会使用这些功能。
在标准中,遮挡贴图用于定义光线通常无法到达的区域,这将使这些部分反射较少的光,并减弱反射的效果。
2. 如何设置反射探针
反射探针捕捉其周围环境的图像到一个纹理中。这意味着几件事:
- 分辨率更高的探针图像更清晰,但由于包含六个纹理,体积也大得多。
- 纹理是静态的。它不能改变。如果周围环境变化,它不会更新。
- 它们只能代表一个单一的视角,这个视角会移动来给出深度的错觉。
- 尽管如此,如果探针大致符合该区域的照明,没人会注意到一个不准确的探针。
所以,下面是我确定如何在场景中放置探针的方法:
1. 基础反射探针
即使你没有反射探针,Unity也会捕捉天空盒材质到一个反射探针,并默认分发给所有对象。
Unity的天空盒真的代表了你的场景吗?可能不是,所以让我们改变它为我们自己设置的东西。
首先,添加一个新的反射探针。将类型设置为“自定义”。
- 如果你已经将场景中的所有对象标记为静态,不要打开动态对象。
- 如果你没有将你的场景标记为静态(因为你没有合并它,或者不能使用静态批处理)则打开动态对象。然后选择在底部烘焙,并将你的反射探针纹理放置在场景的相关位置。
其次,从顶部的窗口菜单打开照明窗口。从那里,将环境反射设置为自定义,并拖动你的新探针进去。
完成这些后,你可以禁用原始探针。现在你的场景有了一个默认的反射,不会影响批处理。
2. 复杂反射探针
这样做的一个明显问题是有些地方你的反射会看起来不对。通常,这不是问题。如果你的反射匹配周围区域的颜色和阴影,它们不需要完全准确。但当差异太大时,它可能会以不好的方式突出。
这不是最坏的情况,但很明显被反射的东西并不在那里。在房间里的球上更糟,因为它没有反射周围的墙。
如果这是地图的一个重要区域,就在那里放一个额外的探针!
在这个截图中,我已经使用反射探针组件顶部的控制设置了探针区域。因为探针区域已经定义,旁边的钢球还在使用外部的反射,而内部的球则反射房间。房间反射它自己,所以天空不可见,尽管建筑通过后墙可见。
如果区域是箱形的,我们可以将探针的边界适应墙壁,并启用箱形投影。
箱形投影是一种强大的技术,可以将你的反射探针适应到一个箱子上。使用得当,它可以使反射看起来非常好,即使周围没有完全反光的表面来展示它。
3. 箱型投影探针说明
反射探针的边界定义了哪些对象受探针的影响。在边界的边缘,对象会在原始探针和最重要、最近的探针之间插值。对于常规探针,这从内向外发生。对于箱形投影探针,这是从外向内。
一个展示箱形投影探针边界扩展的视频。感谢ScruffyRules!箱形投影探针视频链接
箱形投影探针的边界实际上会扩展以包围它们周围的对象,这是基于对象的网格渲染器的边界的。这可能会因为大网格而造成大问题,因为对于一个大网格来说太小但优先级高的箱投影探针会被拉伸以适应更大的网格。
探针技巧与窍门
1. 超采样探针
在低分辨率下烘焙探针时,结果可能看起来有点低分辨率。这是因为探针在保存前是在那个低分辨率下渲染的。如果你在更高的分辨率下烘焙探针,然后将纹理的最大尺寸设置得较低,Unity首先会在高分辨率下渲染探针,然后压缩它——在此过程中执行非常高质量的抗锯齿。
2. 点光源的镜面高光与镜面高光探针
当你为场景从点光源/聚光灯烘焙光照时,你通常会发现结果缺少实时光照时的那些镜面高光。
这是因为点光源在反射探针渲染的环境中没有物理存在,如果点光源所在的位置没有亮的物体,就不会有匹配的闪亮高光。
你可以使用这个 Unity 工具自动在每个点光源上添加一个发光的球,这将在你的反射探针中创建一个闪亮的高光。
注意,还有其他方法可以通过使用特殊着色器从烘焙光获取镜面高光。如果你使用的是 Bakery 的“光图镜面”模式,你不需要使用这个。
3. 随时间而变化的光照
与烘焙光照不同,反射探针与它们的组件相关联。如果你禁用一个反射探针,它将停止影响周围的对象。相反,如果你启用一个反射探针,它将开始影响周围的事物。
所以,如果你的场景中的光照发生变化,你可以启用和禁用包含不同光照的反射探针。这允许你在不同的光照条件下保持反射正确。
主要的问题是存储所有这些反射探针。每个512x512的探针都是2MB。这很快就会累积起来。一种替代方案是将探针设置为实时模式。
在实时模式中,Unity将在游戏中渲染探针,而不是将其保存到纹理中。如果场景的主要元素可以变化——如随时间变化的光照,或地图中的物体外观变化——使用实时探针可能是你的场景的最佳选择。