学习笔记18

这里很好理解,首先我们的shadowmap 分辨率低的时候,shadow map本身就会有一些锯齿。而这个锯齿在shadow map被采样来计算阴影的过程,其实我们可以视作用光照给shadow map中的剪影,生成的阴影。

就是用光去照射这个剪影,剪影本身是有锯齿的,生成的阴影自然也会带有锯齿。或者就直接理解你采样的shadowmap是有锯齿的,那么也就意味着这里是否在阴影中会有一个突变。这就会带来锯齿了。

或者是直接理解生成的屏幕空间shadow map就是带有锯齿的,所以相乘之后还有锯齿。

这里get 这种锯齿明显的阴影,一个操作是吧shadow map分辨率降低,还有一点就是no cascade。因为cascade表示分级,也就是近处的物体,采用比较高分辨率的shadow map,远处的采用分辨率低的。这样一定程度上也是帮我们缓解锯齿的。

这里提升效果的手段就是调整shadow distance。

Shadow distance会影响在生成shadow map时拍摄的场景的大小。

如果这个值不是很大,那么就没必要考虑很远的场景在shadowmap中的样子,所以正交投影的时候就不必考虑那些很远的场景。

这样我们整个近处的shadow map就更大了。也就相当于近处的shadow map的分辨率变高了。因为你用相同的分辨率呈现了更少的内容,那么这些内容所占分辨率就高了。

分辨率高了以后,shadow map本身的锯齿就缓解了一些,自然生成的阴影的锯齿也就有所缓解。

这个质量有提升是因为用了cascade,这样对于近距离的shadowmap的生成,也是比较采用了比较高的分辨率的。所以效果上锯齿就少一些,但是随着距离变远,采样的分辨率就会逐级降低,锯齿也就逐渐明显。但是越远,在scene view下就显示的越小,所以结果也不会很明显,所以效果上还是有很大提升的。

这里讲的就是把cascade的层级进行一个展示。

这里可以修改显示模式。

这里是可以配置cascade分级的标准的,前者是根据距离摄像机的距离,这个直接是根据深度。应该是摄像机空间下的z值。

这里说了一下两种配置在摄像机运动的情况下的区别。对于第一个stable fit,效果是比较好的,只要不注意层级的边缘处就没啥问题。

但是对于close fit就不行了,他在运动的时候就会出现shadow edge swimming现象。

这里可以认为是光源从上往下,然后灰色的那些上表面就可以看作是距离光源最近的那些点,但其实不是点,是Texel,Texel是一个面积,这就有问题了,上边算是一个投影到2D的样子,我们看上边的面,他是有的直接stick in 或者through 或者out of surface的,也就是灰色的上表面那条线,有一部分在绿色外面,有一部分在绿色里面。

这样在摄像机视角下看这个绿色的物体的时候,实际情况本该是上边俩表面都是直接被光照射到的,不会有阴影,但是实际按照深度和shadow map深度进行对比的时候,他有一些地方的深度根据存储的shadow map判断的时候,是被判断了处在阴影中的。

所以就出现了表面阴影的bug。

关于ShadowMap中Shadow acne现象的解释 - 知乎 (zhihu.com)

这里就更清晰,

图形学渲染基础(6)实时阴影(Real-Time Shadows) - 掘金 (juejin.cn)

这里还有一个原因就是精度问题,因为这里float来回变换,难免会有一些精度的损失,所以可能导致误判处在阴影中,也会导致如上的acne。但是上边说了一个当small distance时,这个确实没怎么get到

当然解决方法就是使用bias偏移。而且每一个灯光都可以单独设置自己的bias。

这里bias的设置也是需要注意的,如果太大,就会导致如上的效果,peter panning,主要原因就是我们对shadow map做了bias 偏移,其实就是把整个shadow map的深度往远处push了一下,那么自然产生的阴影也会往远处push,这样导致物体和阴影本该connect的,就连接不上了。

这里关于bias offset。还有一个是沿着normal的思路,这个也会有相应的缺点。

最后关于bias如何选择,还有具体值的设置,需要根据情况来。没有统一的标准。

 

这里关于反走样的问题,基本上就说了,MSAA对于没有三角形边缘的屏幕空间shadowmap,好像没用。没看太明白

这里有一个要强调,其实bias带来的不能说是影子的偏移,根据上边,他是把球,沿着光的方向push,导致影子有什么行为呢?

其实就是相当于当前球在实际空间中,沿着光的方向去移动,这时候的影子就相当于bias偏移之后的影子,所以看上边的球,从bias等于0,然后沿着光方向偏移,球会直接和地面接触,然后逐渐的被淹没,所以他的阴影是会逐渐变小的,最后甚至会消失。

而如果这个球足够高,那么投射到地板上的影子随着bias增大,其实并没有什么影响,为什么呢?因为它足够高,沿着光线方向移动之后,再去沿着光线方向做投影,其实结果还都是一样的,但是一旦沿光线方向走的距离走到了和地板接触,那么bias再增大,影子大小位置都会随之而变化。

在实现线性bias的时候,其实由于是一个

UnityApplyLinearShadowBias — Unity中计算阴影bias的方法 | 码农家园 (codenong.com)

Unity Standard Shader 技术分析 - 知乎 (zhihu.com)

这里大概明白了,先说总的流程:我们要在Shadow Caster里面干什么?

在frame debugger里面可以知道,整个流程最开始是会去生成shadowmap的,那么生成shadowmap的时候,就是这个pass作用的时机,就是用这个pass来生成shadow map。

Shadow map是针对光源的,所以一个光源它对着的所有物体,只要带有shadowcaseter pass  的都会在这时候走一遍shadow caster,这里也进行深度测试,最终把结果写在shadow map里面。

然后对于每一个物体来说,会让顶点变换到裁剪空间,然后bias偏移,然后会再回到世界空间下,然后进行深度值判断,来决定是否参与生成深度图。

所以bias的作用时机是在投影空间的,自然下面:

第一句就很好理解了,里面说了一句为了补偿透视投影。

具体的先不管,因为bias是在透视空间下进行的偏移,不管你物体在这个空间的哪个位置,偏移都应该是一样的,但是直接偏移的话肯定不一样,因为非线性空间,所以需要这一个补偿。

补偿完成之后,还需要一个防止出界的问题。最后一点是光源类型的分类。

然后是使用normal进行bias的,这个就是沿着normal的方向往里缩。

具体缩多少,主要和 光线与法线夹角有关系。

因为我们的shadow acne是倾角导致的,如果说是正对着这种情况会缓解很多,所以这里当倾角比较大的时候,应该有较大的bias进行offset,小角相反

所以这里就使用了和角度之间成正比的sin函数来作为缩放的比例。

另外这里的方案是在世界空间下按照法线偏移之后,又进行了一个linear的偏移。

这里也就是当我们定义了ShadowScreen之后,再次进入Attenuation的时候,就会计算阴影相关的东西了,而在采样的时候,这里就出现了问题,因为我们传递的是个0,当时没有考虑阴影。

他这套是Unity自己的shadow 算法。

这里不知为何,自己写的接受阴影,然后靠近物体之后直接把shadow map给我渲染出来了。

上边情况通过补充一个ForwardBase就好了,果然是之间说过的,不定义这个虽然能够跑起来,但是往往会因此一些宏被不正常的赋值。

关于多阴影的问题,首先多光源的时候,一定要确保一个设置:逐像素灯光的个数,之前玩多光源的时候给改成了0.然后系统会默认只给一个逐像素的光,所以其他的都是逐顶点或者球谐灯光,这种灯光好像是不配有阴影的。

反正经过实验,standard材质是不支持顶点或者球谐光照的阴影的。 然后当逐像素的灯光个数改成4个以后,这时候standard材质是可以直接有多个阴影的。

所有的球谐和所有的顶点+主平行光(必须是平行光,没有就认定为0,走一遍空的base)走一遍base pass,然后剩下的逐像素的光,每人一个add pass。

有时候光源添加之后,默认是no shadow这一点一定要注意一下。

然后如果想要自己写的材质能够支持这种多阴影:就需要加上:

这里可以加SHADOWS_SCREEN也可以上边的预编译指令,区别在于,前者只服务于平行光的多阴影,后者可以任何光照类型。

点光源的阴影,需要一个SHADOW_CUBE,所以这里加一个预编译指令。

妈的这里包含头文件可给我搞蒙了,好在现在已经清晰了。只需要注意两个点:

首先,你看着你包含的顺序是先A后B,但是实则并不一定是,也许由于文件的嵌套,之前已经包含了B,你再来一个先A后B,最终得到的还是先B后A。所以包含之前注意自己之前头文件的包含情况。

其次,这里的decode代码其实我们并没有显式的调用,这个函数搞清楚是被谁调用的,应该是base 和 add的pass里面调用的,在这里俩里面涉及到了对于shadowmap的采样操作,而我们写的encode是在shadowcaster的pass里面,所以一直纠结这个pass里面的头文件了,最后咋纠结都没用。

Unity所谓的softshadow就是filter的,而这里呢连filter 都不是。

由于这个是cubemap存储的,没办法filter,所以这里使用的四次采样然后找平均,其实也是一定程度上的过滤了,但是这个四次采样消耗可比filter大吧。

这个是实际filter的结果。

在自己实现采样,而不是使用Unity封装好的那套宏的时候,大致的流程:声明好采样的坐标,然后我们需要在获取clip空间坐标作为这个采样坐标,但是需要一些变换,尤其注意裁剪空间是没有进行透视除法的,我们的最终目标是得到屏幕坐标用作采样。

但是这里插值和透视除法这里,我们必须先进行插值,然后进行透视除法。因为本身我们想要的图像就是透视的,所以在透视空间里插值,然后再除法。(具体为啥,想的不是很清楚)

关于高光的:

没有了提前操作的深度pass生成深度图。只有提前生成一个shadowmap。

这个和具体的位置就有关系了,所以投影的时候也就是透视投影了,自然也就无法使用cascade了。

关于投射,主要就是bias有一点,Normal bias只有平行光才有,点光和聚光灯只有linear bias,normal默认被设置为0(内部设置为0,面板中虽仍有这个参数,但是调节已经没有任何的效果了)

关于采样,没有了屏幕坐标空间的shadowmap,只有普通的shadow map,所以就是传统的那套:从model变换到世界,然后变换到light视角下的透视空间,进行采样。

对于线性bias:先从模型空间变换到裁剪空间,然后bias,最后输出。

Normal bias ,模型空间,到世界空间,进行normal bias,裁剪空间,然后套用线性bias接口,从裁剪空间线性bias,输出。

————————————————————————————————————————————————————————————————————————————————————————————————

Rendering 8

首先这是为啥要研究这个,就是我们之前的PBR写出来的材质在粗糙表面时表现出的效果是非常不错的,但是当光滑的时候,金属度高的时候,就烂了,效果就完全离谱。

其实核心的问题就是:

对于光滑的金属度高的物体,几乎没有漫反射,镜面反射也只有特定的很小的角度下才能观察到,而我们能看到主要是因为:环境光。无数的环境光,各个方向的环境光经过反射进入人眼。

这里确切来说是环境光或者说是间接光的镜面反射部分,因为间接光其实就是来源不同而已,对于这里说的光滑材质,间接光也主要是镜面反射的部分,这里我们可以在任意角度看到,就是因为它是间接光,来自各个方向。

然后这里我们把之前没有没有考虑的环境高光部分给考虑进来,并把它设置为红色,设置之后,其实我们的红色就代表着反射率。为什么这么说,因为红色是环境高光的颜色,颜色越红,说明反射的越多,那不就是反射率大么。

而看上边边缘部分有着很强的菲涅尔效应,这也是因为我们的pbr的shader是利用了unity封装好的一些东西,其中就有写好了的fresnel

这里的意思应该是:因为如果光受到阴影的影响,那么本身光会被cast过来的阴影压暗。也就是说如果是受到阴影的影响,阴影区域那的环境高光也应该变暗,但是它并不受到影响,而且由于和阴影之间有一个明暗的对比,反而显得更亮。

完成我们的初采样。

这里就知道HDR格式是比较亮的,会有一个系数加亮。我们想要获取没有加亮的个RGB格式,就需要对他进行一个decode。

这里decode之后,我就出问题了,没decode的时候还正常,decode之后就:

How to sample HDR texture in shader? - Unity Forum

看了下网上的decode也是这么操作的。卧槽这他么真稀罕。

上边那个只是法线采样,和反射还没什么关系,这里引入反射。

引入反射之后,反射天空球还不够,这里需要加入实际的周围物体的反射,所以加一个反射探针。

这里icon有点碍事,我们可以给他关掉。

上边主要是介绍这个探针,它的这个实时好像勾选之后,可以有更多的配置。

第一个,多的参数,就是调控什么时候刷新这个probe得到的cubemap,一个是每次变成active刷新一次。(这个active状态是啥也不清楚)。

大致看了一下,是关于c#中的一些设置。然后第二个是每一帧刷新一次,第三个就是完全由用户脚本来进行控制。

第二个参数,更加的智能,它能够吧一次刷新获取cubemap这个过程,分散到好几帧中去做,有的是9帧,有的14帧,还有一个不分散,每一帧把整个cubemap进行刷新。

因为计算cubemap需要渲染6个frame才是一个cube,所以说这是一个非常大的消耗,而实时消耗则更大,所以这些属性基本上都是来减轻实时的一些渲染压力的。

这里说的editmode应该是这种吧。

总之最后他选择的是bake,其实bake基本上就足够了。

另外这个bake对于静态的物体才会被考虑进去,所以需要改成static,改static的时候,可以一下勾选了,也可以根据细分的很多项,单独设置某一项static。

 

我们调节粗糙度和金属度其实对模糊程度基本没啥影响,而且调节之后会对光照有很大影响。

其实这并不合理,实际情况,应该随着光滑度的改动,对反射的模糊程度应该有一个影响,这使得我对于PBR的内部产生了一些怀疑,这本不就该是PBR已经干完了的活吗?为啥没有做呢?

其实这一点想想模糊的原理就明白了,模糊本质是和周围的东西没有清晰的边界,就是混在一起的感觉,显得模糊。我们通常使用卷积滤波来实现模糊的原因。

而PBR再怎么牛逼跑在GPU上,也只是单像素去操作,所以模糊这一效果,他也无能为力,应该是一些后处理或者类似MSAA这种操作才能实现的。

但是光滑度没有用来做模糊等操作,具体被用来干啥了,其实还真想一探究竟。

所以采用mipmap来模拟不完美的反射。

但是这里Unity为了考虑到不同模糊程度之间有一个很好的过渡,采用了另外的一种算法:

通过光滑度得到粗糙度。来确定需要采用的mipmap的level。

这里就是不是简单的用roughness来确定,因为roughness和模糊程度之间并非线性。

然后关于上边的粗糙度的非线性转换,采样cubemap,HDR的这些操作都包含了unity封装的一个函数内部。

虽说他这里又一次执行了HDR,但是我的效果并没有像之前样变得效果不正常,但是我对比了一下,不解码HDR和用它的宏得到的结果是一样的,也就意味着这个宏的解码HDR的部分对我这里没起作用。

这里有一些额外的算法看不太懂,主要还是内部对于各种平台啥的进行了考虑。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值