找回密码
 立即注册
查看: 409|回复: 0

Unity中的shadows(一)

[复制链接]
发表于 2023-3-25 21:57 | 显示全部楼层 |阅读模式
Unity中的阴影针对不同的光源类型,平行光,点光源,聚光灯有不同的处理方式,casting和receiving的实现都有些区别。我们根据光源类型的不同详细看一下具体的实现。
平行光阴影





如图中所示场景,有两个平行光源,我们打开frame debug查看一下:



可以看到,对于平行光产生的阴影,Unity使用screen space shadow map来保存阴影信息。
首先,Unity对整个场景跑了一遍深度pass,记录场景的深度信息:



Unity在这一阶段定义了SHADOWS_DEPTH关键字,并且把ColorMask设置为0,意思是不会输出任何颜色。另外,只有object的shader中包含ShadowCaster标签,才会跑一遍该pass。ShadowCaster的代码可以很简单:
float4 MyShadowVertexProgram (VertexData v) : SV_POSITION {
        return UnityObjectToClipPos(v.position);
    }

    half4 MyShadowFragmentProgram () : SV_TARGET {
        return 0;
    }我们并不需要返回深度信息,z的值引擎底层会记录下来。
screen space的深度图有了之后,Unity会基于每个平行光源渲染一张shadow map,简单来说,就是把平行光源当作一个摄像机,做一次正交投影,将场景中物体的深度信息记录在shadow map上。
之后,Unity会做一次Collect Shadows阴影收集过程,用之前深度图中每个pixel的深度信息,将其重建回世界坐标系下,然后变换到光源空间,对之前光源空间渲染的shadow map进行采样。shadow map采样出的信息就是被光源照射到最近物体的深度,通过比较两个在光源空间下的深度信息,就可以判断出当前pixel是否在阴影内,如果在阴影内则输出0,能被光源照亮则输出1。每个平行光源都对应一张各自的screen space shadow map。
聚光灯阴影





如图中所示场景,有两个聚光灯光源,我们打开frame debug查看一下:



可以看到,与平行光相比,少了深度pass,还有阴影收集的过程,Unity就只是简单地把光源空间内的物体渲染到shadow map上。
点光源阴影





这次场景中有两个点光源,打开frame debug:



可以看到,点光源渲染阴影所用到的pass数量非常多,一个点光源可能需要6次阴影pass,这是因为点光源的shadow map不是一张贴图,而是一个cube map。Unity为点光源阴影定义了SHADOWS_CUBE关键字。
另外值得注意的是,ShadowCaster的pass需要添加如下定义:
#pragma multi_compile_shadowcaster用Visual Studio可以看到具体的keywords:
// -----------------------------------------
// Snippet #2 platforms ffffffff:
Builtin keywords used: SHADOWS_DEPTH SHADOWS_CUBE

2 keyword variants used in scene:

SHADOWS_DEPTH
SHADOWS_CUBE如果要为主平行光(base pass)添加阴影,需要添加SHADOWS_SCREEN关键字:
#pragma multi_compile _ SHADOWS_SCREEN如果要想为第二个平行光,点光源,或者聚光灯(即add pass)添加阴影,则需要如下定义:
#pragma multi_compile_fwdadd_fullshadows用Visual Studio可以看到具体的keywords:
// -----------------------------------------
// Snippet #1 platforms ffffffff:
Builtin keywords used: POINT DIRECTIONAL SPOT POINT_COOKIE DIRECTIONAL_COOKIE SHADOWS_SHADOWMASK LIGHTMAP_SHADOW_MIXING SHADOWS_DEPTH SHADOWS_SOFT SHADOWS_SCREEN SHADOWS_CUBE

13 keyword variants used in scene:

POINT
DIRECTIONAL
SPOT
POINT_COOKIE
DIRECTIONAL_COOKIE
SHADOWS_DEPTH SPOT
SHADOWS_DEPTH SHADOWS_SOFT SPOT
DIRECTIONAL SHADOWS_SCREEN
DIRECTIONAL_COOKIE SHADOWS_SCREEN
POINT SHADOWS_CUBE
POINT SHADOWS_CUBE SHADOWS_SOFT
POINT_COOKIE SHADOWS_CUBE
POINT_COOKIE SHADOWS_CUBE SHADOWS_SOFT阴影设置参数

在Unity的project settings中的quality项,有如下的若干有关阴影的设置:



Shadows有3个选项,一是完全关闭阴影,二是只使用hard shadows,三是hard shadows和soft shadows都使用。使用软阴影的好处是阴影的边缘更加光滑,减少锯齿。根据不同的选项,以平行光源为例,unity会在收集阴影阶段使用不同的subshader绘制screen space shadow map:



只使用hard shadows



使用soft shadows

Shadow Distance控制阴影显示的距离,太远的物体往往没有显示阴影的必要,通过控制距离可以降低绘制的draw call:



shadow distance设置为100



shadow distance设置为10

可以看出,超过阴影显示距离的物体,在光源绘制shadow map时直接就跳过了。
Shadow Cascade控制是否开启级联阴影,以及级联的数量和区域划分。级联阴影的好处是可以根据物体距离的远近,生成不同分辨率的shadow map,近的物体对高分辨率的shadow map进行采样,得到更多的阴影的细节,远的物体只用对低分辨率的shadow map采样即可,避免不必要的性能浪费。不同分辨率的shadow map在阴影收集阶段同样会被绘制到一张screen space shadow map上,因此只是在光源空间渲染shadow map时,draw call会根据选择级联的数量翻倍:



级联数量设置为4

Shadow Projection控制级联阴影的区域生成方式。Close Fit利用摄像机的深度信息来计算区域,而Stable Fit利用到摄像机位置的距离信息来计算区域。在scene窗口下,可以选择Miscellaneous / Shadow Cascades来显示级联阴影区域:



选择Close Fit



选择Stable Fit

Stable Fit的区域通常更稳定,不会受摄像机自身的位置和旋转影响:



Stable Fit



Close Fit

Shadow Acne

由于shadow map的精度问题,shadow map上的一个pixel,实际上是对应了场景上的一片区域。而这片区域中的所有点,在shadow caster阶段,都会去取shadow map同一个pixel的深度值,当这个深度值与区域中的所有点的深度值相近的时候,就会出现一部分点比较深度后,在阴影中,而另一部分点却不在阴影中,导致场景中会出现明显的明暗条纹:



从数学角度上来看,如图所示:



EF为shadw map采样的深度,那么CF区域中的点由于深度都小于EF,因此不在阴影中;而DF区域中的点深度大于EF,会被判定在阴影中。
为了解决这一问题,可以在渲染shadow map的时候人为加上偏移,让阴影位于物体之后。这个偏移就被称作shadow bias。
常用的shadow bias有两种,depth bias和normal bias。depth bias顾名思义,就是在shadow caster阶段,将物体沿着相机空间的z方向往后偏移:



可以看到,我们将CD区域沿着相机空间的z方向平移到了GI区域。此时shadow map采样到的深度值为EH,它等于BD。这样,CD区域中所有的点深度都不会大于EH(因为最大的深度也就是BD,而BD等于EH),从而保证了CD区域中的所有点都不会判定在阴影中,也就可以消除shadow acne。这里,depth bias的值就是CG的大小。
normal bias是在shadow caster阶段,将物体沿着自身的法线方向往后偏移:



原理与depth bias类似,这里normal bias的值就是CG的大小。
shadow bias的参数可以在光源的属性中进行调整:



Reference

[1] Shadows
[2] 自适应Shadow Bias算法
本文是Unity中的shadows系列的第一篇文章,如果你觉得我的文章有帮助,欢迎关注我的微信公众号(大龄社畜的游戏开发之路)^-^

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-11-16 18:53 , Processed in 0.102712 second(s), 28 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表