Unity用户手册-Light & Shadow

Light & Shadow

 

Render Mode(顶点光和像素光)

分为Auto,Important和Not Important模式。

Auto模式:

根据Quality Setting和光照强度,选择顶点光计算模式或像素光计算模式。

Important模式:

光线总是对每像素进行光照计算。(像素光)

Not Important模式:

光线总是以更快的渲染方式,对顶点进行光照计算。(顶点光)

 

Bounce intensity 物体间的间接光照强度(比如,反射光)

 

Light map

对一些静态物体的光照预先计算存储,这个过程叫baking(烘焙),baking的结果就是一张light map的贴图。

 

Unity光照处理

  • 静态物体与静态物体之间的光照,可以用light map烘焙。
  • 动态物体在静态物体下的光照,可以用Light Probe渲染。
  • 动态物体与动态物体之间的光照,Unity不支持。

 

Light Probe(光探测器

模拟全局光照,让动态物体得到静态物体的间接光照。预先在场景中,布置一些光探测器,在预处理阶段,把静态物体的光照信息存储下来,当动态物体经过探测器时,探测器根据预先储存的周围的光照信息,对动态物体进行重新的光照贴图。

探测照明通过3D空间中的探头对入射光进行采样并将这些信息通过球谐函数编码处理后保存成文件。这些信息占用的存储空间很少并且在运行时解码非常快。场景中的Shader可以使用这些信息来模拟物体表面的光照。

 

Reflection Probe(反射探测器)

用来模拟高反射物体表面对周围的实时发射。预先在场景中,布置一些反射探测器,对静态物体启用Reflection probe Static,在预处理阶段,把静态物体的反射光照信息存储下来,当动态物体经过探测器时,探测器根据预先储存的周围的反射光照信息,对动态物体进行重新的光照贴图。

 

Unity光照策略

烘焙的全局光照(Global illumination)和局部的实时光照

  • static的物体采用烘焙
  • 非static的物体采用实时的局部光照
  • light mode采用Mixed模式
  • 开启baked gi,关闭realtime gi

 

全局光照(Global illumination)

全局光照指的是模拟光线是如何在场景中传播的,不仅会考虑哪些直接光照的结果,还会计算光线被不同物体表面反射而产生的间接光照。

 

顶点光

顶点的光照颜色和强度信息,使用每个顶点的法线向量与光照方向之间的夹角的余弦值来得到。顶点之间点的光照,用插值计算的方式,计算出来。

像素光

为每个像素点计算光照。计算两个顶点的法线向量,然后插值计算出两个顶点之间每个像素点的法线向量,每个像素点的法线向量与光照方向分别进行几何运算,得到像素点的光照颜色和强度信息。

 

阴影产生原理(Shadow Map)

首先把摄像机的位置放在与光源重合的位置,那么场景中该光源的阴影区域就是那些摄像机看不到的地方。在前向渲染中,如果场景中最重要的平行光开启了阴影,Unity就会为该光源计算它的阴影映射纹理(shadowmap)。这张阴影映射纹理本质上也是一张深度图,记录从光源出发得到从该光源处观察到的深度纹理。

Unity选择使用了一个额外的Pass来专门更新光源的阴影映射纹理,这个Pass就是LightMode标签被设置为ShadowCaster的Pass。这个Pass渲染目标不是帧缓存,而是阴影映射纹理(或深度纹理)。

 

传统的阴影映射纹理技术

在正常渲染的Pass中把顶点位置转换到光源空间下,以得到它在光源空间中的三维位置信息。然后,使用xy分量对阴影映射纹理进行采样,得到阴影映射纹理中该位置的深度信息。如果该顶点的深度值(通常由z分量得到)大于阴影映射纹理中该位置的深度值,那么说明光源无法照到,该点在阴影中。

 

屏幕空间的阴影映射技术

在Unity5中,Unity采用不同于传统的阴影映射纹理技术,即屏幕空间的阴影映射技术(Screenspace Shadow map)。需要注意,屏幕空间的阴影映射需要显卡支持MRT(Multiple Render Target,多重渲染目标,GPU允许我们把场景同时渲染到多个渲染目标纹理中),需要OpenGL ES 3.0,Metal支持。

 

  • 当使用了屏幕空间的阴影映射技术时,Unity首先会调用LightMode为ShadowCaster的Pass来得到光源的阴影映射纹理以及摄像机的深度纹理。
  • 然后,根据光源的阴影映射纹理和摄像机的深度纹理来得到屏幕空间的阴影映射纹理。
  • 把每一个像素根据它在摄像机的深度纹理值得到在世界空间的坐标,再把它的坐标从世界空间转换到光源空间中,和光源的ShadowMap中的深度值对比,如果大于ShadowMap中的深度值,那么说明光源无法照到,处于该光源的阴影中。
  • 这样,屏幕空间的阴影映射纹理就包含了屏幕空间中所有有阴影的区域。如果我们想要一个物体接收来自其他物体的阴影,只需要在Shader中对屏幕空间的阴影映射纹理进行采样。由于屏幕空间的阴影映射纹理是屏幕空间下的,因此,我们需要把表面坐标从模型空间转换到屏幕空间中,然后使用这个坐标对屏幕空间的阴影映射纹理进行采样即可。

 

物体接收来自其他物体的阴影

如果我们想要一个物体接收来自其他物体的阴影,只需要在Shader中对屏幕空间的阴影映射纹理进行采样,把采样结果和最后的光照结果相乘来产生阴影结果。

 

物体向其他物体投射阴影

如果我们想要一个物体向其他物体投射阴影,就必须把该物体加入到光源的阴影映射纹理的计算中,从而让其他物体在对阴影映射纹理采样时,可以得到该物体的相关信息。在Unity中,这个过程可以通过为该物体执行LightMode为ShadowCaster的Pass来实现,还会在这个Pass中产生一张摄像机的深度纹理。

 

着色器替换技术(Shader Replacement)

使用着色器替换技术选择那些渲染类型(即SubShader的RenderType标签)为Opaque的物体,判断它们使用渲染队列是否小于等于2500(内置的Background、Geometry和AlphaTest渲染队列均在此范围内),如果满足条件,就把它渲染到深度和法线纹理中。

 

Shadow Cascade

Shadow Cascade,就是远处的阴影用分辨率比较小的贴图,近处的阴影用分辨率比较大的贴图,提升了近处阴影的质量,但增加了性能开销。

Shadow Distance

超出此距离的物体(来自相机)不投射阴影,因为远处的对象不需要渲染到阴影贴图中。将阴影距离设置的尽可能低,可以提高渲染性能。

实时阴影

实时为每个顶点计算法线向量,与光照方向进行几何运算,然后得到这个顶点的颜色。

Halo

模拟Point light周围的光晕

Lens Flare

模拟真实镜头中的太阳光斑,通常放在太阳的位置

 

Light的性能优化

  • 实时光源越少越好,甚至不用实时光
  • 利用离线烘焙,light mapping
  • Spotlight(聚光灯)开销很大,少用
  • 限制像素光的数量
  • Culling Mask 在不需要进行光照计算的层,取消勾选
  • 谨慎使用实时阴影
  • 尽量用Hard Shadow
  • 减少Shadow Distance
  • 不用Shadow castcade