渲染角色的时候需要表现出皮肤的通透感,找到下面四种模拟的方法:预积分,贴图映射,matcap,模拟透光。
预积分的方法
把次表面散射的效果预计算成一张二维查找表,查找表的参数分别是dot(N,L)和曲率,因为这两者结合就能够反映出光照随着曲率的变化。
fixed3 sss =tex2D(_SSSLUT,float2(nl*0.499+0.5,cuv));
但是边缘不够通透,这种方法可能更适用于写实效果。
贴图映射
其实上面的预积分方法也属于贴图映射的手段。先来看看效果,原文档在这里。
采样的贴图:
//nl和nv的数值并不是定死的,可以暴露出来调节。fixed3 SSS = tex2D(_SSSLUT,float2(nv*0.8,nl*0.3+0.5));
效果依旧不是很好,非常像橡胶,而且这张图美术表示不好调整。再看看下面一种方法。
matcap
matcap应该都比较熟悉,查看这篇文章看看模拟皮肤。
上面三种效果仍然达不到要求,再来看看模拟透射。
模拟透射
附上原文链接:https://www.alanzucconi.com/2017/08/30/fast-subsurface-scattering-1/
假设光源照射到了某个物体,并且光线穿透了物体。
可以看到正面的效果是L贡献的,背面的效果则是-L,之后只要计算-L贡献的效果就可以了。
出射光经过了物体吸收、散射等等,到背光面时我们能看到多少投射出来的光?假设视线正好跟-L的方向一样,则能看见最多的光,如果视线垂直于-L,就是最少的光。
这取决于视线,如何表现这种效果呢?在计算漫反射的时候,法线和光线符合这种规律,即dot(N,L)。那么描述视线和-L的关系就可以表现为dot(V,-L)。但是法线还是会多少影响到透射的光线,如何表现出这种影响,作者给出了计算方法:dot(V,-normilize(L+Nδ))
然后又加入了控制项,并且可以使用用贴图做mask控制需要透光的部分(作者解释为厚度图)。
float3 Hback = normalize(lightDir + bump*_Distortion);float VH=pow(saturate(dot(viewDir,-Hback)),_Power)*_Scale;half3 thickness = tex2D(_LocalThickness,i.uv.xy);float3 Iback = _Attenuation * VH * thickness * lightColor*_SSSColor ;
厚度图也可以直接烘焙出来:
翻转模型的面渲染AO贴图贴图颜色取反
总算达到了美术的透光要求,也可以用菲涅尔加遮罩来模拟皮肤边缘的透光,只要结果正确那就是正确的。当然菲涅尔的控制没有模拟光透射的效果好,细节也比不上。项目角色就不发了,毕竟还没上线。
下面随便找个模型调节一下,使用模型自己的法线,暂时不使用厚度图控制:
在实际的项目中,皮肤渲染我同时使用了预积分加模拟透射的方式,不管是卡通还是效果都得到了满意的效果。