课程链接:GAMES101-现代计算机图形学入门-闫令琪
部分内容参考自Fundamentals Of Computer Graphics(虎书)7.3节
本篇笔记为本人学习上述课程总结之笔记,仅供交流
0.Review of Linear Algebra
这节课主要回顾了一下线性代数相关的基础知识,包括向量、向量运算、矩阵、矩阵运算等等。基本在本科覆盖范围内,因此叫 Review
1.Basic of Transformation
1.1 Basic of Transformation
首先用几个例子(摄像机在空间中的运动、机器人运动、视角变换)介绍一下为什么要用 Transformation
之后介绍几种二维上的基本变换
Scale
在图形学中Scale变换是非常简单的,如果你想把一个物体Scale至它的\(s\)倍,那么只需要将这个物体上所有点的分量都乘以\(s\),写成矩阵形式就是
\[ \begin{bmatrix} x^{\prime} \\ y^{\prime} \end{bmatrix}= \begin{bmatrix} s & 0 \\ 0 & s \end{bmatrix} \begin{bmatrix} x \\ y \end{bmatrix} \]
Reflection
镜像变换:将一个物体的镜像也很简单,在二维中,这个物体想沿着哪个轴镜像就将另一个轴的分量乘以即可,即
\[
\begin{bmatrix}
x^{\prime} \\
y^{\prime}
\end{bmatrix}=
\begin{bmatrix}
-1 & 0 \\
0 & 1
\end{bmatrix}
\begin{bmatrix}
x \\
y
\end{bmatrix}
\]
Shear
假设\(xy\)平面上左下角过原点的边长为1的正方形上方的两个点沿\(x\)轴平移\(a\)个单位,那么我们会发现:
- \(y=0\)上的点没有移动
- \(y=1\)上的点移动了\(a\)个单位,如点\((0,1)\)移动至了\((a,1)\)
- 垂直方向没有移动
- 如果假设\(y=0.5\)上有一个点\((0,0.5)\),那么它应该移动至\((\dfrac{a}{2},0.5)\)
那么也就是说,实际上所有的\(y\)都没变,而所有的\(x\)都变为\(x+ay\)
因此用矩阵表示如下:
\[ \begin{bmatrix} x^{\prime} \\ y^{\prime} \end{bmatrix}= \begin{bmatrix} 1 & a \\ 0 & 1 \end{bmatrix} \begin{bmatrix} x \\ y \end{bmatrix} \]
Rotate
首先规定,任何时候我们说旋转都是默认绕着原点\((0,0)\) 进行旋转(绕其他点旋转可以看作是先将物体移动至原点,进行旋转操作后再移动回去),另外,如果不规定旋转方向,那么我们默认都是逆时针旋转。现有一个物体,假设让它旋转\(\theta\)度,那么可以根据三角函数来求出旋转后的对应点的坐标。例如点\((1,0)\)将会旋转至点\((cos\theta,sin\theta)\),点\((0,1)\)将会旋转至点\((-sin\theta,cos\theta)\)。
这样我们就能很轻易地写成矩阵形式:
\[R_\theta = \left[\begin{matrix}cos\theta & -sin\theta\\ sin\theta& cos\theta\end{matrix}\right]\]
那么如果向顺时针方向旋转该怎么表达呢?顺时针方向旋转其实就是旋转了\(-\theta\),将其代入旋转矩阵得到
\[R_{-\theta} = \left[\begin{matrix}cos\theta & sin\theta\\ -sin\theta& cos\theta\end{matrix}\right]\]
这里我们发现刚好\(R_{-\theta} = R_{\theta}^T\),并且,旋转\(\theta\)角和旋转\(-\theta\)角正好是互逆的操作,因此还有\(R_{-\theta} = R_\theta^{-1}\)(逆变换的意义其实就是将矩阵变换的操作反过来,下文会继续提到),因此\(R_\theta^{-1} = R_\theta^T\)。这是因为旋转矩阵是一个正交矩阵。
求变换矩阵的方法
在变换中,无非就是将点\((x,y)\rightarrow (x^{\prime},y^{\prime})\),表示成矩阵形式就是
\(
\begin{bmatrix}
x^{\prime} \\
y^{\prime}
\end{bmatrix}=
\begin{bmatrix}
a & b \\
c & d
\end{bmatrix}
\begin{bmatrix}
x \\
y
\end{bmatrix}
\)
即 \(x^{\prime}=Mx\) 我们所做的就是求\(a,b,c,d\),那么既然一个变换矩阵会对这个物体的所有点都起作用,那么也一定对一些特殊点起作用,那么我们就可以利用几个简单的特殊点来进行问题的求解,例如上面旋转矩阵的例子中,有\((1,0)\rightarrow(\cos\theta,\sin\theta)\)和\((0,1)\rightarrow(sin\theta,cos\theta)\)用矩阵表示就是
\[
\begin{bmatrix}
\cos\theta \\
\sin\theta
\end{bmatrix}=
\begin{bmatrix}
a & b \\
c & d
\end{bmatrix}
\begin{bmatrix}
1 \\
0
\end{bmatrix}\\
\begin{bmatrix}
-\sin\theta \\
\cos\theta
\end{bmatrix}=
\begin{bmatrix}
a & b \\
c & d
\end{bmatrix}
\begin{bmatrix}
0 \\
1
\end{bmatrix}
\]
通过第一个矩阵等式我们直接就能求出\(a\)和\(c\),再代入第二个矩阵求出\(b\)和\(d\)即可,最终我们就能求得旋转矩阵为
\[R_\theta = \left[\begin{matrix}cos\theta & -sin\theta\\ sin\theta& cos\theta\end{matrix}\right]\]
这也启发了我们,如果想求一个变换矩阵,只需要将变换前后的矩阵列出来,再代入特殊点求解即可。(求解透视投影矩阵)
Translation
平移操作我们可以很简单地将一个点操作前后的坐标写出来,即
\[ x^{\prime}=x+t_x\\y^{\prime}=y+t_y \]
但是我们会发现,我们不能将其表达成两个矩阵相乘的形式,这个操作的矩阵形式为
\( \begin{bmatrix} x^{\prime} \\ y^{\prime} \end{bmatrix}= \begin{bmatrix} a & b \\ c & d \end{bmatrix} \begin{bmatrix} x \\ y \end{bmatrix}+ \begin{bmatrix} t_x \\ t_y \end{bmatrix} \)
这样一来,这里的变换就不是线性变换了,它就只能是一种特殊的变换了。
1.2 Homogeneous Coordinates
在发现这件事之后人们就开始思考,有没有一种方法能将它表达成线性变换?答案是有,这就引入了齐次坐标(Homogeneous Coordinates) 的概念。人们引入了一种新的形式来表示物体的坐标,他们在二维坐标后面又加了一个分量\(w\),规定
\[
Point(2D)=
\begin{bmatrix}
x \\
y \\
1
\end{bmatrix}
\]
\[ Vector(2D)= \begin{bmatrix} x \\ y \\ 0 \end{bmatrix} \]
这样,平移的变换就可以写成线性变换形式,即
\[ \begin{bmatrix} x^{\prime} \\ y^{\prime} \\ w^{\prime} \end{bmatrix}= \begin{bmatrix} 1 & 0 & t_x \\ 0 & 1 & t_y \\ 0 & 0 & 1 \end{bmatrix} \begin{bmatrix} x \\ y \\ 1 \end{bmatrix}= \begin{bmatrix} x+t_x \\ y+t_y \\ 1 \end{bmatrix} \]
为什么在二维点的后面增加了1而在二维向量的后面增加了0呢?其实是有意义的。因为我们知道,在空间里,两向量和必为一个新的向量,如果坐标最后是0,那么相加后最后还是0;如果空间中的点,如果一个点减一个点,这样就形成了一个向量(末点-初点),我们发现最后的坐标是1时相减得到0,变成了一个向量,刚好也满足;一个点加一个向量表示为一个点沿着一个方向移动,移动到了一个新的点上,最后得到的还是一个点,最后的分量还是1,也可验证。因此第三个分量的引入,在点上加一个1,在向量上加一个0,保证了这些操作最后的结果是对的。
\[ vector+vector=vector \\ point-point=vector \\ point+vector=point \\ point+point=?? \\ \]
那么最后一个,两点相加后,最后的分量是2,这是什么意思呢?人们也扩充了它的定义,即齐次坐标
\(
\begin{bmatrix}
x \\
y \\
w
\end{bmatrix}
\)
表示的是二维点
\(
\begin{bmatrix}
x/w \\
y/w \\
1
\end{bmatrix},
w\not = 0
\)
因此两点相加表达的是它们的中点。
在引入齐次坐标之前,我们做平移、旋转等操作可以起个名字叫做仿射变换(Affine Transformation),仿射(Affine map) = linear map + translation,即
\[
\begin{bmatrix}
x^{\prime} \\
y^{\prime}
\end{bmatrix}=
\begin{bmatrix}
a & b \\
c & d
\end{bmatrix}
\begin{bmatrix}
x \\
y
\end{bmatrix}+
\begin{bmatrix}
t_x \\
t_y
\end{bmatrix}
\]
使用齐次坐标来表达就可以写成
\[
\begin{bmatrix}
x^{\prime} \\
y^{\prime} \\
1
\end{bmatrix}=
\begin{bmatrix}
a & b & t_x\\
c & d & t_y\\
0 & 0 & 1
\end{bmatrix}
\begin{bmatrix}
x \\
y \\
1
\end{bmatrix}
\]
下面利用齐次坐标来重新书写我们前面所学的各种变换
\[
Scale:S(s_x,s_y)=
\begin{bmatrix}
s_x & 0 & 0 \\
0 & s_y & 0 \\
0 & 0 & 1
\end{bmatrix}
\]
\[
Rotation:R(\alpha )=
\begin{bmatrix}
\cos \alpha & -\sin \alpha & 0 \\
\sin \alpha & \cos \alpha & 0 \\
0 & 0 & 1
\end{bmatrix}
\]
\[
Translation:T(t_x,t_y)=
\begin{bmatrix}
1 & 0 & t_x \\
0 & 1 & t_y \\
0 & 0 & 1
\end{bmatrix}
\]
1.3 Inverse TransForm and Composing TransForm
Inverse TransForm
逆变换的意义其实就是将矩阵变换的操作反过来,例如矩阵\(M\)通过旋转矩阵\(R\)得到\(M^{\prime}\),那么如果我们已知变换后的矩阵\(M^{\prime}\)想求得M只需要左乘旋转矩阵\(R\)的逆\(R^{-1}\),即 \[ M^{\prime}=RM \\ M=R^{-1}M^{\prime} \]
Composing TransForm
复杂的变换可以通过多个变换组合来得到,其中,变换顺序至关重要,因为矩阵相乘不满足交换律。做一次变换可以理解为左乘一个矩阵,当然我们也可以将多次变换的矩阵的作用效果看作是一个矩阵的作用效果,因为矩阵相乘满足结合律。
1.4 3D Transformations
升维到3维,首先我们依然引入齐次坐标,得到三维点和三维向量:
\[
Point(3D)=(x,y,z,1)^T \\
Vector(2D)=(x,y,z,0)^T
\]
Generally,齐次坐标\(\begin{bmatrix}x\\y\\z\\w\end{bmatrix},w\not =0\)表示点\(\begin{bmatrix}x/w\\y/w\\z/w\end{bmatrix}\)。
当然,我们也可以用4×4的矩阵表达仿射变换,即
\[
\begin{bmatrix}
x^{\prime} \\
y^{\prime} \\
z^{\prime} \\
1
\end{bmatrix}=
\begin{bmatrix}
a & b & c & t_x\\
d & e & f & t_y\\
g & h & i & t_z\\
0 & 0 & 0 & 1
\end{bmatrix}
\begin{bmatrix}
x \\
y \\
z \\
1
\end{bmatrix}
\]
上图升维到三维下的坐标变换,对应的还是先旋转再平移
对应的三维中的各种变换表达如下:
\[
Scale:S(s_x,s_y,s_z)=
\begin{bmatrix}
s_x & 0 & 0 & 0\\
0 & s_y & 0 & 0\\
0 & 0 & s_z & 0\\
0 & 0 & 0 & 1
\end{bmatrix}
\]
\[
Translation:T(t_x,t_y)=
\begin{bmatrix}
1 & 0 & 0 & t_x \\
0 & 1 & 0 & t_y \\
0 & 0 & 1 & t_z \\
0 & 0 & 0 & 1
\end{bmatrix}
\]
\[
Rotation:R_x(\alpha )=
\begin{bmatrix}
1 & 0 & 0 & 0 \\
0 & \cos \alpha & -\sin \alpha & 0 \\
0 & \sin \alpha & \cos \alpha & 0 \\
0 & 0 & 0 & 1
\end{bmatrix}
\]
\[
Rotation:R_y(\alpha )=
\begin{bmatrix}
\cos \alpha & 0 & \sin \alpha & 0 \\
0 & 1 & 0 & 0 \\
-\sin \alpha & 0 & \cos \alpha & 0 \\
0 & 0 & 0 & 1
\end{bmatrix}
\]
\[
Rotation:R_z(\alpha )=
\begin{bmatrix}
\cos \alpha & -\sin \alpha & 0 & 0\\
\sin \alpha & \cos \alpha & 0 & 0\\
0 & 0 & 1 & 0 \\
0 & 0 & 0 & 1
\end{bmatrix}
\]
上图需要注意的是,绕\(y\)轴旋转时,左下角变为\(-sin\alpha\),右上角变为\(sin\alpha\),这是因为轴的顺序问题造成的,我们说轴的顺序是\(x\rightarrow y\rightarrow z\),有\(x×y =z\),\(y×z=x\),但是根据右手定则,得到\(y = z×x\),而不是\(x×z\),因此这里是反的。
并且这里需要注意坐标系,课程中使用的是右手坐标系,部分API(如:directX)和软件会使用左手坐标系。
对于一般性旋转我们可以将其转化成三个轴的旋转,即
\[R_{xyz}(\alpha,\beta,\gamma) = R_x(\alpha)R_y(\beta)R_z(\gamma)\]
如果想绕着任意一个点旋转,我们可以先将物体沿着这个点平移至原点,做旋转操作后再移回该点。
绕任意轴旋转的方程,罗德里格斯旋转公式Rodrigues’ Rotation Formula,对于给定角度\(\alpha\)和轴\(n\)
我们有
\[R(n,\alpha) = cos(\alpha)I +(1-cos(\alpha))nn^T+sin(\alpha)\left[\begin{matrix}0 & -n_z & n_y\\ n_z & 0 & -n_x\\ -n_y & n_x &0\end{matrix}\right]\]
2.MVP Transformation
接下来考虑视图或摄像机的变换
现实生活中,拍照片我们需要如下步骤:
a. 找到一个好位置安排所有人站好 (model transformation)
b. 找到一个好的角度去摆放相机(view transformation)
c. 拍照(projection transform)
2.1 视图变换(View Transformation)
三维摄像机有 7 个维度
- 位置:3维
- 朝向:3维
- 画面旋转:1维
通常用三个向量进行对应
- 位置向量 (position)\(\vec{e}\)
- 朝向向量 (look-at/gaze direction)\(\hat{g}\)
- 上方向量 (up direction) \(\hat{t}\)(由于一定和朝向正交,所以会冗余2维)
在现实生活中,假如在摄影棚里拍照,相同的人,相同的相机,相同的相对摆放位置,不管在哪一个摄影棚,拍出来的效果是一样的。也就是说,如果相机和所有物体(包括前景背景)都一起移动时,拍出来的照片一定是一样的。更抽象地说,当我们移动物体和移动相机没有相对运动时,拍出来的照片是一样的。那么我们可以将相机永远放在原点这个固定的位置上,物体都可以移动,相机永远不动,并且相机的向上方向为\(Y\)方向,看向\(-Z\)。
解释上图,相机原本在位置\(\vec e\),向\(\hat g\)看,并且向上方向为\(\hat t\),现在要把它变成固定在原点,向\(-Z\)方向看,并且up方向为\(Y\)。那么我们可以先将相机从\(\vec e\) 移到原点,然后再把观原点察方向\(\hat g\)旋转到\(-Z\)上,再把向上方向\(\hat t\)旋转到\(Y\),写成矩阵表达为\(M_{view} = R_{view}T_{view}\)
其中,将相机从\(\vec e\)移到原点很容易写出,将向量\(\vec e\)的三个分量各减去他们本身即可,为
\[ T_{view}= \begin{bmatrix} 1 & 0 & 0 & -x_e \\ 0 & 1 & 0 & -y_e \\ 0 & 0 & 1 & -z_e \\ 0 & 0 & 0 & 1 \end{bmatrix} \]
但是如何把原点观察方向\(\hat g\)旋转到\(-Z\)上,再把向上方向\(\hat t\)旋转到\(Y\)呢?这件事并不容易做,但是反过来,将\(X\)旋转到\((\hat g \times \hat t)\),将\(Y\)旋转到\(\hat t\),将\(Z\)旋转到\(-\hat g\)很容易实现,它和我们需要做的操作是一个互逆的操作,因此我们只需要求这一操作的矩阵的逆,然后因为旋转矩阵是一个正交矩阵,他的逆 = 转置 最后把刚才得到的旋转矩阵和平移矩阵相乘。
\[R_{view}^{-1} = \left[\begin{matrix}x_{\hat g×\hat t} & x_{\hat t} & x_{-\hat g} & 0\\ y_{\hat g×\hat t}& y_{\hat t} & y_{-\hat g} & 0\\z_{\hat g×\hat t} & z_{\hat t} & z_{-\hat g} & 0 \\ 0 & 0 & 0 & 1\end{matrix}\right]\quad R_{view} = \left[\begin{matrix}x_{\hat g×\hat t} & y_{\hat g×\hat t}& z_{\hat g×\hat t} & 0 \\ x_{\hat t} & y_{\hat t} & z_{\hat t}& 0\\ x_{-\hat g} & y_{-\hat g} & z_{-\hat g} & 0\\ 0 & 0 & 0 & 1\end{matrix}\right]\] 需要注意的是,为了保证相对结果不变,我们要将场景中的所有物体都做这样的变换。
2.2 投影变换(Projection Transformation)
投影变换本身是一个降维变换,图形学中主要针对于将三维投影至二维。投影包含两种投影方式:正交投影 (Orthographic Projection) 和透视投影 (Perspective Projection)
正交投影(Orthographic Projection)
正交投影操作比较简单,不管物体的远近,我们只需将它“挤”到某个平面上即可(先不考虑z分量的作用)。投影到\(XY\)平面的操作步骤如下:
- 先将相机放到标准位置上(原点,看向\(-Z\),向上为\(Y\))
- 移除掉物体的\(Z\)坐标
- 平移、缩放将结果映射到\([-1,1]^2\) (约定俗成的方法,方便后续计算)
上述方法是一个简单的理解方式,但在图形学中,还有更方便的一种操作:
- 首先定义空间中的立方体\([l,r]×[b,t]×[f,n]\),只需定义立方体的左右在\(X\)轴上的值,下上在\(Y\)轴上的值和前后在\(Z\)轴上的值(由于右手坐标系,远的值小于近),一共6个数
- 将这个方体canonical(正则)映射到标准立方体\([-1,1]^3\),将立方体的中心移动到原点,再将模型缩放至\([-1,1]^3\)
具体实现:首先通过平移将立方体中心移至原点,然后再缩放使长宽高都缩放至2
\[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}1 & 0 & 0 & -\frac{r+l}{2}\\ 0& 1 & 0 & -\frac{t+b}{2}\\0 & 0 & 1 & -\frac{n+f}{2} \\ 0 & 0 & 0 & 1\end{matrix}\right]\]
注意:
- 由于我们定义相机看向\(-Z\)方向,所以近>远,这也是为什么Direct3D使用的是左手坐标系,但左手系意味着叉积\(X×Y \not =Z\)
- 也可以用变换坐标系的方式来理解,道理是一样的,但是不直观、不好理解。
透视投影 (Perspective Projection)
透视投影是应用最广泛的投影,满足近大远小的性质,带来的视觉效果是平行线不再平行,相交于一点。
回顾一下我们之前关于齐次坐标的定义:
- \((x,y,z,1),(kx,ky,kz,k\not =0),(xz,yz,z^2,z \not =0)\)都表示三维空间中的一个相同点\((x,y,z)\),因为\(z\)也属于任何一个数\(k\)
- 举个例子:\((1,0,0,1)\)和\((2,0,0,2)\)都表示点\((1,0,0)\)
透视投影是从一个点(相机)开始,往外延伸出的一个四棱锥,我们定义近平面\(n\)和远平面\(f\),称为Frustum,和正交投影的区别在于远平面\(f\)相对更大,这也是透视投影和正交投影的主要区别。
因此我们只需要在正交投影之前增加一步,将远平面\(f\)先挤压至与近平面\(n\)相同的尺寸。也就是说透视投影的过程可分为两个步骤:近平面上面的所有点不变,先将远平面挤压至近平面的尺寸,再进行正交投影\(M_{persp\rightarrow ortho}^{(4×4)}\)。在这一过程中,我们规定:
- 近平面\(n\)永远不变
- 远平面\(f\)上的点的\(z\)值不会变(因为是在平面内挤压,远平面内\(z\)值不变)
- 远平面的中心点挤压前后不变
从侧面看Frustum会发现远近平面与相机有着相似三角形的关系,从\(y\)坐标来看就有\(y’ = \frac{n}{z}y\),因此写成矩阵形式就有
\[\begin{bmatrix}x\\y\\z\\1\end{bmatrix} \Rightarrow \begin{bmatrix}nx/z\\ny/z\\unknown\\1\end{bmatrix} == \begin{bmatrix}nx\\ny\\unknown\\z\end{bmatrix}(同乘z后仍表示同一个点)\]
那么我们从
\[M_{persp\rightarrow ortho}^{(4×4)} \begin{bmatrix}x\\y\\z\\1\end{bmatrix} = \begin{bmatrix}nx\\ny\\unknown\\z\end{bmatrix}\]
可知
\[M_{persp\rightarrow ortho}^{(4×4)} = \begin{bmatrix}n& 0 & 0 & 0\\0 & n & 0 & 0\\?& ? & ? & ?\\0& 0 & 1 & 0\end{bmatrix}\]
如何推导出来第三行呢?
- 任意在近平面上的点都没有发生变换
- 远平面的中心点也没有发生变换
(1)在近平面上,点坐标的\(z\)值其实是\(n\),代入
\[M_{persp\rightarrow ortho}^{(4×4)} \begin{bmatrix}x\\y\\z\\1\end{bmatrix} = \begin{bmatrix}nx\\ny\\unknown\\z\end{bmatrix}\]
有
\[\begin{bmatrix}x\\y\\n\\1\end{bmatrix} \Rightarrow \begin{bmatrix}x\\y\\n\\1\end{bmatrix}== \begin{bmatrix}nx\\ny\\n^2\\n\end{bmatrix}\]
第三行为\(n^2\),那么我们可以求出\(M_{persp\rightarrow ortho}^{(4×4)}\)的第三行的前两项为0,即
\[\begin{bmatrix}0& 0&A&B\end{bmatrix} \begin{bmatrix}x\\y\\n\\1\end{bmatrix} = n^2\]
现在还剩下两个未知数\(A\)和\(B\),接着我们再使用第二个条件:任意在远平面中心点坐标保持不变。
(2)在远平面上,点坐标的\(z\)值是\(f\),代入
\[\begin{bmatrix}n&0&0&0\\0&n&0&0\\0&0&A&B\\0&0&1&0\end{bmatrix} \begin{bmatrix}0\\0\\f\\1\end{bmatrix}=\begin{bmatrix}0\\0\\Af+B\\f\end{bmatrix}\Rightarrow \begin{bmatrix}0\\0\\f\\1\end{bmatrix} == \begin{bmatrix}0\\0\\f^2\\f\end{bmatrix}(同乘f后仍表示同一个点)\]
将其展开得
\[Af+B=f^2\]
根据近平面我们得到的结果,将其展开得
\[\begin{bmatrix}0& 0&A&B\end{bmatrix} \begin{bmatrix}x\\y\\n\\1\end{bmatrix} = n^2 \Rightarrow An+B=n^2\]
于是将两个展开式联立得
\[A = n+f\\B=-nf\]
因此
\[M_{persp\rightarrow ortho}^{(4×4)} = \begin{bmatrix}n& 0 & 0 & 0\\0 & n & 0 & 0\\ 0 & 0 & n+f & -nf\\0& 0 & 1 & 0\end{bmatrix}\]
透视投影的矩阵变换为
\[M_{persp} = M_{ortho}M_{persp\rightarrow ortho}\]
待翻译及深度冲突(Z-fighting):
之前已经把如何将透视投影转化成正交投影说明白了,透视投影转化成正交投影需要保证近和远两个平面都是不变的,大小上远平面要变成和近平面一样大。在表示立方体上我们需要 左右前后远近\(\textbf{(l,r,b,t,f,n)}\) 6个值来表示立方体,既然远和近在正交投影和透视投影中都是一样的,就不用管它了,我们可以将Frustum变成一个长方体,我们现在来定义这个Frustum:
如图所示,我们从摄像机出发看向某一个区域,如果假设看到的就是这个近的平面,那么我们可以定义一个宽度和高度,就好像我们在看一个显示器一样,我们需要定义一个宽高比 (aspect ratio),如\(4:3,16:9\)。我们还需要定义另外一个概念,称为field-of-view,即能看到的角度的范围。假如我们在看一个屏幕,我们可以分别从相机出发与屏幕顶边的中点和底边的中点连出两条红线,它们所形成的夹角就是垂直可视角度 (field-of-view Y, fovY)。因此,定义一个视锥需要定义一个宽高比和垂直可视角度。 有些游戏里有水平可视角度,这个可以通过长宽比和垂直可视角度推出。
有了这两个概念,我们就可以将它们和之前定义的空间中的长方体转化成同一个概念。如图所示,从侧面来看这个视锥体可以看到一个三角形,如果我们取垂直可视角度的正切值,可以发现\(tan\dfrac{fovY}{2} = \dfrac{t}{|n|}\),也就是说,如果我们知道这个近平面的距离,就能知道这个屏幕一半的高度是多少,屏幕的最高点对应的\(y\)值就是\(t\),最低点对应的\(y\)值就是\(-t\),也就是说,如果定义一个空间中的长方体,\(b=-t\),根据宽高比\(aspect = \dfrac{r}{t}\)即可求出水平方向上两边中点的坐标。
Z-fighting:
http://www.songho.ca/opengl/gl_projectionmatrix.html
「如果这篇文章对你有用,请随意打赏」
如果这篇文章对你有用,请随意打赏
使用微信扫描二维码完成支付

comments powered by Disqus