Notifications
Article
阴影概述
Updated 20 days ago
9
0
Unity的光源可将对象的阴影投射到其自身的其他部分或其他附近的对象上。阴影为场景添加了一定程度的深度和真实感,因为它们可以显示对象的比例和位置,否则游戏对象看起来显得“扁平”。

阴影的工作原理

考虑只有一个光源的最简单场景的情况。光线从该光源发出后以直线传播,最终可能会照射到场景中的对象。一旦光线照射到某个对象,它就无法再进一步照亮其他任何对象(也就是说,光线会从第一个对象“反弹”而不是直接通过)。对象投射的阴影就是未被照亮的区域,因为光线无法到达这些区域。
另一种看待阴影的方式是设想将摄像机置于与光源相同的位置。场景中阴影区域恰好是摄像机无法看到的区域。事实上,这正是Unity从光源位置确定阴影位置的方法。光源使用与摄像机相同的原理在内部从其视角“渲染”场景。场景摄像机使用的深度缓冲系统可跟踪最接近光的表面;位于直接视线中的表面将接受光照,而所有其他表面都处于阴影中。在这种情况下,深度贴图称为阴影贴图。

启用阴影

使用Light组件的中的Shadow Type属性可为单个光源启用和定义阴影。
Shadow Type:Hard Shadows设置会产生锐边的阴影。与Soft Shadows相比,硬阴影(Hard Shadows)不是特别逼真,但涉及的处理工作较少,并且在许多使用场合中是可接受的。此外,柔和阴影(Soft Shadows)往往还会减少阴影贴图中的“块状”锯齿效果。
Strength:此设置决定了阴影的暗度。通常,一些光会被大气散射并在其他游戏对象上发生反射,因此通常不希望将阴影设置为最大强度。
Resolution:此设置将设置上述阴影贴图的“摄像机”的渲染分辨率。如果阴影具有非常明显的边缘,则可能需要增大此值。
Bias:使用此设置可微调阴影的位置和定义。
Normal Bias:使用此设置可微调阴影的位置和定义。
Shadow Near Plane:通过此设置可以在渲染阴影时选择近平面的值。如果游戏对象与光源之间的距离小于此值,则不会投射任何阴影。
场景中的每个网格渲染器(Mesh Renderer)还具有Cast Shadows(投射阴影)和Receive Shadows(接收阴影)属性,必须根据需要启用它们。
通过从下拉菜单中选择On启用Cast Shadows,即可启用或禁用网格的阴影投射。或者,选择Two Sided以允许表面的任一面投射阴影(因此在进行阴影投射时会忽略背面剔除),或选择Shadows Only以允许不可见的游戏对象投射阴影。

阴影贴图和Bias属性

给定光源的阴影是在最终场景渲染期间确定的。当场景渲染到主摄像机视图时,视图中的每个像素位置都将转换为光源的坐标系。然后,像素与光源的距离将与阴影贴图中的对应像素进行比较。如果像素比阴影贴图像素更远,那么它很可能被另一个游戏对象遮挡住光线,因此不会获得光照。
直接获得光照的表面有时看起来部分处于阴影中。之所以出现这种情况,是因为应该精确位于阴影贴图中指定距离处的像素有时被计算为更远距离(这是对阴影贴图使用阴影过滤或低分辨率图像的结果)。造成的结果是阴影中出现任意像素图案(这些像素其实应当获得光照),带来称为“阴影暗斑”(shadow acne) 的视觉效果。
为了防止阴影暗斑,可在阴影贴图中的距离上添加Bias值,从而确保边线上的像素确实符合比较预期,或者确保在渲染到阴影贴图时游戏对象可以沿着自身法线插入一点点。启用阴影后,这些值由Light Inspector窗口中的Bias和Normal Bias属性设定。
不要将 Bias 值设置得太高,因为游戏对象附近的阴影周围区域有时会被错误地照亮。这会导致阴影脱离游戏对象,使游戏对象看起来好像飘在地面上方。
同样,将Normal Bias值设置得太高会使阴影对于游戏对象来说太窄:
在某些情况下,Normal Bias会导致称为“光渗”(light bleeding)的不良效果,这种情况下,光线从附近的几何体渗透到应该产生阴影的区域。一种可能的解决方案是打开游戏对象的网格渲染器,并将Cast Shadows属性更改为Two Sided。这种做法有时会有所帮助,但可能会占用更多资源,并在渲染场景时增加性能开销。
光源的Bias值可能需要适当调整以免产生不想要的效果。通常用眼睛衡量正确值会更简单,而不是试图计算该值。
为了进一步防止阴影暗斑,我们采用一种称为阴影平坠(Shadow pancaking)的技术。这种技术通常很有效,但对于非常大的三角形可能带来视觉瑕疵。
调整Shadow Near Plane Offset属性可解决此问题。将此值设置得太高会引入阴影暗斑。

平行光阴影

平行光通常模拟太阳光,单个光源即可照亮整个场景。这意味着阴影贴图通常会同时覆盖场景的大部分,而这使得阴影容易受到称为“透视锯齿”的问题的影响。透视锯齿是指靠近摄像机的阴影贴图像素看起来比那些更远的像素更大块。
将柔和阴影和高分辨率用于阴影贴图时,透视锯齿不会那么明显。但是,使用这些功能会增加对图形硬件的需求,因此帧率可能会受到影响。

阴影联级

发生透视锯齿的原因是按摄像机的视角不成比例地缩放阴影贴图的不同区域。光照阴影贴图只需覆盖摄像机可见场景的一部分;该部分是按摄像机的视锥体定义的。如果想象一种简单情况,平行光直接来自上方,即可看出视锥体和阴影贴图之间的关系。
视锥体的远端被阴影贴图的20个像素覆盖,而近端仅被4个像素覆盖。但是,两端都在屏幕上显示为相同大小。结果是,对于靠近摄像机的阴影区域,贴图的分辨率实际上低得多。(请注意,在现实中,该分辨率远高于20x20,并且贴图通常不是摄像机的完美平方。)
对整个贴图使用更高分辨率可以减少大块区域的影响,但这会在渲染时消耗更多的内存和带宽。但是,您会从图中注意到,阴影贴图的大部分会浪费在视锥体的近端,因为它永远不会被看到;远离摄像机的阴影分辨率也可能过高。可以根据与摄像机的距离将视锥体区域分成两个区域。近端区域可以使用尺寸减小的单独阴影贴图(但具有相同分辨率),以便在一定程度上平均像素数。
阴影贴图大小的这些分阶段缩减做法称为级联阴影贴图(有时称为“平行拆分阴影贴图”)。您可以从Quality Settings中为指定的质量级别设置零个、两个或四个级联。
使用的级联越多,阴影受透视锯齿的影响就越少,但增加此数量实际上会带来渲染开销。但是,此开销仍然会低于通常在整个阴影中使用高分辨率贴图的情况。

阴影距离

对象距离摄像机越远,对象的阴影就越不明显;它们在屏幕上看起来更小,而且远处对象通常不是人们关注的焦点。Unity通过在Quality Settings中提供Shadow Distance属性,让您利用此效果。超出此距离(相对于摄像机)的对象根本不投射阴影,而接近此距离的对象的阴影将逐渐淡出。
应将阴影距离设置得尽可能短以帮助提高渲染性能。这种方法会奏效的原因是远处对象根本不需要渲染到阴影贴图中。此外,移除远处阴影后,场景通常看起来更好。正确设置阴影距离对于移动平台上的性能尤为重要,因为移动平台不支持阴影级联。如果当前摄像机远平面小于阴影距离,Unity将使用摄像机远平面而不是阴影距离。

可视化阴影参数调整

Scene视图具有称为阴影级联的绘制模式;该模式使用着色通过不同级联级别显示场景的各个部分。此模式有助于正确设置阴影距离、级联计数和级联分割比率。请注意,此可视化方法会使用通常大于阴影距离的Scene视图远平面,因此如果要将摄像机的游戏内行为与小远平面匹配,可能需要缩短阴影距离。

阴影平坠

为了进一步防止阴影暗斑,我们采用一种称为阴影平坠的技术。该技术旨在减少沿光照方向渲染阴影贴图时使用的光照空间范围。这可以提高阴影贴图的精度,减少阴影暗斑。
在上图中,浅蓝圆圈代表阴影投射物,深蓝矩形代表原始光照空间,绿线代表优化的近平面(排除了在视锥体中不可见的所有阴影投射物)。
将这些阴影投射物钳制在优化空间的近裁剪面(在顶点着色器中)。请注意,虽然这通常很有效,但对于穿过近裁剪面的大型三角形,这会带来瑕疵:
在此情况下,只有蓝色三角形的一个顶点位于近裁剪面背后并被钳制到此处。但是,这会改变三角形的形状,并可能产生不正确的阴影。
您可以从Quality Settings中调整Shadow Near Plane Offset属性以避免发生此问题。这将拉回近裁剪面。但是,如果将此值设置得非常高,最终会引入阴影暗斑,因为它会提高阴影贴图需要在光照方向上覆盖的范围。或者,您也可以细分有问题的阴影投射三角形。
Tags:
尹煜
北京宏宇航天技术有限公司Unity工程师 - Programmer
28
Comments