文章目录
内容参考来自闫令琪老师的课程,有兴趣的同学可以去看完整课程
齐次坐标(Homogeneous Coordinates)
我们需要齐次坐标来帮助我们使用矩阵变换原来的顶点的位置,因为二维矩阵做不到移动二维的顶点,三维矩阵做不到移动三维的顶点,所以需要先把顶点或者向量扩展到齐次坐标,然后再做齐次坐标下的矩阵变换,最后做齐次化,得到新的变换后的顶点。
对于二维坐标,不能直接用二维矩阵做移动的操作,所以需要使用其次坐标,先把顶点或者向量转换到齐次坐标,就是为顶点添加一个w维,并设置为1,向量的w则设置为0。三维顶点或者向量是一样的,都需要在最后添加一个w维。
最后的顶点坐标需要齐次坐标做齐次化才行,就是除以w维。
顶点的旋转,要先移回原点,然后旋转,最后再移回去
3D转换矩阵(3D Transformations)
3D 缩放
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(sx,sy,sz)=⎝⎜⎜⎛sx0000sy0000sz00001⎠⎟⎟⎞
3D 平移
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(tx,ty,tz)=⎝⎜⎜⎛100001000010txtytz1⎠⎟⎟⎞
3D 旋转
坐标系统为如下图,一点顶点绕着轴 x x x 旋转 α \alpha α 角的计算如下。
对于顶点绕着各个轴旋转的矩阵就是如下形式。
R x ( α ) = ( 1 0 0 0 0 cos α − sin α 0 0 sin α cos α 0 0 0 0 1 ) R y ( α ) = ( cos α 0 sin α 0 0 1 0 0 − sin α 0 cos α 0 0 0 0 1 ) R z ( α ) = ( cos α − sin α 0 0 sin α cos α 0 0 0 0 1 0 0 0 0 1 ) \begin{array}{l} \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) \\ \\ \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) \\ \\ \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) \end{array} Rx(α)=⎝⎜⎜⎛10000cosαsinα00−sinαcosα00001⎠⎟⎟⎞Ry(α)=⎝⎜⎜⎛cosα0−sinα00100sinα0cosα00001⎠⎟⎟⎞Rz(α)=⎝⎜⎜⎛cosαsinα00−sinαcosα0000100001⎠⎟⎟⎞
对于列向量,当这些基础旋转矩阵的旋转轴朝向观察者的时候,使用的是右手坐标系,而且旋转角度
α
\alpha
α 是正的,而且都是逆时针(counter clock)方向的旋转。
举例:绕
z
z
z 轴旋转
9
0
∘
90^\circ
90∘
R
z
(
9
0
∘
)
[
1
0
0
]
=
[
cos
9
0
∘
−
sin
9
0
∘
0
sin
9
0
∘
cos
9
0
∘
0
0
0
1
]
[
1
0
0
]
=
[
0
−
1
0
1
0
0
0
0
1
]
[
1
0
0
]
=
[
0
1
0
]
{\displaystyle R_{z}(90^{\circ }){\begin{bmatrix}1\\0\\0\\\end{bmatrix}}={\begin{bmatrix}\cos 90^{\circ }&-\sin 90^{\circ }&0\\\sin 90^{\circ }&\quad \cos 90^{\circ }&0\\0&0&1\\\end{bmatrix}}{\begin{bmatrix}1\\0\\0\\\end{bmatrix}}={\begin{bmatrix}0&-1&0\\1&0&0\\0&0&1\\\end{bmatrix}}{\begin{bmatrix}1\\0\\0\\\end{bmatrix}}={\begin{bmatrix}0\\1\\0\\\end{bmatrix}}}
Rz(90∘)⎣⎡100⎦⎤=⎣⎡cos90∘sin90∘0−sin90∘cos90∘0001⎦⎤⎣⎡100⎦⎤=⎣⎡010−100001⎦⎤⎣⎡100⎦⎤=⎣⎡010⎦⎤
由roll,pitch,raw来表达右手笛卡尔坐标系绕x,y,z轴的旋转。当然用欧拉角来表示会更友好一点,
α
,
β
,
γ
\alpha, \beta, \gamma
α,β,γ 分别是绕着轴
x
,
y
,
z
x,y,z
x,y,z 的旋转角。被乘的顶点则被按照顺序旋转
R
=
R
z
(
α
)
R
y
(
β
)
R
x
(
γ
)
=
[
cos
α
−
sin
α
0
sin
α
cos
α
0
0
0
1
]
yaw
[
cos
β
0
sin
β
0
1
0
−
sin
β
0
cos
β
]
pitch
[
1
0
0
0
cos
γ
−
sin
γ
0
sin
γ
cos
γ
]
roll
{\displaystyle R=R_{z}(\alpha )\,R_{y}(\beta )\,R_{x}(\gamma )={\overset {\text{yaw}}{\begin{bmatrix}\cos \alpha &-\sin \alpha &0\\\sin \alpha &\cos \alpha &0\\0&0&1\\\end{bmatrix}}}{\overset {\text{pitch}}{\begin{bmatrix}\cos \beta &0&\sin \beta \\0&1&0\\-\sin \beta &0&\cos \beta \\\end{bmatrix}}}{\overset {\text{roll}}{\begin{bmatrix}1&0&0\\0&\cos \gamma &-\sin \gamma \\0&\sin \gamma &\cos \gamma \\\end{bmatrix}}}}
R=Rz(α)Ry(β)Rx(γ)=⎣⎡cosαsinα0−sinαcosα0001⎦⎤yaw⎣⎡cosβ0−sinβ010sinβ0cosβ⎦⎤pitch⎣⎡1000cosγsinγ0−sinγcosγ⎦⎤roll
R = [ cos α cos β cos α sin β sin γ − sin α cos γ cos α sin β cos γ + sin α sin γ sin α cos β sin α sin β sin γ + cos α cos γ sin α sin β cos γ − cos α sin γ − sin β cos β sin γ cos β cos γ ] {\displaystyle R={\begin{bmatrix}\cos \alpha \cos \beta &\cos \alpha \sin \beta \sin \gamma -\sin \alpha \cos \gamma &\cos \alpha \sin \beta \cos \gamma +\sin \alpha \sin \gamma \\\sin \alpha \cos \beta &\sin \alpha \sin \beta \sin \gamma +\cos \alpha \cos \gamma &\sin \alpha \sin \beta \cos \gamma -\cos \alpha \sin \gamma \\-\sin \beta &\cos \beta \sin \gamma &\cos \beta \cos \gamma \\\end{bmatrix}}} R=⎣⎡cosαcosβsinαcosβ−sinβcosαsinβsinγ−sinαcosγsinαsinβsinγ+cosαcosγcosβsinγcosαsinβcosγ+sinαsinγsinαsinβcosγ−cosαsinγcosβcosγ⎦⎤
Rodrigues’ Rotation Formula
而绕指定的轴旋转特定角的矩阵
绕着轴
n
n
n 旋转角度
α
\alpha
α
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(α))nnT+sin(α)N
⎝⎛0nz−ny−nz0nxny−nx0⎠⎞
Rodrigues’ Rotation Formula旋转证明
相机转换
相机平移和旋转以及投影矩阵
M
view
=
R
view
T
view
M_{\text {view}}=R_{\text {view}} T_{\text {view}}
Mview=RviewTview
相机平移
定义相机位置属性
- Position e ⃗ \vec{e} e
- Look-at / gaze direction g ^ \hat{g} g^
- Up direction t ^ \hat{t} t^
The origin, up at Y, look at -Z
其实就是相机从世界空间转换到局部空间的矩阵,把顶点移动到原点,
T
v
i
e
w
=
[
1
0
0
−
x
e
0
1
0
−
y
e
0
0
1
−
z
e
0
0
0
1
]
T_{v i e w}=\left[\begin{array}{cccc} 1 & 0 & 0 & -x_{e} \\ 0 & 1 & 0 & -y_{e} \\ 0 & 0 & 1 & -z_{e} \\ 0 & 0 & 0 & 1 \end{array}\right]
Tview=⎣⎢⎢⎡100001000010−xe−ye−ze1⎦⎥⎥⎤
相机旋转
相机的旋转矩阵其实就是把相机从世界空间到局部空间的旋转矩阵
Consider its inverse rotation: X to (g x t), Y to t, Z to -g
R view = [ x g ^ × t ^ y g ^ × t ^ z g ^ × t ^ 0 x t y t z t 0 x − g y − g z − g 0 0 0 0 1 ] R_{\text {view}}=\left[\begin{array}{cccc} x_{\hat{g} \times \hat{t}} & y_{\hat{g} \times \hat{t}} & z_{\hat{g} \times \hat{t}} & 0 \\ x_{t} & y_{t} & z_{t} & 0 \\ x_{-g} & y_{-g} & z_{-g} & 0 \\ 0 & 0 & 0 & 1 \end{array}\right] Rview=⎣⎢⎢⎡xg^×t^xtx−g0yg^×t^yty−g0zg^×t^ztz−g00001⎦⎥⎥⎤
相机投影
- Orthographic projection
- Perspective projection
最终把坐标投影到NDF,在opengl下是 [ − 1 , 1 ] 3 [-1,1]^3 [−1,1]3
NDC到屏幕空间(Canonical Cube to Screen)
光栅化(Rasterization)
- Point-in-triangle test(点在三角形中的测试)
- Aliasing(抗锯齿)
光栅化就是判断最后转换到屏幕空间的三角形,对其它的在屏幕空间的包围盒,判断像素是不是在其内,如果是,那么就画出当前点差值出来的颜色,如果不是,则继续遍历。