Clear Coat
- 原理
- three.js实现
- 稍加分析
原理
车漆这种效果,用BRDF那个直接表达是不足以表达的,这种就出现了clearcoat,这种算通配的做法,当然,还有别的做法。
clear coat大致操作是,分为toplayer bottomlayer 和一个F
toplayer * F +(1 - F) * bottomLayer 得到最终色
three.js实现
首先是直接光照部分
#ifdef CLEARCOAT
float clearcoatDHR = material.clearcoat * clearcoatDHRApprox( material.clearcoatRoughness, ccDotNL );
reflectedLight.directSpecular += ccIrradiance * material.clearcoat * BRDF_Specular_GGX( directLight, geometry.viewDir, geometry.clearcoatNormal, vec3( DEFAULT_SPECULAR_COEFFICIENT ), vec3( 1.0 ), material.clearcoatRoughness );
reflectedLight.directSpecular += ( 1.0 - clearcoatDHR ) * irradiance * BRDF_Specular_GGX( directLight, geometry.viewDir, geometry.normal, material.specularColor, material.specularColorF90, material.specularRoughness);
reflectedLight.directDiffuse += ( 1.0 - clearcoatDHR ) * irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );
然后是间接光照部分
#ifdef CLEARCOAT
reflectedLight.indirectSpecular += clearcoatRadiance * material.clearcoat * BRDF_Specular_GGX_Environment( geometry.viewDir, geometry.clearcoatNormal, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearcoatRoughness );
float clearcoatInv = 1.0 - clearcoatDHR;
BRDF_Specular_Multiscattering_Environment( geometry, material.specularColor, material.specularRoughness, singleScattering, multiScattering );
vec3 diffuse = material.diffuseColor * ( 1.0 - ( singleScattering + multiScattering ) );
reflectedLight.indirectSpecular += clearcoatInv * radiance * singleScattering;
reflectedLight.indirectSpecular += multiScattering * cosineWeightedIrradiance;
reflectedLight.indirectDiffuse += diffuse * cosineWeightedIrradiance;
稍加分析
bottom就是(diffuse + specular)
top是只含有specular 被当做透明的蒙层
从代码看出 他仅仅计算了高光 没有去采样环境贴图
虽然函数名称带有environment,下面实现可以看见所做的事情只是拟合brdf
vec3 BRDF_Specular_GGX_Environment( const in vec3 viewDir, const in vec3 normal, const in vec3 specularColor, const in float roughness ) {
float dotNV = saturate( dot( normal, viewDir ) );
vec2 brdf = integrateSpecularBRDF( dotNV, roughness );
return specularColor * brdf.x + brdf.y;
}