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

先来看下暗影的组成部分,咱们能够将暗影大致分红两个部分:全影(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过滤暗影时,会尤其显着。下图显现了这种闪耀的示例,能够看出视角的微小改动,导致暗影发生了剧烈的闪耀:

视频链接

一般咱们会运用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]learn.microsoft.com/en-us/windo…
[2]zhuanlan.zhihu.com/p/370951892
[3]aras-p.info/blog/2009/0…
[4] ShaderX6 Stable Cascaded Shadow Maps
[5]zhuanlan.zhihu.com/p/136752363

更多内容,请重视:
游戏中的动态暗影(下)


这是侑虎科技第1380篇文章,感谢作者张亚坤供稿。欢迎转发共享,未经作者授权请勿转载。假如您有任何独特的见解或许发现也欢迎联系咱们,一同讨论。(QQ群:465082844)

作者主页:www.zhihu.com/people/tc13…

【USparkle专栏】假如你深怀绝技,爱“搞点研究”,乐于共享也博采众长,咱们期待你的加入,让才智的火花磕碰交织,让知识的传递生生不息!