games101 https://sites.cs.ucsb.edu/~lingqi/teaching/resources/GAMES101_Lecture_04.pdf
https://www.cnblogs.com/leixinyue/p/11166135.html
(http://glasnost.itcarlow.ie/~powerk/GeneralGraphicsNotes/projection/perspective_projection.html)
正交投影
描述: 长方体.
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QX0BAhIl-1635505648983)(./images/000.png)]
- X轴: left,right
- Y轴: top,bottom
- Z轴: near,far
M o r t h o = [ 2 r − l 0 0 − r + l 2 0 2 t − b 0 − t + b 2 0 0 2 f − n − n + f 2 0 0 0 1 ] M_{ortho} = \left[ \begin{matrix} \frac{2}{r-l} & 0 & 0 & -\frac{r+l}{2} \\ 0 & \frac{2}{t-b} & 0 & -\frac{t+b}{2}\\ 0 & 0 & \frac{2}{f-n} & -\frac{n+f}{2} \\ 0 & 0 & 0 & 1 \\ \end{matrix} \right] Mortho=⎣⎢⎢⎡r−l20000t−b20000f−n20−2r+l−2t+b−2n+f1⎦⎥⎥⎤
透视投影
1 投影到近平面
- 首先挤压视锥到长方体
- 做一次正交投影
视锥挤压为长方体, 也就相当于: 把视锥内的点都投影到视锥的近平面,z值暂时不考虑
设视锥内的点
p
(
x
,
y
,
z
)
p(x,y,z)
p(x,y,z),映射到近投影面之后
p
′
(
x
′
,
y
′
,
z
′
)
p'(x',y',z')
p′(x′,y′,z′)。
这里是z的负轴,所以z是负的.
这种映射关系满足相似三角形,可以得出:
x
′
=
n
−
z
x
y
′
=
n
−
z
y
z
′
=
?
x' = \frac{n}{-z} x \\ y' = \frac{n}{-z} y \\ z' = ?
x′=−znxy′=−znyz′=?
$ p = (x,y,z)$, p ′ = ( x ′ , y ′ , z ′ ) p'=(x',y',z') p′=(x′,y′,z′)
这里的映射可以用其次转矩阵表示为:
M
=
[
n
0
0
0
0
n
0
0
?
?
?
?
0
0
−
1
0
]
M = \left[ \begin{matrix} n & 0 & 0 & 0 \\ 0 & n & 0 & 0 \\ ? & ? & ? & ? \\ 0 & 0 & -1 & 0 \\ \end{matrix} \right]
M=⎣⎢⎢⎡n0?00n?000?−100?0⎦⎥⎥⎤
投影后点的其次坐标形式:
p
′
=
M
p
=
[
n
0
0
0
0
n
0
0
?
?
?
?
0
0
−
1
0
]
[
x
y
z
1
]
=
[
n
x
n
y
?
−
z
]
p'=Mp=\left[ \begin{matrix} n & 0 & 0 & 0 \\ 0 & n & 0 & 0 \\ ? & ? & ? & ? \\ 0 & 0 & -1 & 0 \\ \end{matrix} \right] \left[ \begin{matrix} x \\ y \\ z \\ 1 \\ \end{matrix} \right] = \left[ \begin{matrix} nx \\ ny \\ ? \\ -z \\ \end{matrix} \right]
p′=Mp=⎣⎢⎢⎡n0?00n?000?−100?0⎦⎥⎥⎤⎣⎢⎢⎡xyz1⎦⎥⎥⎤=⎣⎢⎢⎡nxny?−z⎦⎥⎥⎤
转换成普通点,同除第四个分量,这一步称为透视除法
p
′
(
x
′
,
y
′
,
z
′
)
=
(
n
−
z
x
,
n
−
z
y
,
?
)
p'(x',y',z')=(\frac{n}{-z} x, \frac{n}{-z} y, ?)
p′(x′,y′,z′)=(−znx,−zny,?)
2 存储深度
到目前位置,所有点的深度信息未知, 如果没有相对深度信息,以后将无法去除隐藏的表面。
因为深度信息和
x
,
y
x,y
x,y无关,所以矩阵第三行一定是
(
0
,
0
,
A
,
B
)
(0, 0, A, B)
(0,0,A,B),
因此投影后的深度可以表示为:
z
′
=
z
A
+
B
−
z
z' = \frac{zA+B}{-z}
z′=−zzA+B
由两个关键已知条件:
- 任何近平面的点深度都会被映射到 -1
- 任何远平面的点深度都会被映射到 +1
− A n + B n = − 1 − A f + B f = 1 \frac{-An + B}{n} = -1 \\ \frac{-Af+B}{f} = 1 n−An+B=−1f−Af+B=1
可以得出:
A
=
−
f
+
n
f
−
n
B
=
−
2
f
n
f
−
n
A = -\frac{f+n}{f-n} \\ B= \frac{-2fn}{f-n}
A=−f−nf+nB=f−n−2fn
所以,变换矩阵目前变为:
M
=
[
n
0
0
0
0
n
0
0
0
0
−
f
+
n
f
−
n
−
−
2
f
n
f
−
n
0
0
−
1
0
]
M = \left[ \begin{matrix} n & 0 & 0 & 0 \\ 0 & n & 0 & 0 \\ 0 & 0 & -\frac{f+n}{f-n} & -\frac{-2fn}{f-n} \\ 0 & 0 & -1 & 0 \end{matrix} \right]
M=⎣⎢⎢⎡n0000n0000−f−nf+n−100−f−n−2fn0⎦⎥⎥⎤
3、CVV (Canonical View Volume)
为了提高裁剪效率,我们希望修改变换后的视图体积的形状,使其独立于相机属性。这将称为规范视图体积(CVV)。这个变换可以通过下面这个矩阵完成。
N
=
[
2
r
−
l
0
0
−
r
+
l
r
−
l
0
2
t
−
b
0
−
t
+
b
t
−
b
0
0
1
0
0
0
0
1
]
N = \left[ \begin{matrix} \frac{2}{r-l} & 0 & 0 & -\frac{r+l}{r-l} \\ 0 & \frac{2}{t-b} & 0 & -\frac{t+b}{t-b} \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{matrix} \right]
N=⎣⎢⎢⎡r−l20000t−b2000010−r−lr+l−t−bt+b01⎦⎥⎥⎤
4、最后矩阵
将该归一化矩阵与透视变换矩阵相乘得到透视投影矩阵。
P
=
N
∗
M
=
[
2
n
r
−
l
0
r
+
l
r
−
l
0
0
2
n
t
−
b
t
+
b
t
−
b
0
0
0
−
f
+
n
f
−
n
−
2
f
n
f
−
n
0
0
−
1
0
]
P = N*M = \left[ \begin{matrix} \frac{2n}{r-l} & 0 & \frac{r+l}{r-l} & 0 \\ 0 & \frac{2n}{t-b} & \frac{t+b}{t-b} & 0 \\ 0 & 0 & -\frac{f+n}{f-n} & \frac{-2fn}{f-n} \\ 0 & 0 & -1 & 0 \end{matrix} \right]
P=N∗M=⎣⎢⎢⎡r−l2n0000t−b2n00r−lr+lt−bt+b−f−nf+n−100f−n−2fn0⎦⎥⎥⎤
// three.js/Matrix4.js
function makePerspective( left, right, top, bottom, near, far ) {
const te = this.elements;
const x = 2 * near / ( right - left );
const y = 2 * near / ( top - bottom );
const a = ( right + left ) / ( right - left );
const b = ( top + bottom ) / ( top - bottom );
const c = - ( far + near ) / ( far - near );
const d = - 2 * far * near / ( far - near );
te[ 0 ] = x; te[ 4 ] = 0; te[ 8 ] = a; te[ 12 ] = 0;
te[ 1 ] = 0; te[ 5 ] = y; te[ 9 ] = b; te[ 13 ] = 0;
te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = c; te[ 14 ] = d;
te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = - 1; te[ 15 ] = 0;
return this;
}