法向量从模型坐标系转换到世界坐标系

本文为bbbbbbion(可以叫我六饼)原创总结,如有疏漏请各位拍砖留言。转载请尊重原作者成果,保留出处。

1:前导知识

众所周知Unity3D shader中,把模型的顶点坐标从模型坐标系转换到世界坐标系的方法为:
float4 worldPos=mul(_Object2World,input.vertex);
由于Unity3D shader中向量默认为列向量,所以上述等式右乘矩阵。
另外有_Object2World和_World2Object互为逆矩阵。
求一个矩阵M的转置矩阵,可以使用transpos()方法:MT=transpos(M);

2:法向量的不同之处

脑补一下,法向量可以看成是由两个点组成的,因此在进行矩阵变换的时候若涉及到缩放变换,则会导致法向量不再垂直于物体表面。
因此我们不能使用float4 worldNormal=mul(_Object2World,float4(normal.xyz,0.0))来求得法向量的世界坐标。

3:正确的方法

3.1:公式推导

假定使用列向量。
设一个通过原点的面的法向量为n,面上面的非原点处的点p(点p和原点构成向量p),点转换到世界坐标的转换矩阵为M,待求的转换矩阵X为把法向量转换到世界坐标的矩阵。
则有p.nT=0
可知对法向量进行转换后仍然垂直于经过M转换的p向量:Mp.(Xn)T=0 => MpnTXT
=0
所以有MXT=I => X=(M-1)T
即,待求的转换矩阵为点转换矩阵M的转置逆矩阵。

3.2:Unity3D中应用

由上述推导可知,法线的世界坐标=mul(((_Object2World)-1)T,float4(normal,0.0))。
由于向量右乘矩阵等于左乘矩阵的转置。可得:
worldNormal=mul(float4(normal.xyz,0.0),_World2Object);

4:参考文档