基于皮肤预积分SSS的面部卡通渲染尝试
之前我在资源商店上发了一个免费资源,内容是一个中国角色模型,其中还包含了头发,皮肤,眼球渲染的shader。现在,我想尝试做做卡通风格,而对于本例中面部卡通渲染,我打算在SSS的基础上尝试弄弄。
资源地址:https://assetstore.unity.com/packages/3d/characters/humanoids/sci-fi/chinese-cyborg-warrior-free-287098
在渲染面部次表面散射效果的时候,一个通用的做法是采样一张LUT图,这也是常用的预积分次表面散射(pre-integrated subsurface scattering)。
float3 SkinBRDF(lightDatas lightDat, surfaceDatas surfDat, half3 L, half3 lightCol, float shadow, float curvature)
{
float a2 = Common.Pow4(surfDat.roughness);
half3 H = normalize(lightDat.V + L);
half NdotH = saturate(dot(lightDat.N, H));
half NdotV = saturate(abs(dot(lightDat.N, lightDat.V)) + 1e-5);
half NdotL = saturate(dot(lightDat.N, L));
half VdotH = saturate(dot(lightDat.V, H));//LoH
half LdotH = saturate(dot(H, L));
float3 radiance = NdotL * lightCol *shadow;
half wrapNoL = 0.2 + NdotL * 0.8;
float3 sss = SAMPLE_TEXTURE2D(_SSSLUT, sampler_SSSLUT, float2(wrapNoL, curvature));
float3 diffuseTerm = surfDat.albedo * OneMinusReflectivityMetallicCustom(surfDat.metallic) * sss;
#if defined(_DIFFUSE_OFF)
diffuseTerm = half3(0, 0, 0);
#endif
float3 specularTerm = DirectBRDF_Specular(surfDat.roughness, NdotH, LdotH) * lerp(kDieletricSpec.rgb, surfDat.albedo, surfDat.metallic);// * surfDat.metallic;
#if defined(_SPECULAR_OFF)
specularTerm = half3(0, 0, 0);
#endif
return diffuseTerm * lightCol * shadow + specularTerm * radiance;
}
上面的代码是预积分次表面散射的BRDF函数部分。我们把标准PBR渲染中的diffuseTerm项里的NdotL换成我们的采样LUT得到的颜色。其中的curvature曲率来自
float curvature = SAMPLE_TEXTURE2D(_CurvatureMap, sampler_CurvatureMap, i.uv);
curvature = pow(curvature, _CurvaturePow);
采样一张曲率图得到。当然,如果你手中的模型没有曲率图,也可以使用fwidth函数来计算。
本例中,高光的渲染使用unity中lit.shader中使用的DirectBRDF_Specular函数。
half DirectBRDF_Specular(float roughness, float NdotH, float L