UE4渲染模块概述(六)---动态光照
上一文中介绍了静态光照:
知道了UE4使用lightmap存储静态光的直接光分量,用采样点存储间接光分量。那么对于位置变化或状态变化的动态光源,又是如何处理的呢?
我们先从动态阴影入手,它是动态光照的重点部分。对性能有着非常大的影响。主要有四种类型的动态阴影。
第一种:常规动态阴影(Regular Dynamic Shadows)
这是最常用的动态阴影,我们在场景中设置一个移动式的动态光源(Movable),并将之配置为投射阴影(Cast Shadows),如下:
可以看到静态网格体的边角有着不合常理的锐利程度,如下:
第二种:逐对象阴影(Per Object Shadows)
我们在场景中摆放一个固定光照(Stationary)的光源,如下:
stationary的光照会混合使用静态光照的lightmap与动态光照的实时计算,它创建的阴影如下:
可以看到阴影仍然清晰锐利,但要比纯movable光源生成的阴影更自然。
第三种:级联阴影图(Cascaded Shadow Maps,CSM)
最经常遇到的CSM就是这个了,它是方向光(Directional light)的阴影生成方式。如果将生成距离调得很小的话,可以看到阴影逐渐生成的过程,如下图:
CSM的特点就是会根据视锥体的远近生成不同精度的影图,如镜头当离得较远时,可以看到阴影边缘有一条锯齿状的线条,如下图:
当相机逼近时,会用精度更高的影图进行渲染,如下:
就几乎没有锯齿了。CSM这样做的目的尽可能降低性能影响,同时会保证好各级分辨率之间的阴影有淹平滑的过度。
第四种:距离场阴影(Distance Field Shadows)
对于开阔的大世界,CSM也会力不从心,这时需要另一种系统,能够处理长距离范围的阴影,那就是距离场阴影。
为了投射阴影,我们需要知道点与点之间的距离 ,因而需要查询几体体之间的距离信息,动态计算会很慢,如果有一种方法可以预先计算并存储好距离信息,那么就可以大大加速这一过程。距离场阴影将距离信息存储于体积纹理中(Volume Texture),纹理的精度决定了生成阴影的细节与质量。体积纹理创建后看起来像这个样子:
它将一张二维的平面纹理切成多个部分,上下堆叠,形成一块立体区域,白色的位置告诉你对象的形状,可以从这些信息里推断出一个3D的对象,像下面这样:
可以看出是一把椅子,本质上是一张纹理,只是以3D显示出来。
距离场阴影可以通过下面方式进行激活,在Project setting里面选择Rendering子项:
钩上Generate Mesh Distance Fields就可以产生距离场阴影了,不过有一点要注意,因为是在编辑器里预计算的,所以移动一小块物件也会导致build很长时间的距离场阴影,会影响开发效率,可以在场景定型后再开启预计算。build完成后,可以在编辑器里可视化距离场阴影,如下:
如果仔细观察,可以看到它的细节并不好,如下面的栏杆所示:
以上介绍了渲染阴影的四个主要方法,下面来看下动态光是如何计算的。动态光源被渲染成球体,这个球类似于mask的作用,任何处于球内的点都会受到融合动态光shader的影响,举个例子,在雕像附近有一盏动态光源:
从计算范围来说,这盏动态光源就是这个球体:
球体内的任何像素都相当于遮罩,白色区域覆盖的像素需要计算动态光影响,而黑色覆盖的像素则不需要。
实际光源有颜色和亮度,如下:
通过之前计算的深度,再加上这个光的颜色、强度,以及作用范围,可以得到下面的图:
再由GBuffer中缓存的world normal,可以进一步优化光照效果:
至于动态光产生的阴影,需要光源到物体的深度信息。可以类似于反射捕获时用到的六面体Cubemap,以光源为捕获点,渲染只有深度信息的立方体贴图,以下图示了cubemap的两面:
这样我们就可以生成阴影贴图shadowmap了,将之加入到前面的图中,有:
最后一步与无动态光的图片进行混合,就有了:
作为结尾,视频中说到了一些性能优化的方面:
(1)确保动态光源的半径尽可能小,这样mask的区域就会小,特别在阴影的计算上可以省不少
(2)多个动态光源的尽量不要有重合的区域,因为重合区域内的像素要分别计算不同光的影响,这一点可以通过编辑器的可视化工具,查看light complexity。如下:
与之前的可视化工具类似,冷色调复杂度低,暖色调复杂度高。
(3)非必要情况下,还是优先考虑静态光的lightmap(大世界除外,因为lightmap会超级占内存)
(4)动态阴影非常非常费,因此可以关闭部分不重要光源的cast shadow选项,或者配置好动态光源的最大绘制距离(Max Draw Distance),超过这个距离引擎就会忽略该动态光源的计算。
以上就是动态阴影/动态光的基本原理了,下章会介绍渲染模块的最后一部分:半透与后处理