GAMES101-现代计算机图形学学习笔记(04)
Lecture 04 Transformation
原课程视频链接以及官网
b站视频链接: link .
课程官网链接: link .
三维变换
定义
根据二维的定义,三维坐标和向量同样可以根据如下公式定义:3 D 3 D 3 D point = ( x , y , z , 1 ) ⊤ =(x, y, z, 1)^{\top} = ( x , y , z , 1 ) ⊤ 3 D 3 D 3 D vector = ( x , y , z , 0 ) ⊤ =(x, y, z, 0)^{\top} = ( x , y , z , 0 ) ⊤
齐次坐标定义如下,本质是先做线性变换 再做平移变换 。( x ′ y ′ z ′ 1 ) = ( a b c t x d e f t y g h i t z 0 0 0 1 ) ⋅ ( x y z 1 ) \left(\begin{array}{l}
x^{\prime} \\
y^{\prime} \\
z^{\prime} \\
1
\end{array}\right)=\left(\begin{array}{llll}
a & b & c & t_{x} \\
d & e & f & t_{y} \\
g & h & i & t_{z} \\
0 & 0 & 0 & 1
\end{array}\right) \cdot\left(\begin{array}{l}
x \\
y \\
z \\
1
\end{array}\right) ⎝ ⎜ ⎜ ⎛ x ′ y ′ z ′ 1 ⎠ ⎟ ⎟ ⎞ = ⎝ ⎜ ⎜ ⎛ a d g 0 b e h 0 c f i 0 t x t y t z 1 ⎠ ⎟ ⎟ ⎞ ⋅ ⎝ ⎜ ⎜ ⎛ x y z 1 ⎠ ⎟ ⎟ ⎞
几种变换
缩放
相对于原点缩放矩阵 S S S 为:S ( s x , s y , s z ) = ( s x 0 0 0 0 s y 0 0 0 0 s z 0 0 0 0 1 ) \mathbf{S}\left(s_{x}, s_{y}, s_{z}\right)=\left(\begin{array}{cccc}
s_{x} & 0 & 0 & 0 \\
0 & s_{y} & 0 & 0 \\
0 & 0 & s_{z} & 0 \\
0 & 0 & 0 & 1
\end{array}\right) S ( s x , s y , s z ) = ⎝ ⎜ ⎜ ⎛ s x 0 0 0 0 s y 0 0 0 0 s z 0 0 0 0 1 ⎠ ⎟ ⎟ ⎞
相对于某点 p ( x , y , z ) p(x,y,z) p ( x , y , z ) 的缩放矩阵 S S S 为(先将坐标移到原点,再缩放,再移回,其组合矩阵如下):[ s x 0 0 0 0 s y 0 0 0 0 s z 0 ( 1 − s x ) x ( 1 − s y ) y ( 1 − s z ) z 1 ] \left[\begin{array}{cccc}
s_{x} & 0 & 0 & 0 \\
0 & s_{y} & 0 & 0 \\
0 & 0 & s_{z} & 0 \\
\left(1-s_{x}\right) x & \left(1-s_{y}\right) y & \left(1-s_{z}\right) z & 1
\end{array}\right] ⎣ ⎢ ⎢ ⎡ s x 0 0 ( 1 − s x ) x 0 s y 0 ( 1 − s y ) y 0 0 s z ( 1 − s z ) z 0 0 0 1 ⎦ ⎥ ⎥ ⎤
平移
平移矩阵 T T T 为:T ( t x , t y , t z ) = ( 1 0 0 t x 0 1 0 t y 0 0 1 t z 0 0 0 1 ) \mathbf{T}\left(t_{x}, t_{y}, t_{z}\right)=\left(\begin{array}{cccc}
1 & 0 & 0 & t_{x} \\
0 & 1 & 0 & t_{y} \\
0 & 0 & 1 & t_{z} \\
0 & 0 & 0 & 1
\end{array}\right) T ( t x , t y , t z ) = ⎝ ⎜ ⎜ ⎛ 1 0 0 0 0 1 0 0 0 0 1 0 t x t y t z 1 ⎠ ⎟ ⎟ ⎞
旋转
旋转矩阵
绕x轴:R x ( α ) = ( 1 0 0 0 0 cos α − sin α 0 0 sin α cos α 0 0 0 0 1 ) \mathbf{R}_{x}(\alpha)=\left(\begin{array}{cccc}
1 & 0 & 0 & 0 \\
0 & \cos \alpha & -\sin \alpha & 0 \\
0 & \sin \alpha & \cos \alpha & 0 \\
0 & 0 & 0 & 1
\end{array}\right) R x ( α ) = ⎝ ⎜ ⎜ ⎛ 1 0 0 0 0 cos α sin α 0 0 − sin α cos α 0 0 0 0 1 ⎠ ⎟ ⎟ ⎞
绕y轴:R y ( α ) = ( cos α 0 sin α 0 0 1 0 0 − sin α 0 cos α 0 0 0 0 1 ) \mathbf{R}_{y}(\alpha)=\left(\begin{array}{cccc}
\cos \alpha & 0 & \sin \alpha & 0 \\
0 & 1 & 0 & 0 \\
-\sin \alpha & 0 & \cos \alpha & 0 \\
0 & 0 & 0 & 1
\end{array}\right) R y ( α ) = ⎝ ⎜ ⎜ ⎛ cos α 0 − sin α 0 0 1 0 0 sin α 0 cos α 0 0 0 0 1 ⎠ ⎟ ⎟ ⎞
绕z轴:R z ( α ) = ( cos α − sin α 0 0 sin α cos α 0 0 0 0 1 0 0 0 0 1 ) \mathbf{R}_{z}(\alpha)=\left(\begin{array}{cccc}
\cos \alpha & -\sin \alpha & 0 & 0 \\
\sin \alpha & \cos \alpha & 0 & 0 \\
0 & 0 & 1 & 0 \\
0 & 0 & 0 & 1
\end{array}\right) R z ( α ) = ⎝ ⎜ ⎜ ⎛ cos α sin α 0 0 − sin α cos α 0 0 0 0 1 0 0 0 0 1 ⎠ ⎟ ⎟ ⎞
欧拉角
可以通过不同轴的旋转次序的组合来达到旋转的效果,所以引入了欧拉角这个概念。表示为:R x y z ( α , β , γ ) = R x ( α ) R y ( β ) R z ( γ ) \mathbf{R}_{x y z}(\alpha, \beta, \gamma)=\mathbf{R}_{x}(\alpha) \mathbf{R}_{y}(\beta) \mathbf{R}_{z}(\gamma) R x y z ( α , β , γ ) = R x ( α ) R y ( β ) R z ( γ ) 该方程说明欧拉角是按x,y,z轴的顺序依次旋转的。下图源自*的欧拉角示例图:
其结果为:R x y z = [ 1 0 0 0 cos β − sin β 0 sin β cos β ] ⋅ [ cos α 0 sin α 0 1 0 − sin α 0 cos α ] ⋅ [ cos γ − sin γ 0 sin γ cos γ 0 0 0 1 ] \mathbf{R}_{x y z} = \left[\begin{array}{ccc}
1 & 0 & 0 \\
0 & \cos \beta & -\sin \beta \\
0 & \sin \beta & \cos \beta
\end{array}\right] \cdot \left[\begin{array}{ccc}
\cos \alpha & 0 & \sin \alpha \\
0 & 1 & 0 \\
-\sin \alpha & 0 & \cos \alpha
\end{array}\right] \cdot \left[\begin{array}{ccc}
\cos \gamma & -\sin \gamma & 0 \\
\sin \gamma & \cos \gamma & 0 \\
0 & 0 & 1
\end{array}\right] R x y z = ⎣ ⎡ 1 0 0 0 cos β sin β 0 − sin β cos β ⎦ ⎤ ⋅ ⎣ ⎡ cos α 0 − sin α 0 1 0 sin α 0 cos α ⎦ ⎤ ⋅ ⎣ ⎡ cos γ sin γ 0 − sin γ cos γ 0 0 0 1 ⎦ ⎤ R x y z = [ c 2 c 3 − c 2 s 3 s 2 c 1 s 3 + c 3 s 1 s 2 c 1 c 3 − s 1 s 2 s 3 − c 2 s 1 s 1 s 3 − c 1 c 3 s 2 c 3 s 1 + c 1 s 2 s 3 c 1 c 2 ] \mathbf{R}_{x y z} = \left[\begin{array}{ccc}
c_{2} c_{3} & -c_{2} s_{3} & s_{2} \\
c_{1} s_{3}+c_{3} s_{1} s_{2} & c_{1} c_{3}-s_{1} s_{2} s_{3} & -c_{2} s_{1} \\
s_{1} s_{3}-c_{1} c_{3} s_{2} & c_{3} s_{1}+c_{1} s_{2} s_{3} & c_{1} c_{2}
\end{array}\right] R x y z = ⎣ ⎡ c 2 c 3 c 1 s 3 + c 3 s 1 s 2 s 1 s 3 − c 1 c 3 s 2 − c 2 s 3 c 1 c 3 − s 1 s 2 s 3 c 3 s 1 + c 1 s 2 s 3 s 2 − c 2 s 1 c 1 c 2 ⎦ ⎤
其中c 1 = cos ( α ) = cos ( Y y a w ) , s 1 = sin α = sin ( Y y a w ) c 2 = cos ( β ) = cos ( X p i t c h ) , s 2 = sin β = sin ( X p i t c h ) c 3 = cos ( γ ) = cos ( Z r o l l ) , s 3 = sin γ = sin ( Z r o l l ) \begin{aligned}
c_{1} &=\cos (\alpha)=\cos \left(Y_{y a w}\right), s_{1}=\sin \alpha=\sin \left(Y_{y a w}\right) \\
c_{2}=& \cos (\beta)=\cos \left(X_{p i t c h}\right), s_{2}=\sin \beta=\sin \left(X_{p i t c h}\right) \\
c_{3} &=\cos (\gamma)=\cos \left(Z_{r o l l}\right), s_{3}=\sin \gamma=\sin \left(Z_{r o l l}\right)
\end{aligned} c 1 c 2 = c 3 = cos ( α ) = cos ( Y y a w ) , s 1 = sin α = sin ( Y y a w ) cos ( β ) = cos ( X p i t c h ) , s 2 = sin β = sin ( X p i t c h ) = cos ( γ ) = cos ( Z r o l l ) , s 3 = sin γ = sin ( Z r o l l )
Pitch,Row,Yaw的描述可以参照下图:
由于存在旋转组合次序,所以当处于旋转次序中的中间轴一旦由于不当旋转使得它其他某个轴重合时,旋转就会出现扭曲,这种现象称为万向节死锁。而解锁时也会使得旋转插值十分扭曲。常见的解决方法是规定旋转次序、规定某个轴的旋转角度不能超过一定范围、使用四元数旋转。
轴角
旋转实际上只需要一个角度和一个旋转轴即可,所以引入了Rodrigues’ 旋转公式来解决这个问题:R ( n , α ) = cos ( α ) I + ( 1 − cos ( α ) ) n n T + sin ( α ) ( 0 − n z n y n z 0 − n x − n y n x 0 ) ⏟ N \mathbf{R}(\mathbf{n}, \alpha)=\cos (\alpha) \mathbf{I}+(1-\cos (\alpha)) \mathbf{n} \mathbf{n}^{T}+\sin (\alpha) \underbrace{\left(\begin{array}{ccc}
0 & -n_{z} & n_{y} \\
n_{z} & 0 & -n_{x} \\
-n_{y} & n_{x} & 0
\end{array}\right)}_{\mathbf{N}} R ( n , α ) = cos ( α ) I + ( 1 − cos ( α ) ) n n T + sin ( α ) N ⎝ ⎛ 0 n z − n y − n z 0 n x n y − n x 0 ⎠ ⎞
视图/摄像机变换
视图变化
视图变化本质是通过定义一个摄像机来观察物体,所以该问题也可以转换成如何定义一个摄像机。通常一个摄像机由四个部分组成:相机位置,相机朝向,相机上轴和右轴。但是我们一般只需要前三个分量,因为最后一个右轴就可以通过相机朝向和上轴叉乘得到。
我们通过相机空间观察物体,一般采用两种方式:一种是相机动,物体不动;另一种是物体动,相机不动。而本课程采用的是第二种方式,并且将相机固定在原点,朝向-z轴,并使上轴与y轴重合。
两种投影
投影所做的事是把3D空间物体投影到二维空间,同时通过一个范围约束所有坐标必须处于这段范围内,落到范围外的坐标应该被舍弃掉。通常这里需要一个投影矩阵,它描述了一个范围的坐标,比如(-100,100)。投影矩阵接着会将在这个指定的范围内的坐标变换为标准设备坐标的范围(-1.0, 1.0)。而(-125,80)的坐标显然是无法在屏幕上看到的。
通常采用的投影方式有两种,一种是正交投影,另一种是透视投影。
正交投影
正交投影假设视点无限远,所以构成的范围是一个长方体。它常常需要我们提供长方体的高,宽,*面距离以及远平面距离。如下图所示:
如何通过一个长方体 [ l , r ] × [ b , t ] × [ f , n ] [l, r] \times[b, t] \times[\mathbf{f}, \mathbf{n}] [ l , r ] × [ b , t ] × [ f , n ] 进行正交投影呢?通常有如下步骤:
1.固定相机在原点,使其朝向-z,上轴和y重合;
2.丢弃z轴;
3.把正方体规范化到 [ − 1 , 1 ] 3 [-1,1]^{3} [ − 1 , 1 ] 3 ,即先平移,后放缩:M ortho = [ 2 r − l 0 0 0 0 2 t − b 0 0 0 0 2 n − f 0 0 0 0 1 ] [ 1 0 0 − r + l 2 0 1 0 − t + b 2 0 0 1 − n + f 2 0 0 0 1 ] M_{\text {ortho}}=\left[\begin{array}{cccc}
\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{array}\right]\left[\begin{array}{cccc}
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{array}\right] M ortho = ⎣ ⎢ ⎢ ⎡ r − l 2 0 0 0 0 t − b 2 0 0 0 0 n − f 2 0 0 0 0 1 ⎦ ⎥ ⎥ ⎤ ⎣ ⎢ ⎢ ⎡ 1 0 0 0 0 1 0 0 0 0 1 0 − 2 r + l − 2 t + b − 2 n + f 1 ⎦ ⎥ ⎥ ⎤
透视投影
透视投影更像一个近小远大的截体来规定坐标的范围,它更符合人眼成像,即产生近大远小效果,在图形学中也更常见,使用得更多。它通常需要我们提供截体的FOV角度,宽高比,*面距离以及远平面距离,如下图所示:
如何进行透视投影呢?
通常采用两步:
1.做“squish”即 M persp → ortho M_{\text {persp} \rightarrow \text {ortho}} M persp → ortho ;通过挤压把远平面上的点都挤压到*面上;
2.做正交投影即 M ortho M_{\text {ortho}} M ortho 。
第一步求 M persp → ortho M_{\text {persp} \rightarrow \text {ortho}} M persp → ortho :假设*面距离视点为n,有一点坐标为 ( x ′ , y ′ , z ′ ) \left(x^{\prime}, y^{\prime}, z^{\prime}\right) ( x ′ , y ′ , z ′ ) ,远平面距离视点为f, 有一点坐标为 ( x , y , z ) (x, y, z) ( x , y , z ) ,则有 y ′ = n z y y^{\prime}=\frac{n}{z} y y ′ = z n y ,x ′ = n z x x^{\prime}=\frac{n}{z} x x ′ = z n x ,只看y轴,那么我们初始点的点y坐标为y,需要通过一个挤压变换使得 y=y’:
对于任意坐标的x和y,都需要通过一个“挤压”使其变换到 nx/z , ny/z ,可以列出等式得到:
( x y z 1 ) ⇒ ( n x / z n y / z unknown 1 ) mult. by z = = ( n x n y still unknown z ) \left(\begin{array}{l}x\\ y\\ z \\ 1\end{array}\right) \Rightarrow\left(\begin{array}{c}n x / z \\ n y / z \\ \text { unknown } \\ 1\end{array}\right) \begin{array}{l}\text { mult. } \\ \text { by z } \\ ==\end{array}\left(\begin{array}{c}n x \\ n y \\ \text { still unknown } \\ z\end{array}\right) ⎝ ⎜ ⎜ ⎛ x y z 1 ⎠ ⎟ ⎟ ⎞ ⇒ ⎝ ⎜ ⎜ ⎛ n x / z n y / z unknown 1 ⎠ ⎟ ⎟ ⎞ mult. by z = = ⎝ ⎜ ⎜ ⎛ n x n y still unknown z ⎠ ⎟ ⎟ ⎞
可得 M persp → ortho M_{\text {persp} \rightarrow \text {ortho}} M persp → ortho 大致形状为:
M persp → ortho = ( n 0 0 0 0 n 0 0 ? ? ? ? 0 0 1 0 ) M_{\text {persp} \rightarrow \text {ortho}}=\left(\begin{array}{cccc}
n & 0 & 0 & 0 \\
0 & n & 0 & 0 \\
? & ? & ? & ? \\
0 & 0 & 1 & 0
\end{array}\right) M persp → ortho = ⎝ ⎜ ⎜ ⎛ n 0 ? 0 0 n ? 0 0 0 ? 1 0 0 ? 0 ⎠ ⎟ ⎟ ⎞
同时由于*面上点的深度不会发生变化,所以将z替换为n,可得:( x y z 1 ) ⇒ ( x y n 1 ) ≡ ( n x n y n 2 n ) \left(\begin{array}{l}
x \\
y \\
z \\
1
\end{array}\right) \Rightarrow\left(\begin{array}{l}
x \\
y \\
n \\
1
\end{array}\right) \equiv\left(\begin{array}{l}
n x \\
n y \\
n^{2} \\
n
\end{array}\right) ⎝ ⎜ ⎜ ⎛ x y z 1 ⎠ ⎟ ⎟ ⎞ ⇒ ⎝ ⎜ ⎜ ⎛ x y n 1 ⎠ ⎟ ⎟ ⎞ ≡ ⎝ ⎜ ⎜ ⎛ n x n y n 2 n ⎠ ⎟ ⎟ ⎞
所以第三行可写做:( 0 0 A B ) ( x y n 1 ) = n 2 ⇒ A n + B = n 2 \left(\begin{array}{llll}
0 & 0 & A & B
\end{array}\right)\left(\begin{array}{l}
x \\
y \\
n \\
1
\end{array}\right)=n^{2} \Rightarrow A n+B=n^{2} ( 0 0 A B ) ⎝ ⎜ ⎜ ⎛ x y n 1 ⎠ ⎟ ⎟ ⎞ = n 2 ⇒ A n + B = n 2
再由于远平面的中心点也不变:( 0 0 f 1 ) ⇒ ( 0 0 f 1 ) = = ( 0 0 f 2 f ) \left(\begin{array}{l}
0 \\
0 \\
f \\
1
\end{array}\right) \Rightarrow\left(\begin{array}{l}
0 \\
0 \\
f \\
1
\end{array}\right)==\left(\begin{array}{l}
0 \\
0 \\
f^{2} \\
f
\end{array}\right) ⎝ ⎜ ⎜ ⎛ 0 0 f 1 ⎠ ⎟ ⎟ ⎞ ⇒ ⎝ ⎜ ⎜ ⎛ 0 0 f 1 ⎠ ⎟ ⎟ ⎞ = = ⎝ ⎜ ⎜ ⎛ 0 0 f 2 f ⎠ ⎟ ⎟ ⎞
所以可以解得A,B为:A n + B = n 2 , A = n + f A f + B = f 2 , B = − n f \begin{array}{ll}
A n+B=n^{2} ,& A=n+f \\
A f+B=f^{2} ,& B=-n f
\end{array} A n + B = n 2 , A f + B = f 2 , A = n + f B = − n f
第二步:
通过正交投影计算透视投影矩阵:M persp = M ortho ⋅ M persp → ortho M_{\text {persp}} = M_{\text {ortho}} \cdot M_{\text {persp} \rightarrow \text {ortho}} M persp = M ortho ⋅ M persp → ortho