创建镜子和反射面

当我们从一定的角度看高光材质物体时,物体会反射光。然而可惜的是,即使是最精确的光照模型之一:菲涅尔反射Fresnel reflection,也不能完全准确的反射来自周围物体的光。前一个章节验证过的光照模型只考虑了一些光源,但是却忽略了来自其他表面的反射光。很显然,用目前我们学的关于着色的知识,来创建一面镜子是不可能的。但是全局光照Global illumination技术提供了这种可能性,这需要提供包含了周围光照信息的PBR着色器。 这就要求物体不仅需要有高光部分,还需要有依赖周围其他物体的真实的反射部分。实时的反射非常消耗性能并且需要一些自定义的设置和调整才能工作,它们可以用来创建类似高光的效果,就如下图所示:


  • 始前准备

    这个知识点中不会涉及新的着色器。恰恰相反,大部分的工作都可以直接在编辑器上完成。就像下面的步骤展示的那样:

    1. 创建一个新场景
    2. 然后在场景中创建一个quad,这个quad会用来作为镜子。
    3. 创建一个新的材质并且把它跟这个镜子关联起来。
    4. 把这个quad放在另一个游戏对象前面。
    5. 在Unity菜单中通过GameObject | Light | Reflection Probe的步骤创建一个反射探针reflection probe并且把它放在quad的前面。

  • 操作步骤

    如果正确的按照前面的步骤操作,那么在你的场景中间会有一个quad,靠近它还有一个反射探针。为了让它出现在镜子中,还需要做西面的这些改变:

    1. 把材质的着色器类型改成Standard并且把Rendering Mode设置成Opaque。【这里的属性英文不翻译把,因为Unity大部分人都是用的英文,我担心找不到】
    2. MetallicSmoothness这两个的属性设置为1。你可以看到材质会很清晰的反射天空盒。
    3. 选择反射探针并且修改SizeProbe Origin直到它刚好在quad的前面,并且让探针包含你想反射的物体。
    4. 最后把Type改成Realtime。确定Culling Mask设置的是Everything

    这样的话,你的反射探针就设置好了,看起来就跟下图一样:


  • 原理介绍

    当着色器想要周围环境信息的时候,它自己提供了一个叫做cube maps的数据结构。它在第一章,创建你的第一个着色器 简短的提及过,跟Color2DFloatVector这些结构一样,都是Cg语言中的一种数据结构。笼统一点来说,cube maps就是2D纹理的3D数据结构。它们表示从中心点看过来的360度的世界视角。 Unity5可以通过特殊的投影预览cube maps,如下图所示:

    当cube maps关联到一个摄像机时,它们会被天空盒skyboxes引用,因为它们此时时被用于反射天空的一种方式。它们能用于反射不在实际场景中的几何体,比如星云,云朵,星星等等。

    之所以会把它们叫做**立方体贴图(cube maps)原因跟它们的创建方式有关:一个立方体贴图是由6张不同的纹理组成的,立方的每个面都有一张纹理。你可以手动的创建一个立方体贴图然后把它放到一个反射探针(reflection probe)**上。你可以把反射探针想象成一个拥有6个摄像机,拥有周围环境360度贴图的几何体。 这也解释了为什么探针的性能消耗会这么高。 在我们的场景中创建一个反射探针,这样允许Unity知道那些游戏对象再镜子的周围。如果你需要更多的反射面,那你可以添加多个探针。探针此时可以工作了,你无需再做进一步的操作。**标准着色器(Standard Shaders)**会自动使用它们。

    需要注意的是当它们被设置成实时(Realtime)的时候,它们会在每一帧的开始渲染立方体贴图。这里有一个技巧可以让这个过程更快;如果你知道你想反射的几何体的哪个部分是不会移动的,你可以对反射进行烘焙。这意味着Unity可以在游戏开始前就将反射预先计算好,可以允许更精确(计算量更大)的计算。 为了做这个操作,那么你的反射探针需要设置成烘培(Baked),于此同时游戏对象也要标记为**静态(Static)**才行。静态的游戏对象没法移动和改变,因此它们特别适合地形,建筑和道具。只要静态游戏对象发生变化,Unity都会为烘焙的反射探针重新生成立方体贴图。这可能要花费几分钟到几个小时。

    为了让你的游戏更加的贴近现实,有时候你需要把**实时(Realtime)烘培(Baked)**这两种探针综合来使用。 烘培过的探针能获得高质量的环境反射,然而实时探针可以用于移动的游戏对象比如汽车或者镜子。下一个知识点 烘培场景中的光 将会解释如何进行光的烘培的具体细节。