反射探针的基础知识
反射探针捕捉其周围世界的图像,并将其存储到一个“立方图”中—想象反射探针是一个360度拍照的摄像头,它会拍下周围环境的六个面,拼成一个立方体盒子般的贴图(Cube Map)。当如你设置512分辨率时,相当于6个 512x512 像素的照片——一个六面的纹理,可以填充立方体的每一个面。六个面拼起来就像展开的纸盒,不过 Unity 会自动帮我们整理这些图片。
每个纹理的面都是正方形,且具有相同的分辨率。这意味着“512”分辨率的探针是六个512x512纹理,紧凑地组合在一起。这将占用2MB的空间和2MB的内存。系统不仅存高清版本,还会自动生成"打了马赛克"的低清版。这些模糊处理的图片可不是偷懒,而是专门用来表现像磨砂金属、粗糙墙面这种不光滑材质的反射效果,这样看起来更真实。
反射探针还会存储它们纹理的低分辨率版本。这些低分辨率副本被模糊处理,允许真实地表现粗糙或不平整的表面。
当场景中的物体被渲染时,它们会询问Unity“我在哪个反射探针中?”——Unity将为它们提供最接近其锚点位置的两个探针的纹理和位置,着色器将在它们之间进行混合。如果只有一个探针可用,Unity将只发送一个。实际运行时,物体会找离自己最近的2个反射探针,根据距离远近自动混合两个探针的效果。如果周围只有一个探针,那就直接用那个。
除了反射探针对象之外,每个场景都有一个“每个场景都有一个保底的“环境反射”,当附近没有反射探针时提供。这通常是从天空盒材质生成的,但可以手动覆盖。但可以自己上传其他立方体贴图(比如想让整个场景都泛着金库的金色反光就可以这么玩),“环境反射”会在当物体附近没有反射探针时启用。
一个反射探针纹理的示意
在这张图像中,您可以看到一个反射探针的内容。您可以看到反射探针所记录的内容。通常,反射探针以未压缩的形式存储,所有面就像这样展开,但Unity在导入它们或任何其他以同样方式排列的立方图纹理时,但 Unity 在导入它们或任何其他以同样方式排列的立方图纹理时,将自动组合它们。您可以看到这个示例中的探针包含了一座建筑物,上方的天空,以及一个外部区域。尽管探针每边只有512像素,它仍然非常清晰,并包含了实时中看起来准确和清晰的反射。
动态对象如何工作,比如玩家?动态对象如何工作?
动态对象使用最接近其网格上锚点位置的探针。
在这张图像中,您可以看到一个对象的锚点。它位于对象的根部,而不是您可能期望的中间。
实际上,这个对象的锚点是红箭头指向的位置——尽管中心在别处。Unity将使用该位置为模型选择反射探针。这个位置默认是网格的“原点”——每个顶点都围绕的(0,Unity 0,里可以通过拖任意空物体到"Anchor 0)点。
您可以通过在网格渲染器上设置一个GameObject在“锚点覆盖”字段中来覆盖这一点。
Override"栏位,以自己指定定位点。
如果细心留意,你会发现大部分虚拟形象使用 Chest 作为所有子物体的 Anchor,以保证虚拟形象所有身体部位时刻处在同样的亮度,否则就会在部分场景遇到身体亮度分裂的问题。
静态对象如何工作,比如地图?静态物体的反射探针如何工作?
它们的工作方式与动态对象相同。然而,这可能会导致一些问题。
Unity有静态批处理,它将多个模型合并成一个网格,并在一个绘制调用中渲染它们。
然而,Unity不会合并受不同探针影响的对象。
您可以通过锚点覆盖部分解决这个问题。使用相同锚点覆盖的对象有时会被批处理在一起。尽管Unity经常无法将它们批处理在一起,因此在这些情况下,您将需要手动合并网格以恢复性能。
静态物体的反射原理和动态物体是一样,但这里有个坑:Unity的静态合批功能(就是把多个物体合并渲染提升性能)有个限制——只能合并受同一个探针影响的物体。比如说,你的场景里有十个箱子,如果五个受探针A影响,五个受探针B影响,那它们会被分成两批渲染。这时候可以试试给这些箱子设置同样的锚点(Anchor),说不定能让它们合并。实在不行的话,就得手动合并模型了。
着色器如何处理反射探针?
在大多数情况下,着色器将遵循Unity标准着色器的做法。Unity提供了一些功能,让任何着色器使用标准的部分来提供与标准相同的反射,或者访问数据以自行完成。大部分情况直接用Unity标准着色器就行,开发者不用自己造轮子。系统会自动处理好这些事:
-
如前所述,Unity将为它们提供最接近其锚点位置的两个探针的纹理和位置,着色器将使用Unity提供的一些方便功能在它们之间进行混合,大多数着色器都会使用这些功能。根据摄像机角度计算反射方向 -
在标准中,遮挡贴图用于定义光线通常无法到达的区域,这将使这些部分反射较少的光,并减弱反射的效果。
混合两个探针的效果 -
用遮挡贴图控制哪些部位反射弱(比如凹陷处)
-
根据材质粗糙度决定用高清还是模糊的贴图