# Games101-1 Transformation 变换

图形学的第一课,讲述了基本点、矢量在二维、三维坐标中的表示形式和仿射变换的矩阵形式。

# 一、 齐次坐标

对于空间中的点

(x,y,z)(x,y,z)

和矢量

[x,y,z]T[x,y,z]^T

我们统一使用使用齐次坐标来表示

[xyzt]\begin{bmatrix} x \\ y \\ z \\ t \end{bmatrix}

其中, t==0 时代表为矢量, t==1 时代表为点。
而当 t!=0 时,规定:

[xyzt]=[x/ty/tz/t1]\begin{bmatrix} x \\ y \\ z \\ t \end{bmatrix} = \begin{bmatrix} x/t \\ y/t \\ z/t \\ 1 \end{bmatrix}

可以验证:

点 - 点 = 矢量
点 +- 矢量 = 点
矢量 +- 矢量 = 矢量
点 + 点 = 中点 (特殊定义之处)

这就是齐次坐标的巧妙之处,通过添加一维来区分点与矢量,为后文的位移变换与其他仿射变换的结合作基础。这对于二维坐标也是一样的。

# 二、 二维仿射变换

仿射变换的基本思想是将各种变换,如大小缩放,绕轴(点)旋转,平移,变换为一个矩阵表示。对于点或矩阵vv, 在经过变换rr 后,v=rvv'=r · v。这样我们就能非常方便的组合各种变换。


# 1. 平移变换

对于正常的二维点 pp

[x,y]T[x,y]^T

如果平移量为

[tx,ty]T[tx,ty]^T

那么 pp'

[x+tx,y+ty]T[x+tx,y+ty]^T

我们发现这并不能表示为一个乘积的形式。
但是如果我们使用齐次坐标

p=[x,y,0]Ttrans=[rx,ry]Tthenp=[x+rx,y+ry,0]p = [x,y,0]^T \\ trans = [rx,ry]^T \\ then \ p' = [x+rx,y+ry,0]

于是,我们可以找到一个变换矩阵

r=[10rx01ry001]r=\begin{bmatrix} 1 & 0 & rx \\ 0 & 1 & ry \\ 0 & 0 & 1 \\ \end{bmatrix}

满足 p=rpp' = r · p. 这就是齐次坐标的作用。
矩阵的最后一位数置为 1,这是为了让点和矢量都可以使用,并且在变换后同样还是点或者矩阵。


# 2. 放缩

对于二维点 p=[x,y,0]Tp=[x,y,0]^T, 放缩 t 倍变为,p=[tx,ty,0]Tp'=[tx,ty,0]^T, 很容易得出

rscale=[t000t0001]r_{scale} = \begin{bmatrix} t & 0 & 0 \\ 0 & t & 0 \\ 0 & 0 & 1 \\ \end{bmatrix}

同样,如果要分别对 x,y 进行不同大小的放缩,在指定位置修改即可。


# 3. 旋转

# ① 绕原点旋转

turn_img
设线段长度为rr,极坐标为(θ,r)(θ,r), 旋转后 (默认旋转都是逆时针为正) 为(θ+α,r)(θ+α,r).

{x0=rcos(θ)y0=rsin(θ)\begin{cases} x_0 = rcos(θ) \\ y_0 = rsin(θ) \\ \end{cases}

{x1=rcos(θ+α)y1=rsin(θ+α)\begin{cases} x_1 = rcos(θ+α) \\ y_1 = rsin(θ+α) \\ \end{cases}

{x1=rcos(θ+α)=rcos(θ)cos(α)rsin(θ)sin(α)=x0cos(α)+y0(sin(α))y1=rsin(θ+α)=rsin(θ)cos(α)+rcos(θ)sin(α)=x0sin(α)+y0cos(α)\therefore \begin{cases} x_1 = rcos(θ+α) = rcos(θ)cos(α)-rsin(θ)sin(α) = x_0cos(α) + y_0(-sin(α)) \\ y_1 = rsin(θ+α) = rsin(θ)cos(α)+rcos(θ)sin(α) = x_0sin(α) + y_0cos(α) \\ \end{cases}

变换矩阵为

rturn=[cosαsinα0sinαcosα0001]r_{turn} = \begin{bmatrix} cosα & -sinα & 0 \\ sinα & cosα & 0 \\ 0 & 0 & 1 \\ \end{bmatrix}

# ① 绕任意点旋转

很简单,我们先平移到原点上,转完了再回来。

rturnanypoint=[10tx01ty001][cosαsinα0sinαcosα0001][10tx01ty001]r_{turnanypoint} = \begin{bmatrix} 1 & 0 & t_x \\ 0 & 1 & t_y \\ 0 & 0 & 1 \\ \end{bmatrix} \begin{bmatrix} cosα & -sinα & 0 \\ sinα & cosα & 0 \\ 0 & 0 & 1 \\ \end{bmatrix} \begin{bmatrix} 1 & 0 & -t_x \\ 0 & 1 & -t_y \\ 0 & 0 & 1 \\ \end{bmatrix}

tips:
对于同一个矩阵中的仿射变换和平移,从结果来看,是先进行变换再进行平移。如果想要先进行平移再变换,必须使用矩阵乘法分开相乘。
而由于 r 的定义是对于原坐标的左乘,因此连乘的变换矩阵,结果来看是先执行右侧的变换,再执行左侧的。务必注意。


# 三、 三维仿射变换

# 1. 平移 与 缩放

这个和二维都差不多,通用形式如下:

r=[scalex00tx0scaley0ty00scaleztz0001]r = \begin{bmatrix} scale_x & 0 & 0 & t_x \\ 0 & scale_y & 0 & t_y \\ 0 & 0 & scale_z & t_z \\ 0 & 0 & 0 & 1 \end{bmatrix}


# 2. 旋转

任意的旋转可以表示为欧拉角的旋转

  • 绕 x 轴旋转

    rturnX=[10000cosαsinα00sinαcosα00001]r_{turn_X} = \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & cosα & -sinα & 0 \\ 0 & sinα & cosα & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix}

  • 绕 y 轴旋转

    rturnY=[cosα0sinα00100sinα0cosα00001]r_{turn_Y} = \begin{bmatrix} cosα & 0 & sinα& 0 \\ 0 & 1 & 0 & 0 \\ -sinα & 0 & cosα & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix}

  • 绕 z 轴旋转

    rturnZ=[cosαsinα00sinαcosα0000100001]r_{turn_Z} = \begin{bmatrix} cosα & -sinα & 0 & 0 \\ sinα & cosα & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix}

可以看出,绕着某一轴旋转,某一轴的坐标是不变的。剩下两个坐标在旋转,类似于二维的旋转。其中只有绕 y 轴旋转非常特殊,右上角为 sinα,左下角为 - sinα。
为啥捏?

turn3
由于是右手系,对于 x、z 轴来说,从上方看去,就是正常的右手二维系,直接参考二维的旋转即可。而对于 y 轴,会变为 z 轴在 x 轴的 - 90°,这是一个左手系。因此我们要修改 α 为 -α。

# 3. 罗德里格斯公式

接下来讨论绕任意轴的旋转。
一般的,对于一个给定的轴,我们可以先移至这个轴通过原点,然后旋转,然后移回即可。因此我们着重讨论绕通过原点的任意轴 k\vec{k}的逆时针旋转 α。
不失一般性,设 k=1|k| = 1,即k\vec{k}是单位方向向量。
则有对于任意 v\vec{v}, 旋转后 vrot\vec{v_{rot}}

vrot=vcosα+(1cosα)(vk)k+sinα(k×v)\vec{v_{rot}} = \vec{v}cos\alpha+(1-cos\alpha)(\vec{v}·\vec{k})\vec{k}+sin\alpha(\vec{k} × \vec{v})

旋转矩阵为:

R=cosαI+(1cosα)KKT+sinαKR = cos\alpha I + (1-cos\alpha)KK^T + sin\alpha K^{\wedge}

其中,

K=[0kzkykz0kxkykx0]K^{\wedge} = \begin{bmatrix} 0 & -k_z & k_y \\ k_z & 0 & -k_x \\ -k_y & k_x & 0 \end{bmatrix}

推导很简单,将 v 沿着 k 分解为两个向量计算即可。推导具体可以见罗德里格斯公式推导


# 四、 Viewing Transformation

观察的投影变换,主要分为两个部分:

  • View / Camera Transformation 视图变换
  • Projection Transformation 投影变换
    • OrthoGraphic projection 正交投影
    • Perspective projection 透视投影
如何理解Viewing Transformation?

我们目前的目的是光栅化,将一个物体绘制在屏幕上。要做到这一步首先得到要显示的画面。我们需要模拟一个摄像机的行为,去对场景中排放好的东西进行绘制。
事实上,我们就是在模拟照相机拍照的过程。视图变换的目的是摆正照相机和物体,投影变换的目的是按下快门键让摄像机成像。带着这样一种思路来看下面的解释会更容易接受。

# View Trans (摆放相机)

目的:对于任意的相机,设位置向量为e\vec{e}, 面对方向为g\vec{g}, 上方向为t\vec{t}, 要将其转换到默认位置(0,0,0)(0,0,0), 面朝方向为Z-\vec{Z}, 上方向为Y\vec{Y}的摆放。
思路:先平移,然后旋转
因此:
变换矩阵

Wview=RviewTviewTview=[100ex010ey001ez0001]Rview=[Xg^×t^Yg^×t^Zg^×t^0txtytz0gxgygz00001]W_{view} = R_{view}*T_{view} \\ T_{view} = \begin{bmatrix} 1 & 0 & 0 & -e_{x} \\ 0 & 1 & 0 & -e_{y} \\ 0 & 0 & 1 & -e_{z} \\ 0 & 0 & 0 & 1 \end{bmatrix} \\ R_{view} = \begin{bmatrix} X_{\hat{g}×\hat{t}} & Y_{\hat{g}×\hat{t}} & Z_{\hat{g}×\hat{t}} & 0 \\ t_{x} & t_{y} & t_{z} & 0 \\ -g_{x} & -g_{y} & -g_{z} & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} \\

$R_{view}$的推导

重要结论:一切旋转变换矩阵,必是正交矩阵。证明可以考虑将所有旋转变换矩阵转过去转回来一定是相反的效果,因此角度取相反数的两个旋转矩阵相乘必为单位矩阵,即互为逆矩阵。而任意的旋转可以拆为欧拉角的旋转。根据公式,带入各角度,可以发现角度相反的两个矩阵互为转置矩阵。因此旋转变换矩阵必为正交矩阵。

根据逆向思考,我们想把方向转过去,那么就是求从 - Z 轴和 Y 轴转过来的逆矩阵。

# 投影变换

# 正交

Mortho=[2rl00002tb00002nf00001][100r+l2010t+b2001n+f20001]缩放+平移M_{ortho} = \begin{bmatrix} \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{bmatrix} * \begin{bmatrix} 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{bmatrix} \\ 缩放 + 平移

# 透视

Mpreortho=[n0000n0000n+fnf0010]Mortho=[2rl00002tb00002nf00001][100r+l2010t+b2001n+f20001]Mper=MorthoMpreorthoM_{pre→ortho} = \begin{bmatrix} n & 0 & 0 & 0 \\ 0 & n & 0 & 0 \\ 0 & 0 & n+f & -nf \\ 0 & 0 & 1 & 0 \end{bmatrix}\\ M_{ortho} = \begin{bmatrix} \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{bmatrix} * \begin{bmatrix} 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{bmatrix} \\ M_{per} = M_{ortho}*M_{pre→ortho}

# 视锥

视锥
用 width,height(或者是 width + 宽高比),视角来表达视角空间。

# 最终反变换上屏幕

视口变换
视口变换

更新于 阅读次数

请我喝[茶]~( ̄▽ ̄)~*

Yian Zhao 微信支付

微信支付

Yian Zhao 支付宝

支付宝

Yian Zhao 贝宝

贝宝