shader之法线变换

对于法线变换,进行非统一缩放时,如果使用跟变换顶点相同的变换矩阵来变换法线,则会得到错误的结果,即变换后的法线方向与平面不再垂直。

如何求得变换法线的矩阵呢:

转载请注明出处:http://www.cnblogs.com/jietian331/p/7047370.html

假设空间a中的某点的切线Ta和法线Na,空间a转换到空间b的矩阵Ma->b,则Ta转换到空间b中后为:T= Ma->bTa,求将法线从空间a转换到空间b的矩阵?

设此矩阵为G,设Na转换到空间b后为Nb,则在空间b中满足:

Tb* Nb=0

由于:

T= Ma->bTa

Nb = GNa

所以可得:

(Ma->bTa)T(GNa) = 0

推导得:

TaTMa->bTGNa = 0

由于在空间a中满足:

(Ta)TN= 0

所以

Ma->bTG = I

可得出:

G = (Ma->bT)-1 = (Ma->b-1)T

如果变换不包含非统一缩放,则Ma->b是正交矩阵,满足 Ma->b-1=Ma->bT,若统一缩放系数为 k,则

G = Ma->b / k

否则,则必须求解逆矩阵来得到变换法线的矩阵。

如UnityCG.cginc中的法线变换函数如下:

// Transforms direction from object to world space
inline float3 UnityObjectToWorldDir( in float3 dir )
{
    return normalize(mul((float3x3)unity_ObjectToWorld, dir));
}

// 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
}
原文地址:https://www.cnblogs.com/jietian331/p/7047370.html