参考:
https://blog.csdn.net/qq_31709249/article/details/80175119?utm_source=app&app_version=4.6.1
Fast Extraction of Viewing Frustum Planes from the World View-Projection Matrix
https://www.zhihu.com/question/46377273
https://blog.csdn.net/zxx43/article/details/41131101
视椎剔除的体六个面方程
前置知识:
[
x
c
l
i
p
y
c
l
i
p
z
c
l
i
p
w
c
l
i
p
]
=
M
p
r
o
j
e
c
t
⋅
[
x
e
y
e
y
e
y
e
z
e
y
e
w
e
y
e
]
\left[ \begin{matrix} x_{clip} \\ y_{clip} \\ z_{clip} \\ w_{clip} \\ \end{matrix} \right] = M_{project} \cdot \left[ \begin{matrix} x_{eye} \\ y_{eye} \\ z_{eye} \\ w_{eye} \\ \end{matrix} \right]
⎣⎢⎢⎡xclipyclipzclipwclip⎦⎥⎥⎤=Mproject⋅⎣⎢⎢⎡xeyeyeyezeyeweye⎦⎥⎥⎤
[ x n d c y n d c z n d c ] = [ x c l i p / w c l i p y c l i p / w c l i p z c l i p / w c l i p ] \left[ \begin{matrix} x_{ndc} \\ y_{ndc} \\ z_{ndc} \\ \end{matrix} \right] = \left[ \begin{matrix} x_{clip}/w_{clip} \\ y_{clip} /w_{clip}\\ z_{clip}/w_{clip} \\ \end{matrix} \right] ⎣⎡xndcyndczndc⎦⎤=⎣⎡xclip/wclipyclip/wclipzclip/wclip⎦⎤
设顶点V:
V
=
(
x
,
y
,
z
,
w
=
1
)
V = (x,y,z,w=1)
V=(x,y,z,w=1)
矩阵M,是ProjectMatrix左乘ModelViewMatrix
M
=
[
m
11
m
21
m
31
m
41
m
12
m
22
m
32
m
42
m
13
m
23
m
33
m
43
m
14
m
24
m
34
m
44
]
M = \left[ \begin{matrix} m_{11} & m_{21} & m_{31} & m_{41} \\ m_{12} & m_{22} & m_{32} & m_{42} \\ m_{13} & m_{23} & m_{33} & m_{43} \\ m_{14} & m_{24} & m_{34} & m_{44} \\ \end{matrix} \right]
M=⎣⎢⎢⎡m11m12m13m14m21m22m23m24m31m32m33m34m41m42m43m44⎦⎥⎥⎤
那么顶点V变换到剪裁空间:
M
∗
V
=
[
m
11
m
21
m
31
m
41
m
12
m
22
m
32
m
42
m
13
m
23
m
33
m
43
m
14
m
24
m
34
m
44
]
∗
[
x
y
z
w
]
\begin{aligned} M * V &= \left[ \begin{matrix} m_{11} & m_{21} & m_{31} & m_{41} \\ m_{12} & m_{22} & m_{32} & m_{42} \\ m_{13} & m_{23} & m_{33} & m_{43} \\ m_{14} & m_{24} & m_{34} & m_{44} \\ \end{matrix} \right] * \left[ \begin{matrix} x \\ y \\ z \\ w \\ \end{matrix} \right] \\ \end{aligned}
M∗V=⎣⎢⎢⎡m11m12m13m14m21m22m23m24m31m32m33m34m41m42m43m44⎦⎥⎥⎤∗⎣⎢⎢⎡xyzw⎦⎥⎥⎤
M ∗ V = [ m 11 x m 21 y m 31 z m 41 w m 12 x m 22 y m 32 z m 42 w m 13 x m 23 y m 33 z m 43 w m 14 x m 24 y m 34 z m 44 w ] M*V = \left[ \begin{matrix} m_{11}x & m_{21}y & m_{31}z & m_{41}w \\ m_{12}x & m_{22}y & m_{32}z & m_{42}w \\ m_{13}x & m_{23}y & m_{33}z & m_{43}w \\ m_{14}x & m_{24}y & m_{34}z & m_{44}w \\ \end{matrix} \right] M∗V=⎣⎢⎢⎡m11xm12xm13xm14xm21ym22ym23ym24ym31zm32zm33zm34zm41wm42wm43wm44w⎦⎥⎥⎤
M ∗ V = [ V r o w 1 V r o w 2 V r o w 3 V r o w 4 ] = [ x ′ y ′ z ′ w ′ ] M*V = \left[ \begin{matrix} V row_1 \\ V row_2 \\ V row_3 \\ V row_4 \\ \end{matrix} \right] = \left[ \begin{matrix} x' \\ y' \\ z' \\ w' \\ \end{matrix} \right] M∗V=⎣⎢⎢⎡Vrow1Vrow2Vrow3Vrow4⎦⎥⎥⎤=⎣⎢⎢⎡x′y′z′w′⎦⎥⎥⎤
那么ndc坐标系:
p
′
(
x
′
w
′
,
y
′
w
′
,
z
′
w
′
)
p'(\frac{x'}{w'}, \frac{y'}{w'},\frac{z'}{w'} )
p′(w′x′,w′y′,w′z′)
因为ndc范围是(-1,1),满足这个关系,则说明转换后的顶点位于视椎体内:
−
1
<
x
′
/
w
′
<
1
−
1
<
y
′
/
w
′
<
1
−
1
<
z
′
/
w
′
<
1
-1 < x'/w' < 1 \\ -1 < y'/w' < 1 \\ -1 < z'/w' < 1 \\
−1<x′/w′<1−1<y′/w′<1−1<z′/w′<1
如果顶点位于剪裁空间的左侧:
−
1
=
x
′
w
′
x
′
+
w
′
=
0
V
r
o
w
1
+
V
r
o
w
4
=
0
V
(
r
o
w
1
+
r
o
w
4
)
=
0
-1 = \frac{x'}{w'} \\ x'+w' = 0 \\ V row_1 + V row_4 = 0 \\ V (row_1 + row_4) = 0
−1=w′x′x′+w′=0Vrow1+Vrow4=0V(row1+row4)=0
一般的平面方程:
A
∗
x
+
B
∗
y
+
C
∗
z
+
D
=
0
;
(
A
,
B
,
C
)
是
平
面
的
法
向
量
A*x+B*y+C*z+D=0; (A,B,C)是平面的法向量
A∗x+B∗y+C∗z+D=0;(A,B,C)是平面的法向量因此该平面方程:
x
(
m
11
+
m
14
)
+
y
(
m
21
+
m
24
)
+
z
(
m
31
+
m
34
)
+
w
(
m
41
+
m
44
)
=
0
x(m_{11}+m_{14}) + y(m_{21}+m_{24}) + z(m_{31}+m_{34}) + w(m_{41}+m_{44}) = 0
x(m11+m14)+y(m21+m24)+z(m31+m34)+w(m41+m44)=0
其他平面类似。
参考代码:
// three.js/Frustum.js
function setFromProjectionMatrix( m ) {
const planes = this.planes;
const me = m.elements;
const me0 = me[ 0 ], me1 = me[ 1 ], me2 = me[ 2 ], me3 = me[ 3 ];
const me4 = me[ 4 ], me5 = me[ 5 ], me6 = me[ 6 ], me7 = me[ 7 ];
const me8 = me[ 8 ], me9 = me[ 9 ], me10 = me[ 10 ], me11 = me[ 11 ];
const me12 = me[ 12 ], me13 = me[ 13 ], me14 = me[ 14 ], me15 = me[ 15 ];
planes[ 0 ].setComponents( me3 - me0, me7 - me4, me11 - me8, me15 - me12 ).normalize();
planes[ 1 ].setComponents( me3 + me0, me7 + me4, me11 + me8, me15 + me12 ).normalize();
planes[ 2 ].setComponents( me3 + me1, me7 + me5, me11 + me9, me15 + me13 ).normalize();
planes[ 3 ].setComponents( me3 - me1, me7 - me5, me11 - me9, me15 - me13 ).normalize();
planes[ 4 ].setComponents( me3 - me2, me7 - me6, me11 - me10, me15 - me14 ).normalize();
planes[ 5 ].setComponents( me3 + me2, me7 + me6, me11 + me10, me15 + me14 ).normalize();
return this;
}