文章目录
首先要了解的几点:
1.对于一个三维的点(a, b, c),我们给他加一维,从而来区分点和向量,使用0表示向量,1表示点,如(a, b, c, 0)则表示向量(a, b, c),(a, b, c, d)则表示点(a/d, b/d, c/d),即将第四维归1后的点。
2.变换的目的就是将坐标轴中的点变换到另一个位置,而变换的方法就是左乘一个变换矩阵,对一个物体变换的核心就是找到这个矩阵。
1.二维变换
a.缩放
b.翻转
c.翻转
图像的变换无非就是对于图像的每个像素点进行变换换到另一个点位从而看起来是对图像进行了不同的变换操作(无非就是乘以不同的变换矩阵),上述三种变换均为线性变换,即对
(
x
,
y
)
T
(x, y)^{T}
(x,y)T进行左乘变换矩阵实现。但是如果想对图像进行平移变换呢?如下图,很明显出现了常项,仅仅是左乘变换矩阵是不够的。
这时候刚开始说的“多加一维”则起了作用,我们用(x, y, 1)表示图像上的任意一个点。通过对
(
x
,
y
,
1
)
T
(x, y, 1)^{T}
(x,y,1)T左乘变换矩阵可以同时实现对图像点的线性变换和非线性变换。
二维变换矩阵小总结:
通过对线性变换和平移的不同组合可以实现不同组合,例如绕任意一点旋转,可以先将该点平移到原点,然后平移后的点绕原点旋转,再将该点平移至原来的位置即可实现绕任意点旋转;也可以灵活运用矩阵的逆变换。
2.三维变换
3维图像的变换与二维图像相似,将三维扩展为四维,然后左乘变换矩阵。有点烦的是旋转有点不同,由原来的绕原点旋转变成了绕坐标轴旋转。
通过推导可以看出对于绕y轴旋转是与绕x或者z轴旋转不同的,需要把上下两行倒过来从而变成
(
x
,
z
)
T
(x, z)^{T}
(x,z)T,所以三个旋转矩阵应该为:
绕原点任何角度的旋转都可以分解为绕三个轴的旋转,即
R
x
y
z
(
α
,
β
,
γ
)
R_{xyz}(α, β, γ)
Rxyz(α,β,γ) =
R
x
(
α
)
R
y
(
β
)
R
z
(
γ
)
R_{x}(α)R_{y}(β)R_{z}(γ)
Rx(α)Ry(β)Rz(γ),(α, β, γ)被称作欧拉角。
3.观测变换
3.1.视图变换(View/Camera transformation)
视图变换的目的就是将三维投影到二维。
什么是视图变换(MVP变换):
- 首先找到一个好地方摆好动作(模型变换 Model transformation:场景中每个物体上的某一点,从局部坐标系变换到世界坐标系,每个物体有自己独有的模型变换矩阵,代表物体独有的在世界坐标系中的位置。这一步的目的是将虚拟世界中或者具体点,游戏场景中的物体调整到他们应该在的位置。)
- 找个好的位置和角度摆好相机(视图变换 View transformation:设定照相机或者眼睛的位置,所有模型对于同一个照相机共用一个视图变换矩阵)
- 拍照(投影变换 Projection transformation:成像)
我们规定对相机做模型变换,物体随着相机一起变换直至相机变换至原点,相机是往-Z轴看的,头上沿+Y轴,右手系。如下图:
来推导一下变换矩阵,首先先将观测点平移至原点,然后再进行坐标轴的旋转,平移的矩阵很简单,对模型的点直接变换即可,将三个方向旋转到坐标轴的旋转矩阵比较复杂,但是我们可以先求逆矩阵即从坐标轴旋转到观测坐标系的旋转变换矩阵如下图。注意:旋转轴的时候是对向量来进行变换而不是对点进行变换。
该变换矩阵的一种证明方法是倒推,例如对于图中矩阵乘以向量
(
1
,
0
,
0
,
0
)
T
(1, 0, 0, 0)^{T}
(1,0,0,0)T可以得到向量
(
x
g
×
t
,
y
g
×
t
,
z
g
×
t
,
0
)
T
(x_{g×t}, y_{g×t}, z_{g×t}, 0)^{T}
(xg×t,yg×t,zg×t,0)T,即在g×t方向长度为1的向量,从而将x轴旋转至g×t的轴;另一种方法是直接推导如下图:
求出旋转矩阵 R v i e w − 1 R^{-1}_{view} Rview−1后求转置即为 R v i e w R_{view} Rview,因为旋转变换矩阵总是为正交矩阵,而正交矩阵的逆即为其转置。所以变换矩阵为 M v i e w = R v i e w T v i e w M_{view}=R_{view}T_{view} Mview=RviewTview,即先平移再旋转。
3.2.投影变换(Projection transformation)
3.2.1.正交投影(Orthographic Projection)
简单理解: 将相机放在原点,往-Z轴看,头朝+Y轴,然后丢弃Z轴,缩放变换到
[
−
1
,
1
]
2
[-1, 1]^{2}
[−1,1]2即为模型在XoY面上的正交投影。
做法: 将模型中心放在原点,将模型缩放到
[
−
1
,
1
]
3
[-1, 1]^{3}
[−1,1]3的单位立方体中(注意是先平移再缩放所以要先左乘平移变换矩阵)
特别的: 至于为什么是[-1, 1],这个是约定俗成规定的,记一下就好。
3.2.2 透视投影(Persective Projection)
- 对于透视投影,首先说一下视椎体的概念:
视锥体是一个三维体,视锥体的形状决定了模型如何从camera space投影到屏幕上。透视投影使用棱锥作为视锥体,摄像机位于棱锥的椎顶。该棱锥被前后两个平面截断,形成一个棱台,叫做View Frustum,只有位于Frustum内部的模型可见。为了防止物体离摄像机过近,设置近裁剪面(Front Clipping Plane)。同时为了防止物体离摄像机太远而不可见,设置远裁剪面(Back Clipping Plane)。在视锥体中,比近剪裁面更靠近摄像机的任何对象以及比远裁剪面更远离摄像机的任何对象都不会被渲染,任何落在图像视锥面之外的物体对摄像机而言均不可见。 - 透视投影的特点:近大远小、平行线不再平行,可能会出现交点。(道理我都懂,但是为什么鸽子这么大)
- 点表示方法的一个齐次特点:(x, y, z, 1), (kx, ky, kz, k) 均表示点(x, y, z)
所以我们怎样来做透视投影呢?(n面指near;f面指far)
透视投影做法:对于图中的视椎体近裁剪面作为n(near)面远裁剪面作为f面,首先先将该棱台挤压成
[
1
,
1
]
3
[1, 1]^{3}
[1,1]3的立方体,再对该立方体进行正交投影。关键点就是要去找这个挤压操作的变换矩阵。
先考虑模型的xoy面是怎么变换的:
通过相似可以得到
x
′
=
n
z
x
x^{'}=\frac{n}{z}x
x′=znx,
y
′
=
n
z
y
y^{'}=\frac{n}{z}y
y′=zny,进一步得到x和y的变换(先不考虑z的变换):
(
x
,
y
,
z
,
1
)
T
→
(
n
z
x
,
n
z
y
,
?
,
1
)
=
=
(
n
x
,
n
y
,
?
,
z
)
(x, y, z, 1)^{T}→(\frac{n}{z}x, \frac{n}{z}y, ?, 1)==(nx, ny, ?, z)
(x,y,z,1)T→(znx,zny,?,1)==(nx,ny,?,z)。其中z的变换暂时还未知,但可以推出这个投影矩阵的一部分(第四行不是(0, 0, 0, z)的原因是由于z为变量,而1是常量,这样设置可以减少计算机的开销):
下一步我们则去思考z是怎么变化的,有两个性质:
- 对于近裁剪面n面任何一个点的位置变化前后是不发生改变的
- 对于远裁剪面f面任何一个点的z值变化前后不发生改变并且中心位置的点x值和y值也是不发生改变的
利用第一个性质对于近裁剪面n面任何一个点的位置变化前后是不发生改变的可以得到
(
x
,
y
,
n
,
1
)
T
=
(
n
x
,
n
y
,
n
2
,
n
)
T
→
(
n
x
,
n
y
,
n
2
,
n
)
T
(x, y, n, 1)^{T}=(nx, ny, n^{2}, n)^{T}→(nx, ny, n^{2}, n)^{T}
(x,y,n,1)T=(nx,ny,n2,n)T→(nx,ny,n2,n)T,从而推出变换矩阵的第三行一定是(0, 0, A, B)型:
再利用第二个性质对于远裁剪面f面中点位置变化前后不发生改变可以得出第二个变换
(
0
,
0
,
f
,
1
)
T
=
(
0
,
0
,
f
2
,
f
)
T
→
(
0
,
0
,
f
2
,
f
)
T
(0, 0, f, 1)^{T}=(0, 0, f^{2}, f)^{T}→(0, 0, f^{2}, f)^{T}
(0,0,f,1)T=(0,0,f2,f)T→(0,0,f2,f)T,两个变换组成二元一次方程,解出A和B即得到变换矩阵的第三行:
最终得到
M
p
e
r
s
p
→
o
r
t
h
o
M_{persp→ortho}
Mpersp→ortho,但这还不算完,在将棱台形状的模型转化为正交模型后还要去进行一遍正交投影才算完成整个透视投影。
**一个问题:**视锥体中间的点在变换之后的 z 的变化是怎样的?