一下观点是我个人的经验总结,如有不正确的地方,希望各位大神斧正。
现在是2018年2月3日,现在的业界正在流行PBR标准。但是标准PBR渲染方案并不能覆盖所有的材质类型,所以你才会在很多次世代引擎里面看到多种材质模型,他们都是基于PBR的改造。如Hair ,Skin,Eye,车漆等。
所以如果想在游戏里对角色的皮肤进行正确的着色,就不能将迪士尼那套公式直接盖过去了,我们需要做一些修改。
在管线开始时我们还是按照PBR管线走
float4 OUT = float4(0, 0, 0, 0);
half3 BaseColor = half3(1, 1, 1);
half Metallic = 0;
half Roughness = 1.0;
float3 N = float3(0, 1, 0);
half3 Emission = half3(0, 0, 0);
half3 GILighting = half3(0, 0, 0);
half Alpha = 1.0;
half InShadow = 0.0;
half AO = 1.0;
PS_GetParameters(IN, BaseColor, Metallic, Roughness, N, Emission, GILighting, InShadow, Alpha);
OUT.a = Alpha;
但是在计算光照模型的部分的时候需要做一些计算,我先贴出我的代码
float3 SubsurfaceColor = cPrincipleColorTint1 * OUT.rgb;
float4 SSSMask = tMixMap.SampleRGBA(sMixSampler, BaseMapUV(IN.TexCoord));
float Opacity = 1-SSSMask.r;
float3 H = normalize(V + L);
float InScatter = pow(saturate(dot(L, -V), 0), 12) * lerp(3, .1f, Opacity);
float NormalContribution = saturate(dot(N, H) * Opacity + 1 - Opacity);
float BackScatter = NormalContribution / (PI * 2);
float2 SkinScaterLookingUpUV = saturate(1 - lerp(BackScatter, 1, InScatter) * SSSMask.r);
float4 SkinSubScaterFinalColor = tEmissionMap.SampleRGBA(sEmissionMapSampler, SkinScaterLookingUpUV);
OUT.rgb += SkinSubScaterFinalColor.rgb;
下面我来解释一下。
我就不科普3S材质的原理了网上一搜一大把。3S材质其实有两个比较主要的(“目前业界的标准”),第一就是计算出光线透射的厚度,第二就是计算光照如何透射和透射对表面纹理的影响。
首先来说一下第一点。光纤透射的厚度计算方法目前大概有3种(我所知道的,当然还有其他的请大神告诉我一下)。第一种计算厚度的方法适用于那种比较规则的物体。比如一个立方体或者一个球。这种规则的几何体我们时能通过简单的公式就能得到物体的厚度。比如光源在一个立方体的左边,那么最右边的像素的厚度肯定时最厚的。第二种计算厚度的方法就是烘焙一张厚度图,将物体表面的厚度信息记录在那张图里。到时候光纤打上去直接采那张图的厚度就能知道物体的一部分是不是应该透射。第三种就是使用实时计算的方式,在光源方向渲染一张深度图,在视口摄像机方向对得到的像素进行矩阵变换,变换到灯光坐标系种比对深度。
有了厚度信息,下一步我们就可以开始计算光的散射了,光线进入物体后一部分反射一部分透射,透射的那部分光纤会在物体内散射。这个怎么模拟呢。对于皮肤的话最明显的就是下面那张图的感觉:
现在想模拟这种光线在介质中散射的方法之一时模糊红色通道(对皮肤而言)。模拟这种效果方法有很多了,大家可以自行发挥想象。
我做了一个耳朵的3S效果
我还模拟了耳朵里的血管,呃呃呃。。。这个和那张厚度图的制作有很大关系,可以找美术帮忙画一张人脸的厚度图
这是我自己画的,可能对人体结构理解还是不是很到位。