0,引子
unity的光源有四种,每种光源都有3种光照模式,而场景中不同模式的光源而且对静态和动态的对象有不同的效果,而官方文档又显得有点晦涩难懂,如果是初学者第一次阅读(比如说我),难免会被场景中动态和静态游戏对象与不同模式光源的交互,以及它们阴影的投射结果搅得晕头转向,本人愚钝,也是费劲琢磨了一段时间才彻底弄清楚了它们之间的关系,这里将我的感想与收获尽量用通俗易懂的语言分享给在读的各位,如有不正确之处,请在留言指出,小弟将不胜感谢。
光源类型
首先咱先不考虑阴影,只考虑表面与各种光线的交互,我们知道unity中光源有三种光照模式:realtime,mixed,baked。首先先来说一下realtime模式,这个是最容易理解的,设置为realtime模式的光源,都会对所有能被它照射到的表面施加影响,那为啥叫realtime呢,其实所谓的realtime就是平时我们写shader的时候直接在shader里拿到并用于计算的光源,它是在shader里每帧更新的,所以叫realtime模式,是这三种光源里最没面子的光源,因为只能计算一次直接光照(因为咱shader用的是光栅化的方法,没法算间接光),而且也比较耗费资源(毕竟每一帧都要更新),所以realtime模式的光源在场景里不能太多。
接下来是Baked模式,对于这种光照模式的光源就要设计到光照烘焙了,所谓的光照烘焙,是利用的另外的程序获得unity中的场景数据,然后在场景中各种光源的相应方向上发射出很多束光线,这些光线经过反弹,就会形成所谓的间接光对场景施加更多的影响,然后经过几次反弹后,就完成了每个物体的光照计算,并把结果保存在每个物体各自的贴图中,下次在场景启动的时候,直接采样这些贴图就行了,这样就预计算了光照,注意这里预计算的光照是所谓的全局光,能更为生动的增加场景的真实感。那这里的Baked的模式就是这个光源的所有光照或者说是能量都用来烘焙光照贴图,就相当于把一把沙子全部撒在一张纸上,不管是直接撒到纸上的一大把沙子还是纸面周围弹出的零散的沙子全部记录在内。然后跑游戏的时候这种光源就“退休”了,因为它已经完成了它的历史使命,它的所有光照信息都已经烘焙进场景了。
最后是Mixed模式,这种模式在刚开始了解的时候可能会让人有一点稍稍的困惑,这种模式的光源也是在烘焙的时候被考虑到,But,烘焙的时候只会将它的间接光纳入光照贴图,然后在跑游戏的时候它跟那个realtime模式的光源的作用一模一样,啥意思呢?就是在烘培的时候,mixed模式光源的光线也会从光源发出,但光线第一次接触到物体表面的时候不会留下足迹,也就是说烘焙程序不会在物体表面记录这次碰撞所得到的光照能量,然后接下来光线反弹,注意了,这个时候的光线因为不是光源直接发出的,所以我们叫它间接光,在mixed模式中,虽然直接光线不会对物体表面施加能量,但是反弹后的间接光线却会对表面施加光照,打个比方,还是那个例子,把一把沙子丢在纸面上,纸面上有一堆沙子,而纸面周围有反弹的稀疏的沙砾,mixed模式就是把那张纸抽调,只留下周围零零碎碎的沙砾。这种模式的光源在烘焙的时候只贡献了自己的间接光,然而直接光却还有所保留,所以在跑游戏的时候他会像realtime模式一样贡献自己的直接光,这样就好像同时贡献了自己的直接光和间接光一样(前提是光源保持不动)。“什么?为啥不在跑游戏的时候直接贡献间接光,偏要烘焙进去?”Unity:“因为臣妾做不到啊,由于光栅化方法的局限性,目前的技术和算力只能计算一次性的直接光”。
总结:realtime模式就是shader中直接拿到并计算的光源,baked模式就是用烘焙程序把baked模式光源中所有的光照信息毫无保留的奉献在物体表面,mixed模式则是在烘焙的时候烘焙间接光照信息,而运行时就是跟realtime模式一样贡献直接光就行了。
阴影
上面是说的没有阴影的情况下各个模式的效果,接下来就谈一谈unity中三种模式对应的阴影会有怎么的表现,为了使问题简单明了,我们假设场景里所有的物体的MeshRenderer都设置成投射阴影和接受阴影。
先讨论简单的realtime模式和baked模式光源的阴影情况,首先是realtime模式,在这种模式下,无论是静态对象和动态对象都会在每帧实时的计算该光源对表面的影响,众所周知,一般动态光源的阴影都是利用阴影贴图计算的,而一个光源就需要一张阴影贴图,像是点光源的话更是需要六张阴影贴图,所以为了避免不必要的开销,unity中针对比较远的物体可以直接不渲染它的阴影贴图,这里究竟多远就不渲染呢?在quality setting里面有一个shadow distance参数就是控制究竟什么距离下才渲染阴影的。也就是收realtime模式的光源会对所有动态和静态的物体投射阴影,前提是它们距离摄像机的距离要小于阴影距离。再来谈谈backed光照模式下的阴影表现,这里因为是baked模式,所有对于设置为此模式的光照,它的所有光照信息都会被烘焙到所有静态物体上,包括光照探针,注意这里说的是静态物体,意思就是烘焙光照的时候相当于把动态物体直接完全忽略了,然后运行游戏的时候因为该光源所有的光照信息都已经存在相应的静态物体的光照贴图中了,所有运行时具有baked光照模式的光源就会直接“退休”,如同没有存在过一样。
说完realtime和baked光照模式的阴影表现,接下来说一下mixed光照模式的阴影是怎么作用的,对于mixed模式来说,阴影的情况比上面两种都要复杂一点,因为unity针对mixed模式的阴影表现有一些额外的设置,这些设置就是在light setting里面mixed lighting下的light mode设置,有三种,分别为baked indirect,shadowmask,subtractive,注意这些设置只对mixed光照模式有效果,而且是针对场景中所有的mixed光源的。先说说baked indirect设置,这是最符合直觉的设置,上面说过mixed光照模式实时计算直接光,烘焙间接光,所以这种设置下光源会把它的间接光直接烘焙到静态物体的光照贴图中的(记住这一点,烘焙光照永远只能烘焙进静态物体中,光照探针也算),注意间接光因为太弱了一般不会造成阴影,烘焙完以后你还能在editor模式中看见阴影那是因为mixed模式光源的直接光是实时的。所以运行的收mixed模式造成的阴影效果就更realtime模式一摸一样(使用阴影贴图的动态阴影)。
接下来是subtrative模式,这是三种模式里开销最低得一种模式,为什么呢,启用这种设置以后,场景中所有的mixed光源会在烘焙的时候烘焙间接光和直接光,前面说过baked indirect设置下尽管间接光被烘焙进光照贴图里去了,但是mixed光源的直接光部分会像realtime光照模式的光源一样既照射到静态物体上又照射在动态物体上,But,对于subtractive,首先它不仅会把自己的间接光照信息烘焙到静态物体和光照探针里,而且直接光也会烘焙进去,这样由于是直接光也参与了烘焙,所有光照贴图中就会阴影存在,最后在运行时,就像把所有的静态物体全部拿掉一样,mixed光源在实时的时候将不会再于静态物体交互,而只对动态物体投射直接光,也就是说这个时候实时情况下静态物体既不会投射动态阴影也不会接受动态阴影。但是unity觉得如果运行时静态物体如果不接受动态物体的阴影,如果一个挺大的人走在墙边,结果那么大一个太阳,墙面由于是静态物体不会显示人的阴影然后就会直接穿帮,所以unity中subtractive设置会把一个主directional light的光源考虑在内,也就是说,虽然静态物体在运行时不会再接受动态物体的阴影,但如果这个阴影是主directional light照射的,那么它会破例接受动态阴影(上面提到过,受到设置为subtractive的mixed光源照射的静态物体理论上既不会接受动态阴影也不会投射动态阴影)。