乐趣区

关于游戏开发:游戏中的动态阴影上

暗影对于进步游戏真实感十分重要,简略总结下游戏中的暗影实现。

先来看下暗影的组成部分,咱们能够将暗影大抵分成两个局部:全影(Umbra)和半影(Penumbra)。半影区域就是暗影的过渡区,也就是软暗影,有半影的暗影过渡时,视觉效果会好很多。

暗影的组成部分

对于动态的场景,咱们能够抉择将暗影烘焙到 Lightmap 中,或者间接画在贴图上。这篇文章,咱们次要来介绍下动静暗影的相干技术,因为暗影是实时渲染中比拟重要的技术,实现的形式也十分多。本篇文章,尽量笼罩到各种罕用的暗影渲染技术。

一、简略的手绘假暗影

在手游或者 2D 游戏中常常能看到这种做法,对于动静的角色,将暗影做成一张贴图,而后贴到脚下的高空上,尽管是很简略的模式,也能极大地加强真实感。

繁难的暗影

二、立体投射暗影

1. 立体投射暗影的计算
立体投射暗影,就是将须要投射暗影的物体再渲染一次,投射到高空上,来产生暗影。依据立体的地位,咱们能够计算出一个投射的矩阵,间接将物体的坐标变换到立体上。

咱们先来看简略的状况,如下图右边所示将暗影投射到 x 轴上的状况,咱们在光源 l 的照耀下,须要从点 v 投射暗影到点 p,依据三角形类似原理,咱们能够简略地失去:

相应地,咱们还能够算出 z 轴上的坐标为:pz =(lyvz-lzvy)/(ly-vy),将后果整顿成投影矩阵为:

这样能够通过矩阵计算投影坐标为:p=Mv。

当初,咱们看上图中左边这种更加个别的状况,在这种状况下,咱们同样能够依据三角形类似原理,推导出投射暗影的坐标变换方程为:

从 v 点映射到 p 点:

p=Mv 推导后写成矩阵的模式:

如果是平行光源,计算的形式也是大致相同,并没有特地的难度。

在进行渲染时,咱们能够抉择先来渲染暗影,将投射暗影的物体,通过上述矩阵的变换到立体上,而后失去没有光照的彩色高空,此时同时把深度写入。而后再失常渲染高空和投射暗影的物体,为了使高空和暗影之间不会抵触,此时能够为深度值增加一些偏移。

增加偏移的形式能够间接通过图形 API 来增加,比方 OpenGL 中的 glPolygonOffset 和 DirectX 中的 DepthBias 设置。当然,你也能够抉择在绘制暗影时增加偏移,绘制高空时失常绘制,最终的后果都是雷同的。前面咱们讲到的各种暗影技术,常常会用到增加偏移(Bias)的技术。

另外一种平安的做法是,先失常渲染高空,而后渲染高空上的暗影,渲染暗影时将深度测试敞开,就不会产生深度抵触的问题。最初再渲染投射暗影的物体,这样能够避免暗影投射到非高空的区域。

如果承受暗影的高空不是一个无穷大的立体,则可能须要通过 Stencil Buffer 标记出须要承受暗影的局部,这样能够只让暗影产生在须要产生的立体上。

另外一个须要留神的,是如下图所示的状况,在进行计算时,须要保障投射暗影的物体位于光源和承受暗影的高空之间,否则就会呈现谬误的暗影成果。

左边的情景下不应该绘制出暗影

总的来说,这种间接投射暗影的形式,简略间接,适宜间接投射在立体上的暗影。目前在手机游戏中,依然有宽泛的利用。

这种间接投射的暗影无奈实现软暗影成果。而且因为咱们是先渲染出的高空,再将影子的色彩乘以高空的色彩,这样其实并不是完全符合暗影产生的原理。

咱们晓得,暗影是因为高空没有受到光照而产生的,如果间接将高空的色彩乘以暗影,可能会产生不正确的暗影成果,特地是高空上有高光成果时。这类暗影叫做调制暗影(Modulated shadow),绝对一般的暗影,开销要小一些。

游戏中的立体投射暗影

2. 借助 Texture 的投射暗影
下面咱们说到的投射暗影,是间接渲染到被投射的立体上,这样咱们就无奈实现软暗影的成果,因而咱们这里将暗影先保留在一张贴图中,再从贴图中投射到立体上。这样还能够先失去暗影图,再渲染高空,失去正确的暗影成果。

和后面的间接投射相比,这种形式因为两头通过了一层转变,如果保留暗影的贴图分辨率很低,就可能会造成投射进去的后果有锯齿感。

这样,咱们就能够将贴图中的暗影先进行边缘含糊,再进行投射,就能够十分不便地失去软暗影成果。

投射暗影实现的软暗影,先将暗影投射到贴图中,而后进行含糊,再投射至立体,实现软暗影成果

为了晋升运行效率,咱们还能够将多个物体的 Texture 打包到一个 Shadow Atlas 中,这样每个物体的投射暗影,占用整个大贴图的一部分。如果光源和投射暗影的物体都没有扭转,咱们甚至能够不必更新暗影,实现帧间暗影的复用。

三、Shadow Volume 暗影

Shadow Volume 以前是一种十分风行的暗影实现计划,目前在游戏中也有肯定的利用,特地是前面咱们将要讲到的 PerObject 暗影,因而理解其原理是十分重要的。Shadow Volume 须要依赖 Stencil Buffer 来进行实现。

1. Shadow Volume
Shadow Volume 就是从光源沿着模型边缘拉伸至有限远处加上前盖后盖造成的形态。能够说,位于 Shadow Volume 外部的物体,在渲染时具备暗影,在 Shadow Volume 内部的物体,在渲染时没有暗影。

shadow volume

2. ZPass 算法
Shadow Volume 暗影的原理就是取一条从视点到指标点的线,每次进入 Shadow Volume,Stencil 模板计数加一,每次来到计数减一,这样计数为 0 的局部就是无暗影的中央,计数不为 0 的中央就是有暗影的中央。

Shadow Volume 的实现须要两个 Pass,第一个 Pass 是标记具备暗影的区域,第二个 Pass 是进行暗影渲染。

第一个 Pass,从视点渲染 Shadow Volume 几何体,屏幕中被 Shadow Volume 笼罩的区域,就是所有可能产生暗影的地位。咱们这里应用 Stencil Buffer 来标记出理论具备暗影的地位:开启 Z -Test,设置 Stencil 模式为侧面局部 +1,反面局部 -1。这样渲染实现后,Stencil Buffer 为 0 的局部就是无暗影的中央,Stencil Buffer 中不为 0 的局部就是有暗影的中央。

ZPass 的原理

第二个 Pass,同样也是渲染 Shadow Volume 的几何体,不过此时间接敞开深度测试,应用模板测试,间接在上一步中标记出的地位渲染出暗影。

3. Z-Fail 算法
ZPass 算法有个缺点,当摄影机在 Shadow Volume 中的时候,就会产生谬误的后果。

当摄影机位于 Shadow Volume 中时,ZPass 标记暗影区域生效

所以就有了 Z -Fail 的算法,Z-Fail 算法和 ZPass 算法相似,只是改成从物体反面计数,在 Z -Test fail 的几何体局部,在进入 Shdow Volume 时计数 -1,来到时计数 +1,这样就能够躲避这个缺点。

应用 Z -Fail 算法,标记处正确的暗影地位

不过一般来说 Z -Fail 算法广泛要比 ZPass 算法慢,因为从反面渲染 Shadow Volume,通常会笼罩更多的像素点。

因而在实践中,咱们能够先做一个摄影机是否位于 Shadow Volume 中的判断,来决定应用 ZPass 或者是 Z -Fail 算法来进行标记暗影区域。

4. 生成暗影体的步骤
有一种最常见的生成 Shadow Volume 的办法,不过这种办法要求指标模型是关闭的多边形网格(没有空洞、裂隙、自相交)。

分为三局部:front capping 前盖 -> back capping 后盖 -> silhouette 轮廓拉伸成的侧面

front capping 就是取模型中面向光源的三角面,方向判断能够通过判断面法线和光源方向的乘积的正负值来判断。

back capping 就是取模型中背向光源的面,沿光源方向拉伸到无穷远处。

silhouette 是判断两个临接面与光源方向不同的边,若认为是轮廓边,则将每条边扩大拉伸到无穷远处造成一个四边形面。

5. 在无穷远出的渲染
如何示意无穷远处的点?应用齐次坐标将 w 重量置为 0,xyz 示意方向即可。

如何防止图元在摄影机 far clip plane 外被裁剪掉?

一种办法是应用 GL_DEPTH_CLAMP_NV 扩大,将 far plane 外的点 clamp 到裁剪空间中。不过这个办法如同是只实用于 OpenGL 和 NVIDIA 显卡。

另外一种办法是略微批改下摄影机的裁剪矩阵,将 far plane 设置为无穷远。

一般摄影机矩阵

变成上面这样:

远裁面在无穷远处的摄影机矩阵

当然精度或有微不足道的缩小。

6. 实用于非关闭模型的办法
把模型分成两局部,一部分是面向光源的面,一部分是背向光源的面,别离进行拉伸生成 Shadow Volume,就能够反对非关闭模型。毛病是原来的轮廓边相当于生成了两次,造成性能节约。

右边是面向光源面,左边是背向光源面,两个加在一起造成正确的后果

7. 应用 Geometry Shader 生成 Shadow Volume
应用 GS 能够将生成 Shadow Volume 的工作移交给 GPU,不过必须用 TRIANGLE_STRIP 的形式来输出模型。

应用 GL_TRINGLES_ADJACENCY_EXT 模式来向 GS 中输出三角形图元,就能够获取三角形的邻接面,以此在 GS 中进行轮廓边判断、输入 Shdow Volume 等操作。

Geometry Shader 中输出的顶点

四、Shadowmap- 以后最支流的形式

1. Shadowmap 的原理
是当下利用最宽泛最常见的办法,Shadowmap 的应用,须要两个步骤。

假如咱们当初要渲染带暗影的场景如下:

步骤 1:从光源处登程,向光照的方向看去,来结构出光照空间。而后在光照空间,咱们渲染须要产生暗影的物体,此时将深度写入到 Z -Buffer 中,失去保留最近处物体的深度值的 Shdowmap。

步骤 2:而后咱们再次失常渲染物体,在渲染时,咱们依据渲染物体的世界坐标,变换到上一阶段的光照空间坐标,再计算出该点在 Shadowmap 中的深度值并进行比拟,如果绝对光源的间隔比 Shadowmap 中的深度要大,就阐明该点处在暗影中,否则就阐明不在暗影中。

下图显示了整个 Lightmap 工作的流程:

Shadowmap 计算暗影的大抵过程

对于锥形光源,咱们只须要沿着光照方向生成 Shadowmap。对于相似太阳光的平行光源,咱们就须要应用正交投影来进行计算深度,而且投影体的空间范畴,须要蕴含咱们的视锥空间。如果是点光源,就会更加简单一点,为了能保留各个方向的深度值,咱们个别须要应用 Cubemap。如果将一个物体进行六次渲染,每次渲染深度到每个面,那么渲染深度的开销就会比拟大,因而咱们个别会应用 RenderTargetArray 配合 Gemotry Shader,一次性将一个物体的深度,同时写入到六个面上。

2. Light Space Frustrum 的计算
Shadowmap 的成果,个别会十分依赖于 Shadowmap 分辨率的大小和 Z -Buffer 的精度。因而咱们要尽量进步 Shadowmap 的精度。

如果间接应用整个场景的 AABB 转化到 Light Space,必定是不行的,这样会造成很多不须要的暗影投射计算:

过大的 Light Space 边界

通常咱们会应用上面的形式来计算 Light Space Furstrum 的边界大小。将世界空间视锥的八个顶点,变换到光照空间,算出在光照空间下,最远和最近的 z 值,并计算出 AABB 边界:

不过,这样也可能会造成另外一个问题,就是当摄影机的 View Frustrum 很小时,造成计算出来的 Light Space Frustrum 十分小,无奈正确地投射所有须要投射暗影的物体。

因而咱们还会依据整个场景的 AABB 空间,对失去的 Light Space Frustrum 进行扩大,使其是否笼罩到可能产生暗影的物体。当然,为了避免 Light Space Frustrum 的 Near Plane 和 Far Plane 的值相差过大,咱们还会在光照中设置一个最大暗影间隔,当暗影投射物体,超出这个最大间隔后,就不再投射暗影,来进步暗影的精度。

正确的计算形式

3. Shadow Bias 解决自暗影走样
如下图所示,在进行暗影计算时呈现了 Self-shadow Aliasing/Shadow Acne,在计算本身的暗影时,因为在 Shadowmap 中存储的深度值,和物体本身的深度是雷同的。因为在写入 Shadowmap 时,咱们计算的是 Shadowmap 像素中心点的深度值,这样在进行深度采样时,因为 Shadowmap 的精度限度,就会使比拟的深度值产生误差,造成谬误的渲染成果。

自暗影走样,左边是加了 Bias 的成果

一种常见的解决自暗影误差的形式,是应用Bias Factor,对采样时的深度值,沿着光照的方向进行偏移。偏移的值能够是一个常量,这样计算起来比拟不便,然而可能会在斜立体上持续产生误差,应用常量时叫做Constant Bias

下图右边展现了 Shadow Acne 呈现的起因,彩色的竖线代表 Shadowmap 中像素点的地位。右边是未增加 Bias 的状况,当咱们在黑白的地位点进行比拟深度时,其实采样到的深度是旁边的竖线处 x 标记地位的深度,能够看出,绿色点的深度测试是正确的,蓝色和橙色的深度测试是谬误。下图两头是应用了 Bias 的状况,将深度值沿着光照方向进行偏移固定的间隔。这样绿色和橙色的点造成了正确的深度值,然而因为偏移的值比拟小,蓝色的点的暗影计算,依然是谬误的。

左:呈现 Shadow Acne 的起因;
中:应用 Constant Bias;
右:应用 Slope Scale Bias

咱们发现,在斜面角度较大时,一个固定的偏移值就不再实用了,因而一个常见的改良,就是依据斜面角度来扭转偏移值,叫做Slope Scaled Depth Bias / Slope Bias。如上图左边所示,能够看出所有的点的暗影计算结果都是正确的。

设立体法线和光照方向的夹角为 θ,视锥大小为 frustrumSize,Shadowmap 的大小为
shadowmapSize,思考到咱们须要半像素的偏移,这样咱们能够计算出须要的 Slop Bias 的偏移值为:

不过咱们能够留神到,这个偏移值是和 tan(θ)成正比的,这样的话,当 θ 趋近于 90 度时,偏移值是趋近于无穷大的,因而咱们须要为偏移值设置一个最大值。

在理论游戏引擎实际中,咱们经常须要联合两种 Bias 来应用,这样来达到较好的成果。

这两种 Bias 都能够通过图形 API 硬件来实现。例如在 DX11 中,咱们能够在 OutputMerge 阶段中,通过参数指定两种 Bias 的值 [1]:DepthBiasSlopeScaledDepthBias,这样总的 Bias 计算形式为:

Bias = (float)DepthBias * r + SlopeScaledDepthBias * MaxDepthSlope;

咱们还能够设置 DepthBiasClamp 的值,避免计算出的 Bias 值过大:

Bias = min(DepthBiasClamp, Bias)

另外一种罕用的代替 Slope Scaled Depth Bias 的计划是Normal Offset Bias,将暗影的计算地位沿着物体外表的法线偏移,通过计算咱们能够算出须要偏移的间隔为:

绝对于 Slope Scaled Depth Bias,这种形式的一个长处是不必放心 θ 趋近于 90 度时,整个偏移值趋近于无穷大。

UE4 中,应用的Constant Bias + Slope Scaled Depth Bias

Unity 中,应用的是Constant Bias + Normal Offset Bias

当然,咱们的 Bias 值也不能设置得过大,否则会呈现漏光等问题,也叫做Peter Panning

Bias 值太大导致的 Peter Panning

为了保障这种 Bias 的形式能正确地解决深度抵触。咱们应尽量保障物体几何模型是正确的,保障正反面朝向是对的,尽量保障模型关闭,且防止应用太薄的物体模型。

增加 Bias 能够是在生成 Shadowmap 阶段实现,也能够在暗影计算阶段,也就是生成 Shadowmap 时。在 Vertex Shader 中通过反向增加 Bias 的形式来偏移计算处的 Shadowmap 深度值,这样能够节俭一些运行开销,且能够简化暗影的计算,这样在采样暗影时,就无需思考计算偏移的问题。

大部分状况下二者失去的成果是根本靠近的,不过在 Shadowmap 生成阶段增加偏移这种形式也有一些瑕疵:

  1. 不够灵便,所有点的偏移值完全相同,意味着无奈依据状况灵便调整 Bias 值,比方在 PCF 采样软暗影时,只能提前给出比拟大的 Bias 值,而无奈依据 PCF Radius 的大小灵便调整;
  2. 和 Normal Offset Bias,在光照角度比拟小的时候,会导致渲染后果谬误[2],Unity 中的暗影就有这样的缺点。

在光照角度较小时,Unity URP 的谬误暗影成果

还有一种比拟少见的解决自暗影的形式,是将物体反面的深度写入到 Shadowmap,进行深度测试时,就不会呈现深度抵触。然而这种形式有很大限度,要求应用的模型必须是正确关闭的,且正反面没有谬误。而且如果物体模型很薄,导致后面和反面深度简直相等,这种形式依然会生效。因而这种形式不太通用,当初曾经很少能见到。

4. 挪动平台的 Pack
某些旧的挪动平台不反对浮点数纹理,这时须要咱们将 Shadowmap 的深度值 Pack 到 RGBA 贴图中,Pack 和 UnPack 的公式如下:

//Pack:
vec4 comp = fract(depth * vec4(255.0 * 255.0 * 255.0, 255.0 * 255.0, 255.0, 1.0));
comp -= comp.xxyz * vec4(0.0, 1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0);
//UnPack:
float depth = dot(texture((m_tex), (m_uv)), vec4(1.0 / (255.0 * 255.0 * 255.0), 1.0 / (255.0 * 255.0), 1.0 / 255.0, 1.0))

这里咱们应用的是 255 作为模来应用,网上也能搜寻到应用 256 作为模的版本。

然而测试结果表明,应用 256 时精度是不如 255 的[3],而且还会遇到不同硬件体现不统一的问题,因而强烈建议应用 255 作为参数。

五、Shaowmap 精度晋升

因为 Shdowmap 的精度限度,咱们在渲染中会遇到各种各样的渲染问题。

一种叫做 Perspective Aliasing,因为 Shadowmap 是在 Light Sapce 中进行计算的,所以在 View Frustrum 近处察看时,每个像素对应 Shaodowmap 中 Texel 的比例就会升高,产生锯齿。

Perspective Aliasing 在近处比拟显著

另外这一种叫做 Projective Aliasing,是在斜面上进行渲染时,Shadowmap 精度有余产生的,实质上来说和 Perspective Aliasing 是雷同的。

Projective Aliasing

通常,晋升 Shadowmap 的分辨率能够改善下面两种渲染问题。然而处于性能思考,咱们不会把 Shadowmap 的分辨率设置的太大,而是应用一些伎俩,来进步渲染后果的精度。

1. 应用 Perspective Warping
这类办法,通过批改光照空间的投影矩阵,来为视锥近处的物体暗影,提供更高的精度。

常见的有这样几种形式,Perspective Shadow Maps(PSM),Light Space Perspective Shadow Maps(LiSPSM)和 Trapezoidal Shadow Maps (TSM)。这些批改投影矩阵的形式原理上大抵都是相通的,如下图所示,显示了这类形式的原理:

扭转计算 Shadwomap 时的投影方向
就能够为近处提供更高的精度

这类形式尽管应用起来简略,然而有很多无奈解决的非凡状况,比方察看方向和光照方向完全相同时,这类形式就齐全无奈发挥作用。而且在摄影机挪动时,这种形式十分的不稳固。

这类形式目前曾经被彻底淘汰,这里也就不再深刻解说相干的原理和实现。

2. Cascaded Shadow Maps(CSM)
CSM 是目前最常见的进步 Shadowmap 精度的伎俩,候也叫做 Parallel-Split Shadow Maps。

通常在渲染视角左近的物体时须要更高的 Shadowmap 精度,而间接生成的 Shadowmap 往往不合乎这个条件,所以将 Frustum 宰割成数个局部,每个局部独自生成一张 Shadowmap,最初组合成一张 Atlas。

CSM

从实践上来说,应用指数分布的 CSM 划分计划是最佳的,即满足

f、n 是相机的 far、near 值,n 是指数系数。

比方咱们取 n =3,f=1000。这样咱们划分进去的三级 CSM 就是:1-10,10-100,100-1000。

然而如果咱们这样来划分,最近处 1 -10 这个范畴的一个 CSM 划分,物体太少,反而会导致 Shadowmap 空间的节约。因而在实践中,经常会联合指数划分和其余划分伎俩来应用,或者间接由用户手动设置相应的比例值。

Unity 中的 CSM,不同的色彩代表不同的 CSM 区域

3. Stablize CSM [4]
在应用 Shadowmap 时,在挪动摄影机时,咱们常常会遇到暗影闪动的问题。因为当摄影机挪动后,摄影机的 View Frustrum 会产生扭转,同时 Light Space 的 Frustrum 会相应扭转,就会造成两帧间接的暗影地位不一样,产生闪动,在没有应用 PCF 过滤暗影时,会尤其显著。下图显示了这种闪动的示例,能够看出视角的渺小变动,导致暗影产生了激烈的闪动:
https://www.youku.com/video/XNTk2MDI3MzYyMA==

通常咱们会应用 Stabilize Cascades 来解决这个问题,Stabilize Cascades 将相机的挪动分成两个局部来解决,别离是相机的旋转和平移。无论相机是如何静止的,都能够分解成沿着视锥核心的旋转和平移。

首先来看绕视锥核心的旋转,当视锥旋转时,因为视锥边界的扭转,就会导致计算出来暗影的 Light Space Frustrum 扭转,产生不稳固的后果。要解决这个问题,咱们将视锥 Frustrum 计算出一个球形的 Bounding Volume 进去,并用这个球形的 Bounding Volume 来算出暗影的 Light Space Frustrum,这样当咱们的视锥沿着球体核心旋转时,失去的球形 Bounding Volume 是不变的,算进去的暗影的 Light Space Frustrum 天然也不会变动。

ab 展现的传统的 Light Space Frustrum 计算过程
cd 应用球形 BV 时的计算过程,在摄影机转动时也是稳固的

从 Frustrum 生成 Bounding Box Sphere,能够应用简略办法求出中心点,算最大半径的形式。也能够应用能失去更加紧凑边界的规范算法[5]。

接下来就是解决摄影机平移的局部了,这一步的解决,就是通过偏移投影矩阵,来保障两帧之间,世界空间中的同一点,能投影到 Shaodwmap 中的雷同绝对像素地位上。为了计算不便,咱们经常取世界空间中的零点,作为参考点,将世界空间的零点,变换到 Shadowmap 坐标中,并通过偏移,确保失去的 Shadowmap 坐标是对齐于某个像素的。对齐过程实现的大抵代码如下:

            // Create the rounding matrix, by projecting the world-space origin and determining
            // the fractional offset in texel space
            XMMATRIX shadowMatrix = shadowCamera.ViewProjectionMatrix().ToSIMD();
// 应用零点作为参考点
            XMVECTOR shadowOrigin = XMVectorSet(0.0f, 0.0f, 0.0f, 1.0f);
// 将参考点变换到 shadowmap 的坐标
            shadowOrigin = XMVector4Transform(shadowOrigin, shadowMatrix);
            shadowOrigin = XMVectorScale(shadowOrigin, sMapSize / 2.0f);
// 在 shadowmap 坐标系中,将坐标对齐到整数坐标线上
            XMVECTOR roundedOrigin = XMVectorRound(shadowOrigin);
            XMVECTOR roundOffset = XMVectorSubtract(roundedOrigin, shadowOrigin);
            roundOffset = XMVectorScale(roundOffset, 2.0f / sMapSize);
            roundOffset = XMVectorSetZ(roundOffset, 0.0f);
            roundOffset = XMVectorSetW(roundOffset, 0.0f);
// 利用偏移,失去新的 projection 矩阵
            XMMATRIX shadowProj = shadowCamera.ProjectionMatrix().ToSIMD();
            shadowProj.r[3] = XMVectorAdd(shadowProj.r[3], roundOffset);
            shadowCamera.SetProjection(shadowProj);

在大部分游戏引擎中,Stablize CSM 都是默认关上的。不过须要留神的一点是,关上 Stablize CSM 时,因为暗影的无效范畴缩小了,所以是会导致暗影精度升高的。在能够保障暗影成果足够软而不会产生闪动的时候,也能够抉择敞开这个性能,来晋升暗影的精度。

4. CSM Caching
在应用 CSM 时,咱们经常会遇到 CSM 开销较大的问题,比方当初应用四级 CSM 级联,就意味着在生成 Shaodwmap 时,很多物体须要反复绘制四次。因而有的时候咱们会对 CSM 进行一些优化。

一种形式是升高远处 CSM 的更新频率。比方在原神的 PC 版中,共有八级的 CSM,前四级是每帧都更新的,后四级是逐帧顺次更新的,这样相当于每帧须要更新五级的 CSM。

另外一种形式是将 CSM 中算出的暗影动静缓存,对于动态物体的 Shadowmap,是能够实现前后两帧之间的复用的。上一帧中动态物体的 Shadowmap,通过一些小小的解决,在以后帧依然是可用的,对于一些没有笼罩的区域,能够动静来检测,从新绘制生成:

CSM Caching

参考:
[1] https://learn.microsoft.com/en-us/windows/win32/direct3d11/d3…
[2] https://zhuanlan.zhihu.com/p/370951892
[3] https://aras-p.info/blog/2009/07/30/encoding-floats-to-rgba-t…
[4] ShaderX6 Stable Cascaded Shadow Maps
[5] https://zhuanlan.zhihu.com/p/136752363

更多内容,请关注:
游戏中的动静暗影(下)


这是侑虎科技第 1380 篇文章,感激作者张亚坤供稿。欢送转发分享,未经作者受权请勿转载。如果您有任何独到的见解或者发现也欢送分割咱们,一起探讨。(QQ 群:465082844)

作者主页:https://www.zhihu.com/people/tc130-52

【USparkle 专栏】如果你深怀绝技,爱“搞点钻研”,乐于分享也博采众长,咱们期待你的退出,让智慧的火花碰撞交错,让常识的传递生生不息!

退出移动版