作用:融合两个法线向量
用法:
void InitializeFragmentNormal(inout Interpolators i){
float3 mainNormal = UnpackScaleNormal(tex2D(_NormalMap, i.uv.xy), _BumpScale); // 根据平台自动对方法线贴图使用正确的解码,并缩放法线
float3 detailNormal = UnpackScaleNormal(tex2D(_DetailNormalMap, i.uv.zw), _DetailBumpScale); // 根据平台自动对方法线贴图使用正确的解码,并缩放法线
i.normal = BlendNormals(mainNormal, detailNormal); // 融合法线
i.normal = i.normal.xzy; // 交换z和y
}
源码:
详细解析
融合法线
将主反照率和细节反照率相乘。但不能用法线来做这件事,因为它们是向量。在归一化之前,可以先把他们平均化。
(平均法线)
结果不是很好。主凹凸和细节凹凸都会变平。理想情况下,当其中一个平坦时,它根本不会影响另一个。
我们在这里实际上要尝试做的是结合两个高度场。平均它们没有意义。叠加它们更有意义。当添加两个高度函数时,它们的斜率(也就是它们的导数)也要相加。
我们可以从法线中提取导数吗?
之前,我们通过归一化构造了自己的法线向量
法线贴图包含相同类型的法线,除了它们的Y和Z分量已互换。所以它们的形式是
但是,这些法线已通过标准化过程进行了缩放。所以我们从
开始。
s是任意比例因子。Z分量等于该因子。这意味着我们可以通过将X和Y除以Z来找到偏导数。这仅在Z为零(与垂直表面相对应)时失败。我们的凹凸远没有那么陡峭,所以不必为此担心。
一旦有了导数,就可以将它们相加,以求出总和高度场的导数。然后,我们转换回法线向量。在归一化之前,所得向量为
(增加导数)
这样会产生更好的结果!当组合大部分为平面的贴图时,它的效果很好。但是,合并陡峭的斜率仍然会丢失细节。另一种替代方法是泛白混合。首先,将新法线乘以 MzDz。之所以可以这样做,是因为之后无论如何都要进行归一化。这给了我们向量
然后降低X和Y的缩放比例,得到
这种调整会夸大X和Y分量,从而沿陡峭的坡度产生更明显的凸起。但是,当一个法线平坦时,另一个法线不会改变。
为什么称为泛白混合?
该方法由Christopher Oat在SIGGRAPH’07上首次公开描述。它用于AMD的Ruby:Whiteout演示中,因此得名。
(泛白混合法线,和反照率)
UnityStandardUtils包含BlendNormals函数,该函数还使用泛白混合。因此,让我们开始这个功能。它还可以标准化结果,因此我们不再需要自己做。
BlendNormals是什么样的?
它执行与我们完全相同的计算。