法线矩阵推导
https://zhuanlan.zhihu.com/p/72734738
https://juejin.cn/post/7113952418613690382
https://blog.csdn.net/wangjianxin97?type=blog
1、为什么需要法线矩阵
vec3 normalEyeSpace = modelViewMatrix * normal;
如果模型矩阵执行了非等比缩放, 顶点的改变会导致法向量不再保持垂直关系。
缩放后 n n n不在与线段垂直了, 真正垂直的是 n ′ n' n′。
three.js 代码:
const geometry = new THREE.BufferGeometry()
const position = [];
const normals = [];
position.push(-1, 0, 0)
position.push(1, 0, 0)
position.push(0, 1, 0)
normals.push(0.5, 0.5, 0)
normals.push(0.5, 0.5, 0)
normals.push(0.5, 0.5, 0)
geometry.setAttribute('position', new THREE.Float32BufferAttribute(position, 3))
geometry.setAttribute('normal', new THREE.Float32BufferAttribute(normals, 3))
const material = new THREE.ShaderMaterial({
vertexShader: `
varying vec3 vNormal;
void main() {
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
gl_Position = projectionMatrix * mvPosition;
vNormal = normal;
}
`,
fragmentShader: `
varying vec3 vNormal;
uniform mat3 normalMatrix;
void main() {
gl_FragColor = vec4( vNormal, 1.0 );
}
`,
});
const mesh = new THREE.Mesh(geometry, material);
mesh.scale.set(0.5, 1, 1)
2 法向量矩阵推导
约定:
- 向量用小写字母的表示
- 转换矩阵用大写字母表示
假设矩阵
G
G
G 转换法向量, 矩阵
M
M
M转换切线。
如果转换到视图空间,那么
M
M
M就是modelViewMatrix
, 如果转换到世界空间,
M
M
M就是modelMatrix
。
根据假设有:
n
′
=
G
n
t
′
=
M
t
n' = G n \\ t' = M t \\
n′=Gnt′=Mt
根据几何关系有:
n
⋅
t
=
n
′
⋅
t
′
=
0
n \cdot t = n' \cdot t' = 0
n⋅t=n′⋅t′=0
带入有:
n
′
⋅
t
′
=
(
G
n
)
⋅
(
M
t
)
=
(
G
n
)
T
(
M
t
)
=
n
T
G
T
M
t
\begin{aligned} n' \cdot t' &= (G n) \cdot (M t) \\ &= (G n)^{T} (M t) \\ &= n^{T} G^{T} M t \\ \end{aligned}
n′⋅t′=(Gn)⋅(Mt)=(Gn)T(Mt)=nTGTMt
因为(向量点积用矩阵表示):
n
⋅
t
=
n
T
t
=
n
′
⋅
t
′
n \cdot t = n^{T} t = n' \cdot t'
n⋅t=nTt=n′⋅t′
所以,满足上式, 只需:
G
T
M
=
I
G^{T} M = I
GTM=I
因此:
G
T
=
M
−
1
(
G
T
)
T
=
(
M
−
1
)
T
G
=
(
M
−
1
)
T
\begin{aligned} G^{T} &= M^{-1} \\ (G^{T})^{T} &= (M^{-1})^{T} \\ G &= (M^{-1})^{T} \end{aligned}
GT(GT)TG=M−1=(M−1)T=(M−1)T