原文链接:【GAMES101】透视投影
GAMES101作业1中编程实现一个三角形旋转投影的任务,期间配置环境、找Bug费了好几天的功夫。本期,推送一些注意的地方。
1 3D Perspective Projection
How to do perspective projection
First “squish” the frustum into a cuboid n→n,f→fn \rightarrow n, f \rightarrow fn→n,f→f (Mpersp→orthoM_{persp\rightarrow ortho}Mpersp→ortho?)
Do orthographic projection (MorthoM_{ortho}Mortho?, already known!)
就是将Frustum拉成一个长方体,然后再利用正交投影进行变换。
注意:在右手系中,相机正对?z-z?z方向。这是一个坑,在编程时,应该n=?zNearn = -zNearn=?zNear。
由△OAC?△OBD\triangle OAC \sim \triangle OBD△OAC?△OBD,有
{y′=nzyx′=nzx。\left\{ \begin{aligned} y' = \frac{n}{z}y\\ x' = \frac{n}{z}x \end{aligned}\right.。 ??????y′=zn?yx′=zn?x?。
在齐次坐标系中,,有
(xyz1)?(nzxnzyunknown1)?×z(nxnystill unknownz)\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????????????zn?xzn?yunknown1???????×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…
Mpersp→orthoM_{persp\rightarrow ortho}Mpersp→ortho?如下
Mpersp→ortho=(n0000n00????0010)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?0?0n?0?00?1?00?0??????
Observation: the third row is responsible for z’z’z’
- Any point on the near plane will not change
- Any point’s zzz on the far plane will not change
- Near plane
Mpersp→ortho(xyn1)=(xyn1)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??????
所以Mpersp→orthoM_{persp\rightarrow ortho}Mpersp→ortho?第三行为(0,0,A,B)(0, 0, A, B)(0,0,A,B)
- Far plane
Mpersp→ortho(00f1)=(00f1)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??????
综上
{An2+B=nAf2+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+fB=?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
因此
Mortho=(2r?l00002t?b00002n?f)00001)(000?r+l2000?t+b2000?n+f20001)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?l2?000?0t?b2?00?00n?f2?)0?0001???????????0000?0000?0000??2r+l??2t+b??2n+f?1??????
3. Filed of View
Filed of View如下
How to convert from fovYfovYfovY and aspect to l,r,b,tl, r, b, tl,r,b,t?
易得
{t=tan?(fovY2)∣n∣,b=?tr=aspect×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?。
综上所述,透视投影矩阵
Mpersp=Mortho×Mpersp→ortho=(2r?l00002t?b00002n?f)00001)(000?r+l2000?t+b2000?n+f20001)(n0000n0000n+f?n×f0010)\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?l2?000?0t?b2?00?00n?f2?)0?0001???????????0000?0000?0000??2r+l??2t+b??2n+f?1???????????n000?0n00?00n+f1?00?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 functionEigen::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;
}