计算机图形学:变换矩阵

最近在研究3D建模和新视点合成,在渲染过程中需要选取新视点去合成新图。一般在接口处需要传递一个变换矩阵,用于控制视点的变化。

成像的过程实质上是几个坐标系的转换。首先空间中的一点由世界坐标系转换到 摄像机坐标系 ,然后再将其投影到成像平面 ( 图像物理坐标系 ) ,最后再将成像平面上的数据转换到图像平面 (图像像素坐标系 ) 。

以AdaMPI的代码为例:

# 定义新视角的角度和渲染的帧数
def gen_swing_path(num_frames=90, r_x=0.14, r_y=0., r_z=0.10):
    "Return a list of matrix [4, 4]"
    t = torch.arange(num_frames) / (num_frames - 1)
    poses = torch.eye(4).repeat(num_frames, 1, 1)
    poses[:, 0, 3] = r_x * torch.sin(2. * math.pi * t)
    poses[:, 1, 3] = r_y * torch.cos(2. * math.pi * t)
    poses[:, 2, 3] = r_z * (torch.cos(2. * math.pi * t) - 1.)
    return poses.unbind()

以Synsin代码为例:

# Parameters for the transformation
theta = -0.15
phi = -0.1
tx = 0
ty = 0
tz = 0.1

RT = torch.eye(4).unsqueeze(0)
# Set up rotation(旋转参数)
RT[0,0:3,0:3] = torch.Tensor(quaternion.as_rotation_matrix(quaternion.from_rotation_vector([phi, theta, 0])))
# Set up translation(平移参数)
RT[0,0:3,3] = torch.Tensor([tx, ty, tz])

一开始其实没有明白为什么需要对 r_x=0.14, r_y=0., r_z=0.10 进行处理,处理成4*4的矩阵形式,而不是直接使用,后来查阅资料发现应该是涉及到计算机图形学的变换矩阵的范畴。

计算机图形学中3D的变换是基于转换矩阵( 仿射空间 )进行的。那么为什么是4维的矩阵而不是3维:用第四维度标识向量 or 点。

模型的变换可以认为是空间中一堆点的变换,三维空间中,(x,y,z)可以认为是点,也可以认为是一个向量,因此,人们引入的第4个维度来标识是点还是向量,这个4维空间就叫 仿射空间,,在仿射空间中,(x,y,z,0)标识向量,而(x,y,z,1)表示点。

在图形学中,在做平移,旋转和缩放时,经常会用到矩阵,有缩放矩阵、平移矩阵和旋转矩阵。在三维空间中,变换矩阵都是一个四维矩阵,每一行分别表示x, y, z, w。

1. 缩放矩阵(scale)

上面的公式,左边的第一个操作数(四维矩阵)就是一个缩放矩阵,s1表示x轴的缩放倍数,s2表示y轴的缩放倍数,s3表示z轴的缩放倍数。第二个操作数表示空间中(x, y, z)点, w分量在缩放矩阵中没有用到,我们将其设为1。由右边的结果,可以看出(x, y, z)点经过缩放矩阵变换后,x、y、z分量都各自缩放了s(s1、s2、s3)倍。需要注意的是矩阵的乘法不具有交换律,这里点是用一维列矩阵表示的,作为矩阵乘法的右操作数。如果将其转换到乘法的左边,那么点应该用一维行矩阵表示:

缩放矩阵比较简单,不需要证明,只需要会简单的乘法,就可以看出x,y,z经过缩放矩阵的变换确实被缩放了。

2.平移矩阵(translation)

平移矩阵也称位移矩阵,平移矩阵用到了第四列(w列),这也是为什么三维空间变换矩阵为什么是四维的。平移矩阵也比较容易理解,因为可以通过结果看出想x 、y、z确实各自平移了T步。

3. 旋转矩阵

旋转矩阵,相对难一些,也不是那么容易理解,我们先看最基础的绕x、y、z轴旋转的旋转矩阵。

沿x轴:

沿y轴:

沿z轴:

引入了三角函数,我们无法从结果看出旋转矩阵是否正确,所以我们需要证明。下面我给出沿z轴旋转的变换矩阵证明过程,其他轴同理可证。

image-20210521112417466

假设有如图的点p1,因为绕z轴旋转,点的z值是不变的,我们将其设为0,这样可以将其模拟成二维平面xy中旋转。假设p1绕原点旋转b角度,初始角度为a。整个证明过程如下:

// 经过旋转后向量的长度不变为L(原点到p1和p2的距离相同)
// 由三角函数得到sin(a + b), cos(a + b)的值
cos(a + b) = x2 / L;
sin(a + b) = y2 / L;

// 展开sin(a + b)和cos(a + b)
cos(a) * cos(b) - sin(a) * sin(b) = x2 / L;
sin(a) * cos(b) + cos(a) * sin(b) = y2 / L;

// 用x和y表示cos(a)和sin(a)
x / L * cos(b) - y / L * sin(b) = x2 / L;
y / L * cos(b) + x / L * sin(b) = y2 / L;

// 等式两边同时乘以L
x * cos(b) - y * sin(b) = x2;
y * cos(b) + x * sin(b) = y2;

将x2和y2的结果与上面z轴旋转矩阵结果比较,发现是完全一样的。

按照上面的方法同理可证绕x轴旋转和绕z轴旋转的矩阵。

那么绕任意轴旋转的矩阵呢?learnOpengl_cn官网直接给出了绕任意轴旋转的矩阵,(Rx, Ry, Rz)表示任意轴,θ表示旋转的矩阵。这个矩阵证明比较复杂。

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注