1.UnityObjectToWorldNormal
用于将object space下的normal向量转换到world space下。
// Transforms normal from object to world space
inline float3 UnityObjectToWorldNormal( in float3 norm )
{
#ifdef UNITY_ASSUME_UNIFORM_SCALING
return UnityObjectToWorldDir(norm);
#else
// mul(IT_M, norm) => mul(norm, I_M) => {dot(norm, I_M.col0), dot(norm, I_M.col1), dot(norm, I_M.col2)}
return normalize(mul(norm, (float3x3)unity_WorldToObject));
#endif
}
其中,UNITY_ASSUME_UNIFORM_SCALING宏显然是优化用的,即如果是统一scale变换的情况下,直接用object to world space的矩阵就可以了,不用再去特意计算normal变换的矩阵;否则,根据Unity提供的注释,计算出变换后的normal:
[(n')^T = (M^{-1})^T cdot n^T = (n cdot M^{-1})^T
]
2.DotClamped
用于将两个向量的点积进行clamp,使其值位于0~1之间。
inline half DotClamped (half3 a, half3 b)
{
#if (SHADER_TARGET < 30)
return saturate(dot(a, b));
#else
return max(0.0h, dot(a, b));
#endif
}
3.EnergyConservationBetweenDiffuseAndSpecular
用来计算一个object的diffuse color的能量保存程度,保存程度越大,那么反射出来的diffuse color越弱,通常用来解决一个object的diffuse color + spec color过亮的问题(例如亮度超过入射光的强度)。
// Helper functions, maybe move into UnityCG.cginc
half SpecularStrength(half3 specular)
{
#if (SHADER_TARGET < 30)
// SM2.0: instruction count limitation
// SM2.0: simplified SpecularStrength
return specular.r; // Red channel - because most metals are either monocrhome or with redish/yellowish tint
#else
return max (max (specular.r, specular.g), specular.b);
#endif
}
// Diffuse/Spec Energy conservation
inline half3 EnergyConservationBetweenDiffuseAndSpecular (half3 albedo, half3 specColor, out half oneMinusReflectivity)
{
oneMinusReflectivity = 1 - SpecularStrength(specColor);
#if !UNITY_CONSERVE_ENERGY
return albedo;
#elif UNITY_CONSERVE_ENERGY_MONOCHROME
return albedo * oneMinusReflectivity;
#else
return albedo * (half3(1,1,1) - specColor);
#endif
}
我们可以这样使用:
float oneMinusReflectivity;
albedo = EnergyConservationBetweenDiffuseAndSpecular(albedo, specColor, oneMinusReflectivity);
float3 diffuse = albedo * lightColor * DotClamped(lightDir, i.normal);
float3 specular = specColor * lightColor * pow(DotClamped(halfVector, i.normal), _Smoothness);
return float4(diffuse + specular, 1);
4.DiffuseAndSpecularFromMetallic
用于根据一个object的金属化程度,计算出它的diffuse和spec分量。金属化程度越高,spec分量越大,diffuse分量越小。
inline half OneMinusReflectivityFromMetallic(half metallic)
{
// We'll need oneMinusReflectivity, so
// 1-reflectivity = 1-lerp(dielectricSpec, 1, metallic) = lerp(1-dielectricSpec, 0, metallic)
// store (1-dielectricSpec) in unity_ColorSpaceDielectricSpec.a, then
// 1-reflectivity = lerp(alpha, 0, metallic) = alpha + metallic*(0 - alpha) =
// = alpha - metallic * alpha
half oneMinusDielectricSpec = unity_ColorSpaceDielectricSpec.a;
return oneMinusDielectricSpec - metallic * oneMinusDielectricSpec;
}
inline half3 DiffuseAndSpecularFromMetallic (half3 albedo, half metallic, out half3 specColor, out half oneMinusReflectivity)
{
specColor = lerp (unity_ColorSpaceDielectricSpec.rgb, albedo, metallic);
oneMinusReflectivity = OneMinusReflectivityFromMetallic(metallic);
return albedo * oneMinusReflectivity;
}
值得注意的是,这里的specColor是API返回的,而并非是我们事先设置的。我们可以这样使用:
float oneMinusReflectivity;
albedo = DiffuseAndSpecularFromMetallic(albedo, metallic, specColor, oneMinusReflectivity);
float3 diffuse = albedo * lightColor * DotClamped(lightDir, i.normal);
float3 specular = specColor * lightColor * pow(DotClamped(halfVector, i.normal), _Smoothness);
return float4(diffuse + specular, 1);
如果你觉得我的文章有帮助,欢迎关注我的微信公众号(大龄社畜的游戏开发之路)-