图形学的第一课,讲述了基本点、矢量在二维、三维坐标中的表示形式和仿射变换的矩阵形式。
# 一、 齐次坐标
对于空间中的点
(x,y,z)
和矢量
[x,y,z]T
我们统一使用使用齐次坐标来表示
⎣⎢⎢⎢⎡xyzt⎦⎥⎥⎥⎤
其中, t==0
时代表为矢量, t==1
时代表为点。
而当 t!=0
时,规定:
⎣⎢⎢⎢⎡xyzt⎦⎥⎥⎥⎤=⎣⎢⎢⎢⎡x/ty/tz/t1⎦⎥⎥⎥⎤
可以验证:
点 - 点 = 矢量
点 +- 矢量 = 点
矢量 +- 矢量 = 矢量
点 + 点 = 中点 (特殊定义之处)
这就是齐次坐标的巧妙之处,通过添加一维来区分点与矢量,为后文的位移变换与其他仿射变换的结合作基础。这对于二维坐标也是一样的。
# 二、 二维仿射变换
仿射变换的基本思想是将各种变换,如大小缩放,绕轴(点)旋转,平移,变换为一个矩阵表示。对于点或矩阵v, 在经过变换r 后,v′=r⋅v。这样我们就能非常方便的组合各种变换。
# 1. 平移变换
对于正常的二维点 p
[x,y]T
如果平移量为
[tx,ty]T
那么 p′ 为
[x+tx,y+ty]T
我们发现这并不能表示为一个乘积的形式。
但是如果我们使用齐次坐标
p=[x,y,0]Ttrans=[rx,ry]Tthen p′=[x+rx,y+ry,0]
于是,我们可以找到一个变换矩阵
r=⎣⎢⎡100010rxry1⎦⎥⎤
满足 p′=r⋅p. 这就是齐次坐标的作用。
矩阵的最后一位数置为 1,这是为了让点和矢量都可以使用,并且在变换后同样还是点或者矩阵。
# 2. 放缩
对于二维点 p=[x,y,0]T, 放缩 t 倍变为,p′=[tx,ty,0]T, 很容易得出
rscale=⎣⎢⎡t000t0001⎦⎥⎤
同样,如果要分别对 x,y 进行不同大小的放缩,在指定位置修改即可。
# 3. 旋转
# ① 绕原点旋转
![turn_img]()
设线段长度为r,极坐标为(θ,r), 旋转后 (默认旋转都是逆时针为正) 为(θ+α,r).
有
{x0=rcos(θ)y0=rsin(θ)
{x1=rcos(θ+α)y1=rsin(θ+α)
∴{x1=rcos(θ+α)=rcos(θ)cos(α)−rsin(θ)sin(α)=x0cos(α)+y0(−sin(α))y1=rsin(θ+α)=rsin(θ)cos(α)+rcos(θ)sin(α)=x0sin(α)+y0cos(α)
变换矩阵为
rturn=⎣⎢⎡cosαsinα0−sinαcosα0001⎦⎥⎤
# ① 绕任意点旋转
很简单,我们先平移到原点上,转完了再回来。
rturnanypoint=⎣⎢⎡100010txty1⎦⎥⎤⎣⎢⎡cosαsinα0−sinαcosα0001⎦⎥⎤⎣⎢⎡100010−tx−ty1⎦⎥⎤
tips:
对于同一个矩阵中的仿射变换和平移,从结果来看,是先进行变换再进行平移。如果想要先进行平移再变换,必须使用矩阵乘法分开相乘。
而由于 r 的定义是对于原坐标的左乘,因此连乘的变换矩阵,结果来看是先执行右侧的变换,再执行左侧的。务必注意。
# 三、 三维仿射变换
# 1. 平移 与 缩放
这个和二维都差不多,通用形式如下:
r=⎣⎢⎢⎢⎡scalex0000scaley0000scalez0txtytz1⎦⎥⎥⎥⎤
# 2. 旋转
任意的旋转可以表示为欧拉角的旋转
绕 x 轴旋转
rturnX=⎣⎢⎢⎢⎡10000cosαsinα00−sinαcosα00001⎦⎥⎥⎥⎤
绕 y 轴旋转
rturnY=⎣⎢⎢⎢⎡cosα0−sinα00100sinα0cosα00001⎦⎥⎥⎥⎤
绕 z 轴旋转
rturnZ=⎣⎢⎢⎢⎡cosαsinα00−sinαcosα0000100001⎦⎥⎥⎥⎤
可以看出,绕着某一轴旋转,某一轴的坐标是不变的。剩下两个坐标在旋转,类似于二维的旋转。其中只有绕 y 轴旋转非常特殊,右上角为 sinα,左下角为 - sinα。
为啥捏?
![turn3]()
由于是右手系,对于 x、z 轴来说,从上方看去,就是正常的右手二维系,直接参考二维的旋转即可。而对于 y 轴,会变为 z 轴在 x 轴的 - 90°,这是一个左手系。因此我们要修改 α 为 -α。
# 3. 罗德里格斯公式
接下来讨论绕任意轴的旋转。
一般的,对于一个给定的轴,我们可以先移至这个轴通过原点,然后旋转,然后移回即可。因此我们着重讨论绕通过原点的任意轴 k的逆时针旋转 α。
不失一般性,设 ∣k∣=1,即k是单位方向向量。
则有对于任意 v, 旋转后 vrot 为
vrot=vcosα+(1−cosα)(v⋅k)k+sinα(k×v)
旋转矩阵为:
R=cosαI+(1−cosα)KKT+sinαK∧
其中,
K∧=⎣⎢⎡0kz−ky−kz0kxky−kx0⎦⎥⎤
推导很简单,将 v 沿着 k 分解为两个向量计算即可。推导具体可以见罗德里格斯公式推导
观察的投影变换,主要分为两个部分:
- View / Camera Transformation 视图变换
- Projection Transformation 投影变换
- OrthoGraphic projection 正交投影
- Perspective projection 透视投影
如何理解Viewing Transformation?
我们目前的目的是光栅化,将一个物体绘制在屏幕上。要做到这一步首先得到要显示的画面。我们需要模拟一个摄像机的行为,去对场景中排放好的东西进行绘制。
事实上,我们就是在模拟照相机拍照的过程。视图变换的目的是摆正照相机和物体,投影变换的目的是按下快门键让摄像机成像。带着这样一种思路来看下面的解释会更容易接受。
# View Trans (摆放相机)
目的:对于任意的相机,设位置向量为e, 面对方向为g, 上方向为t, 要将其转换到默认位置(0,0,0), 面朝方向为−Z, 上方向为Y的摆放。
思路:先平移,然后旋转
因此:
变换矩阵
Wview=Rview∗TviewTview=⎣⎢⎢⎢⎡100001000010−ex−ey−ez1⎦⎥⎥⎥⎤Rview=⎣⎢⎢⎢⎡Xg^×t^tx−gx0Yg^×t^ty−gy0Zg^×t^tz−gz00001⎦⎥⎥⎥⎤
$R_{view}$的推导
重要结论:一切旋转变换矩阵,必是正交矩阵。证明可以考虑将所有旋转变换矩阵转过去转回来一定是相反的效果,因此角度取相反数的两个旋转矩阵相乘必为单位矩阵,即互为逆矩阵。而任意的旋转可以拆为欧拉角的旋转。根据公式,带入各角度,可以发现角度相反的两个矩阵互为转置矩阵。因此旋转变换矩阵必为正交矩阵。
根据逆向思考,我们想把方向转过去,那么就是求从 - Z 轴和 Y 轴转过来的逆矩阵。
# 投影变换
# 正交
Mortho=⎣⎢⎢⎢⎡r−l20000t−b20000n−f200001⎦⎥⎥⎥⎤∗⎣⎢⎢⎢⎡100001000010−2r+l−2t+b−2n+f1⎦⎥⎥⎥⎤缩放+平移
# 透视
Mpre→ortho=⎣⎢⎢⎢⎡n0000n0000n+f100−nf0⎦⎥⎥⎥⎤Mortho=⎣⎢⎢⎢⎡r−l20000t−b20000n−f200001⎦⎥⎥⎥⎤∗⎣⎢⎢⎢⎡100001000010−2r+l−2t+b−2n+f1⎦⎥⎥⎥⎤Mper=Mortho∗Mpre→ortho
# 视锥
![视锥]()
用 width,height(或者是 width + 宽高比),视角来表达视角空间。
# 最终反变换上屏幕
视口变换
![视口变换]()