原理方面的东西很难搞明白,越研究疑惑越多,所以先放弃原理,今天结合unity shader来分析下如何套用原理方面的东西很难搞明白,越研究疑惑越多,所以先放弃原理,今天结合unity shader来分析下如何套用,第一次研究,如果有错误的地方欢迎指出。
反射率方程
将这个公式拆分为两部分
第一部分:
这是半球积分,表示多光源下光照的叠加,主要是为了环境反射
第二部分:半球积分以内的部分,主要是直射光的结果
第一部分跟第二部分结合过后的结果如下:
输出颜色 =
结果还是两部分组成,漫反射部分 跟 高光部分。
下面就开始分别给公式里的每一项来赋值了。
1.漫反射部分:
漫反射比例:Kd 它是用来根据金属度计算漫反射和镜面反射比例,当Metallic为1时,反射率接近1,函数返回的diffColor接近 0,表示几乎不反射漫反射。下面代码的结果得到的是个float3:albedo x Kd系数 的值
inline half OneMinusReflectivityFromMetallic(half metallic)
{
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;
}
Unity_ColorSpaceDielectricSpec为Unity的内置变量,定义了绝缘体的高光颜色和反射率,不完全为0,是一个经验值。
从第二段函数里:我们可以得到3个变量的结果:
1)specColor:有点不太好理解,只是一个由unity自带的Unity_ColorSpaceDielectricSpec内置变量,比较暗 ,跟 贴图采样 的值根据金属度来lerp,是用来做菲尼尔效果用的
metallic=0 metallic=1
2)oneMinusReflectivity :就是我们想要的Kd系数,及漫反射系数。
3)贴图颜色*oneMinusReflectivity
纹理颜色
unity分为两部分来做,一个是迪斯尼漫反射,还有一个是兰伯特漫反射,兰伯特漫反射更节省一些,效果并每有太大的差异
迪斯尼漫反射:
half DisneyDiffuse(half NdotV, half NdotL, half LdotH, half perceptualRoughness)
{
half fd90 = 0.5 + 2 * LdotH * LdotH * perceptualRoughness;
half lightScatter = (1 + (fd90 - 1) * Pow5(1 - NdotL));
half viewScatter = (1 + (fd90 - 1) * Pow5(1 - NdotV));
return lightScatter * viewScatter;
}
那么得出的结果就是:
directDiffuse = lightScatter * viewScatter ;
这个函数计算的结果 还需要 *NdotL*atten*LightColor,而的出来的结果其实就是漫反射系数 ,比lanbert好的一点 ,是随着粗造度的变化,效果稍有变化。
directDiffuse *= NdotL * attenColor;
环境光照的漫反射部分
gi.indirect.diffuse:这就是环境光的漫反射部分
GI data:
UnityLight light;
#ifdef LIGHTMAP_OFF
light.color = lightColor;
light.dir = lightDirection;
light.ndotl = LambertTerm (normalDirection, light.dir);
#else
light.color = half3(0.f, 0.f, 0.f);
light.ndotl = 0.0f;