unity urp内置lit材质源码解析(下)

Posted 暮志未晚Webgl

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了unity urp内置lit材质源码解析(下)相关的知识,希望对你有一定的参考价值。

接上一篇,这已经是第三篇了,这一篇的难度应该是最高的,因为涉及到pbr的渲染。我作为一个小ta,也不能说能够把物理材质吃透,这里我将能把我理解的都列出来,并结合源码给大家讲解一下。
UniversalFragmentPBR函数是写到Lighting.hlsl文件内,这是主要处理光照相关的函数,里面也封装了很多其它应用函数,并且还有很多重载。

合并代码,我们发现,这个文件里面封装了pbr(物理材质) BlinnPhong(冯氏渲染模型)Unlit(无光照模型)三种,每一种都有一个重载。重载的意思就是,我们可以不生成SurfaceData,而是通过传入相关必要的值,也可以调用这个函数,获取到颜色。
我们的lit就使用了里面的计算pbr的函数获得了颜色,接下来,我们解析一下lit里面的pbr的实现。

这里是高光的开关,这个宏可以在材质上开和关。根据宏声明一个变量,在后面使用。

生成BRDF数据,BRDF就是微平面模型,也是物理材质现在常用的实现方式。
BRDF最后总结出来了一个DVF:
D项 定义了高光的形状
V项 解析了由于微平面相互遮蔽导致的光衰减(需要和D项配对使用)
F项 菲涅尔 根据视角和平面朝向计算反射率

接下来,我们先看一下unity内如何实现的,然后再做一个解析

来看一下,它是如何生成这里面根据你的工作流,相应的计算出来brdf的基本色 高光色 反射率等。
计算BRDF需要一个基本色和一个高光色,所以这里做了一个处理。
仔细看一下金属工作流:

这里主要求出了当前的反射率。反射率是什么,就是可以吸收多少的光,吸收的越多,漫反射就越强,反射出来的光就越少,如果吸收的越少,反射出来的光就越多,反射率就高。通过金属度来得出结果,之前在pbr材质解析中,我们了解到不同的材质的反射率不同,比如金属材质反射率很低,无限接近于0,所以它的基本色也基本全黑,但是它的高光色无限接近于基本色贴图的颜色。
这里可以看到,它的推理,其实这个的返回值是 0.96 - 0.96 * 金属度,应该是为了防止反射率全满。如果金属度的话,它的漫反射就是0,颜色全黑,也应证了金属材质的漫反射是0 。

高光也称之为镜面反射,其实就是反射的颜色。这里是根据金属度做了一个lerp操作,kDieletricSpec.rgb这是通用默认高光强度,rgb都为0.04,研究证明,非金属的反射强度都比较偏低,范围在0.02-0.05中间,所以这里使用了中间值0.04,也是为了让非金属的高光有一些颜色偏向。
金属材质的高光颜色,也就是默认的baseColor了,因为它的反射率为1,把所有的颜色都反射了出去。

上面,我们求出了材质的反射率,基本色和高光色以后,然后又调用了这个放假,继续计算数据。

这里把默认颜色 漫反射颜色 镜面反射颜色 以及反射率直接传出。
并且根据光滑度,计算相应的粗糙度。

这个其实是 1.0 - 光滑度,来计算一个初始的粗糙度。
然后,粗糙度不能为0,做了一个max操作。
后面的还不知道有什么用,再往后看看用途。

到此,也就算计算出了,BRDF计算所需的一些数据,主要就是漫反射颜色 镜面反射颜色 反射率 粗糙度。

这里调试使用,略过。

然后开始计算涂层的BRDF数据,数据跟上面差不多,里面也对手机进行了兼容,减少手机上的运算。这里不再做过多的讲解。unity的设置,涂层是没有默认颜色的,它的漫反射的颜色是0.96。

多种途径去获取阴影遮罩。

这里是获取环境光遮蔽,直接光的遮蔽和间接光的遮蔽。并且和烘焙的环境光遮蔽贴图取一个最小值。

这里是获取主光源数据,里面包含主光源的方向,距离阴影衰减(主光源默认为1,有距离衰减的光源才有渐变值)光源颜色 还有阴影遮罩的数据,如果传入了环境光遮蔽并且开启了SSAO(屏幕空间环境光遮蔽)它还能够帮你合并计算出最终的环境光遮蔽。

这里使用了实时光去混合了环境光漫反射,具体就是这一段


这里创建了一个光照数据
里面主要设置了环境色和自发光色。

总算开始计算最终的环境色了。

在这个函数里面,计算了最终的环境漫反射和环境镜面反射。

这一句,我们能够清晰看出,环境漫反射就是我们之前求出来的bakedGI。

这个函数,根据我们的菲涅尔和位置,以及粗糙度,来求出间接光的镜面反射。

到这里,我们能看到,其实,它就拿着这个数据去环境贴图,简称IBL(Image based lighting)基于图像的光照,或者反射球上面,根据粗糙的获取不同的mip层级。如果是HDR贴图,还需要进行HDR转换。来求出环境镜面反射的颜色。

我们获取到了环境光漫反射颜色和环境光镜面反射的颜色以后,使用unity内置的环境BRDF方法来计算出来最终物体上显示的环境色。

这里就是unity使用环境BRDF实现的环境色。
之前我研究的间接光照公式:IndirectLighting = DiffuseColor / pi * SH + LD * DFG(SpecularColor)
基本上差不多,只是使用的公式不一样,它这里的高光是将D项和G项 使用F项进行了一个插值。
最后,和环境光遮蔽相乘,得出了最终的环境色。unity里面好像比较喜欢直接使用默认颜色,而不是像ue里面的基本色/PI,所以unity里面显得比较亮一些。

接下来就是直接光漫反射和直接光镜面反射的获取。

这个是实现函数,里面首先计算出了NdotL并限制在了0-1范围内,然后乘以光的颜色。这是标准的兰伯特模型,unity也是没有除以PI。
直接光照公式: DirectLighting = (DiffuseColor / pi + D(Roughness,x) * V(Roughness,x) * F(SpecularColor,x) )* NdotL * LightColor
我拿之前的直接光照公式可以对比一下。
然后就是重要的直接光镜面反射实现。

可以看代码看出它是使用的GGX高光实现,具体GGX高光如何实现,大家可以查看代码和读相关资料自行查看。
最终得到的GGX高光强度,去乘以radiance,保证了,光照背面没有直接光漫反射和直接光的镜面反射。
然后直接光颜色和间接光颜色想加,这就实现了主光源的光照颜色。

如果你有其它附加光源,也需要进行相关的计算,求出光源的直接光漫反射和直接光镜面反射。环境光一次就够了。

别忘记了,还需要加上顶点上计算出来的光照颜色。
最后是合并颜色,把所有的光照数据内的颜色进行相加,得到了最终的颜色。

写完之后发现,unity内置的lit shader好乱,有的问题进行了多次处理,看来为了兼容真是做了很多的处理,后面我整理一个简洁的pbrshader吧。

以上是关于unity urp内置lit材质源码解析(下)的主要内容,如果未能解决你的问题,请参考以下文章

unity urp内置lit材质源码解析(中)

unity URP内置shader lit解析

投石问路Unity内置管线升级URP之色彩空间(伽马sRGBGamma Space和Linear Space)

在着色器图中访问二级纹理法线贴图?

Unity_URP_Rendering Debugger 调试入门之解构环境光反射光等Lit光照模型的代码逻辑

unity默认渲染管线切换到URP渲染管线并切换材质