原文链接:【GAMES101】透视投影
GAMES101作业1中编程实现一个三角形旋转投影的任务,期间配置环境、找Bug费了好几天的功夫。本期,推送一些注意的地方。
1 3D Perspective Projection
How to do perspective projection
First “squish” the frustum into a cuboid n → n , f → f n \rightarrow n, f \rightarrow f n→n,f→f ( M p e r s p → o r t h o M_{persp\rightarrow ortho} Mpersp→ortho)
Do orthographic projection ( M o r t h o M_{ortho} Mortho, already known!)
就是将Frustum拉成一个长方体,然后再利用正交投影进行变换。
注意:在右手系中,相机正对 − z -z −z方向。这是一个坑,在编程时,应该 n = − z N e a r n = -zNear n=−zNear。
由
△
O
A
C
∼
△
O
B
D
\triangle OAC \sim \triangle OBD
△OAC∼△OBD,有
{
y
′
=
n
z
y
x
′
=
n
z
x
。
\left\{ \begin{aligned} y' = \frac{n}{z}y\\ x' = \frac{n}{z}x \end{aligned}\right.。
⎩⎪⎨⎪⎧y′=znyx′=znx。
在齐次坐标系中,,有
(
x
y
z
1
)
⟹
(
n
z
x
n
z
y
unknown
1
)
⟹
×
z
(
n
x
n
y
still unknown
z
)
\left ( \begin{matrix} x \\ y \\ z \\ 1 \end{matrix} \right ) \Longrightarrow \left ( \begin{matrix} \frac{n}{z}x \\ \frac{n}{z}y \\ \text{unknown} \\ 1 \end{matrix} \right ) \Longrightarrow^{\times z} \left ( \begin{matrix} nx \\ ny \\ \text{still unknown} \\ z \end{matrix} \right )
⎝⎜⎜⎛xyz1⎠⎟⎟⎞⟹⎝⎜⎜⎛znxznyunknown1⎠⎟⎟⎞⟹×z⎝⎜⎜⎛nxnystill unknownz⎠⎟⎟⎞
因此
KaTeX parse error: No such environment: equation* at position 8: \begin{̲e̲q̲u̲a̲t̲i̲o̲n̲*̲}̲M_{persp\righta…
M
p
e
r
s
p
→
o
r
t
h
o
M_{persp\rightarrow ortho}
Mpersp→ortho如下
M
p
e
r
s
p
→
o
r
t
h
o
=
(
n
0
0
0
0
n
0
0
?
?
?
?
0
0
1
0
)
M_{persp\rightarrow ortho} = \left ( \begin{matrix} n & 0 & 0 & 0 \\ 0 & n & 0 & 0 \\ ? & ? & ? & ? \\ 0 & 0 & 1 & 0 \end{matrix}\right )
Mpersp→ortho=⎝⎜⎜⎛n0?00n?000?100?0⎠⎟⎟⎞
Observation: the third row is responsible for z ’ z’ z’
- Any point on the near plane will not change
- Any point’s z z z on the far plane will not change
- Near plane
M p e r s p → o r t h o ( x y n 1 ) = ( x y n 1 ) M_{persp\rightarrow ortho} \left ( \begin{matrix}x \\ y \\ n \\ 1\end{matrix}\right ) = \left ( \begin{matrix}x \\ y \\ n \\ 1\end{matrix}\right ) Mpersp→ortho⎝⎜⎜⎛xyn1⎠⎟⎟⎞=⎝⎜⎜⎛xyn1⎠⎟⎟⎞
所以 M p e r s p → o r t h o M_{persp\rightarrow ortho} Mpersp→ortho第三行为 ( 0 , 0 , A , B ) (0, 0, A, B) (0,0,A,B)
- Far plane
M p e r s p → o r t h o ( 0 0 f 1 ) = ( 0 0 f 1 ) M_{persp\rightarrow ortho}\left ( \begin{matrix}0 \\ 0 \\ f \\ 1\end{matrix}\right ) = \left ( \begin{matrix}0 \\ 0 \\ f \\ 1\end{matrix}\right ) Mpersp→ortho⎝⎜⎜⎛00f1⎠⎟⎟⎞=⎝⎜⎜⎛00f1⎠⎟⎟⎞
综上
{
A
n
2
+
B
=
n
A
f
2
+
B
=
f
。
\left\{ \begin{aligned}A n^2 + B = n\\A f^2 + B = f\end{aligned}\right.。
{An2+B=nAf2+B=f。
解得
{
A
=
n
+
f
B
=
−
n
×
f
。
\left\{ \begin{aligned}A &= n + f\\ B &= - n \times f\end{aligned}\right.。
{AB=n+f=−n×f。
2 Orthographic Projection
In general
- We want to map a cuboid [ l , r ] × [ b , t ] × [ f , n ] [l, r] \times [b, t] \times [f, n] [l,r]×[b,t]×[f,n] to the canonical cube [ − 1 , 1 ] 3 [-1,1]^3 [−1,1]3.
需要两部操作:
- Center cuboid by translating
- Scale into “canonical” cube
因此
M
o
r
t
h
o
=
(
2
r
−
l
0
0
0
0
2
t
−
b
0
0
0
0
2
n
−
f
)
0
0
0
0
1
)
(
0
0
0
−
r
+
l
2
0
0
0
−
t
+
b
2
0
0
0
−
n
+
f
2
0
0
0
1
)
M_{ortho} = \left ( \begin{matrix} \frac{2}{r - l} & 0 & 0 & 0 \\ 0 & \frac{2}{t - b} & 0 & 0 \\ 0 & 0 & \frac{2}{n - f}) & 0\\ 0 & 0 & 0 & 1\end{matrix}\right ) \left ( \begin{matrix} 0 & 0 & 0 & -\frac{r + l}{2} \\ 0 & 0 & 0 & -\frac{t + b}{2} \\ 0 & 0 & 0 & -\frac{n + f}{2} \\ 0 & 0 & 0 & 1\end{matrix}\right )
Mortho=⎝⎜⎜⎛r−l20000t−b20000n−f2)00001⎠⎟⎟⎞⎝⎜⎜⎛000000000000−2r+l−2t+b−2n+f1⎠⎟⎟⎞
3. Filed of View
Filed of View如下
How to convert from f o v Y fovY fovY and aspect to l , r , b , t l, r, b, t l,r,b,t?
易得
{
t
=
tan
(
f
o
v
Y
2
)
∣
n
∣
,
b
=
−
t
r
=
a
s
p
e
c
t
×
t
,
l
=
−
r
。
\left\{ \begin{aligned}t &= \tan(\frac{fovY}{2}) | n |, &~b = -t\\ r &= aspect \times t, ~ &l = -r\end{aligned}\right.。
⎩⎨⎧tr=tan(2fovY)∣n∣,=aspect×t, b=−tl=−r。
综上所述,透视投影矩阵
M
p
e
r
s
p
=
M
o
r
t
h
o
×
M
p
e
r
s
p
→
o
r
t
h
o
=
(
2
r
−
l
0
0
0
0
2
t
−
b
0
0
0
0
2
n
−
f
)
0
0
0
0
1
)
(
0
0
0
−
r
+
l
2
0
0
0
−
t
+
b
2
0
0
0
−
n
+
f
2
0
0
0
1
)
(
n
0
0
0
0
n
0
0
0
0
n
+
f
−
n
×
f
0
0
1
0
)
\begin{aligned}M_{persp}=&M_{ortho} \times M_{persp\rightarrow ortho} \\=&\left ( \begin{matrix} \frac{2}{r - l} & 0 & 0 & 0 \\ 0 & \frac{2}{t - b} & 0 & 0 \\ 0 & 0 & \frac{2}{n - f}) & 0\\ 0 & 0 & 0 & 1\end{matrix}\right ) \\&\left ( \begin{matrix} 0 & 0 & 0 & -\frac{r + l}{2} \\ 0 & 0 & 0 & -\frac{t + b}{2} \\ 0 & 0 & 0 & -\frac{n + f}{2} \\ 0 & 0 & 0 & 1\end{matrix}\right ) \\&\left ( \begin{matrix}n & 0 & 0 & 0 \\ 0 & n & 0 & 0 \\ 0 & 0 & n + f & - n \times f \\ 0 & 0 & 1 & 0\end{matrix}\right )\end{aligned}
Mpersp==Mortho×Mpersp→ortho⎝⎜⎜⎛r−l20000t−b20000n−f2)00001⎠⎟⎟⎞⎝⎜⎜⎛000000000000−2r+l−2t+b−2n+f1⎠⎟⎟⎞⎝⎜⎜⎛n0000n0000n+f100−n×f0⎠⎟⎟⎞
Eigen::Matrix4f get_model_matrix(float rotation_angle)
{
Eigen::Matrix4f model = Eigen::Matrix4f::Identity();
// TODO: Implement this function
// Create the model matrix for rotating the triangle around the Z axis.
// Then return it.
double rotation_radian = rotation_angle * MY_PI / 180;
model << std::cos(rotation_radian), -std::sin(rotation_radian), 0, 0,
std::sin(rotation_radian), std::cos(rotation_radian), 0, 0,
0, 0, 1, 0,
0, 0, 0, 1;
return model;
}
Eigen::Matrix4f get_projection_matrix(float eye_fov, float aspect_ratio,
float zNear, float zFar)
{
// Students will implement this function
Eigen::Matrix4f projection = Eigen::Matrix4f::Identity();
// TODO: Implement this function
// Create the projection matrix for the given parameters.
// Then return it.
float n = -zNear;
float f = -zFar;
float t = std::abs(n) * std::tan(.5f * eye_fov * MY_PI / 180);
float b = -t;
float r = aspect_ratio * t;
float l = -r;
Eigen::Matrix4f perspective_to_orthogonal = Eigen::Matrix4f::Identity();
perspective_to_orthogonal << n, 0, 0, 0,
0, n, 0, 0,
0, 0, n + f, - n * f,
0, 0, 1, 0;
Eigen::Matrix4f orthogonal_projection = Eigen::Matrix4f::Identity();
orthogonal_projection << 2.f/(r-l), 0, 0, 0,
0, 2.f/(t-b), 0, 0,
0, 0, 2.f/(n-f), 0,
0, 0, 0, 1;
projection = orthogonal_projection * perspective_to_orthogonal;
return projection;
}