前言
最近,在学习UnityCG.cgjnc源码时,发现在非统一变换下,矩阵变换变成了左乘,顿时充满了疑惑,故此文章推导官方为啥这么写。
符号 | 含义 |
---|---|
T o T_o To | 模型空间下顶点的切线向量 |
T w T_w Tw | 世界空间下顶点的切线向量 |
N o , N w N_o,N_w No,Nw | 同上,N表示法线向量 |
M o w M_{ow} Mow | 模型空间到世界空间的变换矩阵 |
M w o M_{wo} Mwo | 世界空间到模型空间的变换矩阵 |
G G G | 法线向量从模型空间到世界空间的变换矩阵 |
一、特殊的法线变换
在计算光照的时候,我们常常会用到世界空间坐标下的法线。对于顶点的切线向量
T
w
T_w
Tw ,可由下列公式得到:
T
w
=
M
o
w
⋅
T
o
T_w = M_{ow} \cdot T_o
Tw=Mow⋅To
单独来说,顶点的法线向量,也可通过上式变换。但是,变换后的法线向量却不一定与变换后的切线向量垂直了。具体可看乐乐女神的图解,
所以,为了求得
N
w
N_w
Nw,我们得利用切线与法线垂直的关系。即:
T
w
⋅
N
w
=
0
T_w \cdot N_w = 0
Tw⋅Nw=0
因此,我们可以进行如下公式推导:
T
w
⋅
N
w
=
0
(
M
o
w
⋅
T
o
)
⋅
(
G
⋅
N
o
)
=
0
T
o
T
⋅
(
M
o
w
T
⋅
G
)
⋅
N
o
=
0
T_w \cdot N_w = 0 \\ (M_{ow} \cdot T_o) \cdot (G \cdot N_o) = 0 \\ T_o^T \cdot (M_{ow}^T \cdot G) \cdot N_o = 0 \\
Tw⋅Nw=0(Mow⋅To)⋅(G⋅No)=0ToT⋅(MowT⋅G)⋅No=0
因为
T
o
T
⋅
N
o
=
0
T_o^T \cdot N_o =0
ToT⋅No=0, 所以只要
M
o
w
T
⋅
G
=
I
M_{ow}^T \cdot G = I
MowT⋅G=I,上式即可成立。
故,
G
=
(
M
o
w
T
)
−
1
G
=
(
M
o
w
−
1
)
T
G = (M_{ow}^T)^{-1} \\ G = (M_{ow}^{-1})^T \\
G=(MowT)−1G=(Mow−1)T
因此,
N
w
=
(
M
o
w
−
1
)
T
⋅
N
o
N_w = (M_{ow}^{-1})^T \cdot N_o
Nw=(Mow−1)T⋅No,再来个双重转置可得,
N
w
=
N
o
T
⋅
M
o
w
−
1
N_w = N_o^T \cdot M_{ow}^{-1}
Nw=NoT⋅Mow−1,又因为
M
o
w
−
1
=
M
w
o
M_{ow}^{-1} = M_{wo}
Mow−1=Mwo,所以最终得到:
N
w
=
N
o
⋅
M
w
o
N_w = N_o \cdot M_{wo}
Nw=No⋅Mwo
这个公式,就是源码中的实现方式。