shader之法线变换
对于法线变换,进行非统一缩放时,如果使用跟变换顶点相同的变换矩阵来变换法线,则会得到错误的结果,即变换后的法线方向与平面不再垂直。
如何求得变换法线的矩阵呢:
转载请注明出处:http://www.cnblogs.com/jietian331/p/7047370.html
假设空间a中的某点的切线Ta和法线Na,空间a转换到空间b的矩阵Ma->b,则Ta转换到空间b中后为:Tb = Ma->bTa,求将法线从空间a转换到空间b的矩阵?
设此矩阵为G,设Na转换到空间b后为Nb,则在空间b中满足:
TbT * Nb=0,
由于:
Tb = Ma->bTa,
Nb = GNa
所以可得:
(Ma->bTa)T(GNa) = 0
推导得:
TaTMa->bTGNa = 0
由于在空间a中满足:
(Ta)TNa = 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 }