“为什么DirectX里表示三维坐标要建一个4*4的矩阵?”
前言
本文标题源自知乎上的同名问题:为什么DirectX里表示三维坐标要建一个4*4的矩阵? - 编程。正如Milo Yip大神所说,这个标题存在问题,矩阵的作用是表示变换,而非坐标。在了解矩阵的作用后,我们需要思考为何变换要使用4×4的矩阵,而非3×3的矩阵,这是否多此一举?下面我们来深入探讨这个话题。
怎么平移一个三维空间中的点
在三维空间中平移一个点,方法很简单,只需将该点坐标的每个分量(x, y, z)与对应轴上的平移距离相加。
例如,点p1(x1, y1, z1)在X轴、Y轴以及Z轴上分别平移Δx、Δy、Δz后到达新的点p2(x2, y2, z2),则可通过以下公式确定p2的坐标:
x2 = x1 + Δx
y2 = y1 + Δy
z2 = z1 + Δz
接下来,我们看看另一种变换:旋转。
再来旋转一个点
旋转相较于平移更为复杂,描述一个旋转需要明确以下几个方面:旋转轴、旋转方向和旋转角度。
这里假设点p需要绕Z轴顺时针旋转β度。
设点P1(x1, y1, z1)绕Z轴顺时针旋转β度后到达点P2(x2, y2, z2)。假设原点到P1的距离为L,且P1和Y轴之间的夹角为α,根据三角函数公式可得P1点的坐标:
x1 = L·sinα
y1 = L·cosα
由于是绕Z轴旋转,z坐标不变,暂不考虑。
同样根据三角函数公式,可计算出P2的坐标:
x2 = L·sin(α + β)
y2 = L·cos(α + β)
回忆中学几何数学中两角和与差的公式:
cos(α + β) = cosα·cosβ - sinα·sinβ
cos(α - β) = cosα·cosβ + sinα·sinβ
sin(α + β) = sinα·cosβ + cosα·sinβ
sin(α - β) = sinα·cosβ - cosα·sinβ
结合P1的坐标表示形式,可将P2的坐标变换形式:
x2 = L·(sinα·cosβ + cosα·sinβ) = cosβ·x1 + sinβ·y1
y2 = L·(cosα·cosβ - sinα·sinβ) = cosβ·y1 - sinβ·x1
z2 = z1
由此,已知P1点坐标和旋转角度β,就可根据上述公式求出P2点坐标的各个分量。结合上一小节平移点的公式,似乎不使用矩阵,仅通过两组表达式就能实现坐标变换。但实际情况并非如此简单。
带来便捷的矩阵
理论上,通过数学公式可以实现坐标变换。然而,当变换较为复杂时,直接使用数学表达式进行运算会非常繁琐。因此,在实际应用中,常使用矩阵(由m × n个标量组成的长方形数组)来表示平移、旋转和缩放等线性变换。
两个变换矩阵A和B的积P = AB,变换矩阵P相当于A和B所代表的变换。例如,若A为旋转矩阵,B为平移矩阵,则矩阵P可实现旋转和平移变换。需注意,矩阵乘法不符合交换律,即AB和BA不相等。
我们仍未解答为何三维空间需要4×4矩阵来实现变换,下面分别看看3×3矩阵和4×4矩阵的使用情况。
3×3矩阵和旋转
先看一个矩阵乘以三维矢量的算式,矩阵为3×3矩阵,右侧是点P1的坐标,左侧是点P2的坐标。根据表达式可求出x2、y2、z2的值:
x2 = a·x1 + b·y1 + c·z1
y2 = d·x1 + e·y1 + f·z1
z2 = g·x1 + h·y1 + i·z1
将旋转表达式与该矩阵等式对比:
x2 = a·x1 + b·y1 + c·z1
x2 = cosβ·x1 + sinβ·y1
y2 = d·x1 + e·y1 + f·z1
y2 = cosβ·y1 - sinβ·x1
z2 = g·x1 + h·y1 + i·z1
z2 = z1
通过对比可得:a = cosβ,b = sinβ,c = 0;d = -sinβ,e = cosβ,f = 0;g = 0,h = 0,i = 1。
这表明,通过这个3×3的变换矩阵,可实现三维空间的旋转变换。那为何还需要4×4矩阵呢?
搞不定的平移,4×4矩阵来救场
我们已用3×3矩阵实现了旋转变换,若它是完美的变换解决方案,应也适用于其他变换,如平移。下面通过对比矩阵等式和数学表达式来探究它是否能满足平移需求。
x2 = a·x1 + b·y1 + c·z1
x2 = x1 + Δx
y2 = d·x1 + e·y1 + f·z1
y2 = y1 + Δy
z2 = g·x1 + h·y1 + i·z1
z2 = z1 + Δz
对比发现,平移表达式中带有常量Δx,而旋转表达式和矩阵等式中都没有与之对应的常量。因此,无法用3×3矩阵表示平移,需使用4×4矩阵。但新问题随之而来,三维坐标如何与4×4矩阵相乘?
齐次坐标
为解决三维矢量和4×4矩阵相乘的问题,我们为三维矢量添加了第四个分量,使三维矢量(x, y, z)变为四维的(x, y, z, w),这种由4个分量组成的矢量称为齐次坐标。
齐次坐标(x, y, z, w)等价于三维坐标(x/w, y/w, z/w),当w分量的值为1时,该齐次坐标可当作三维坐标使用,其所表示的坐标就是以x、y、z为坐标值的点。
为与4×4矩阵相乘,P1点坐标变为(x1, y1, z1, 1),矩阵等式变为:
x2 = a·x1 + b·y1 + c·z1 + d
x2 = x1 + Δx
y2 = e·x1 + f·y1 + g·z1 + h
y2 = y1 + Δy
z2 = i·x1 + j·y1 + k·z1 + l
z2 = z1 + Δz
1 = m·x1 + n·y1 + o·z1 + p
通过对比可得:a = 1,b = 0,c = 0,d = Δx;e = 0,f = 1,g = 0,h = Δy;i = 0,j = 0,k = 1,l = Δz;m = 0,n = 0,o = 0,p = 1。
这样,我们就得到了4×4的平移矩阵。
总结
在介绍矩阵乘法时提到,两个变换矩阵A和B的积P = AB,相当于A和B所代表的变换。在游戏编程中,常需将一连串的变换预先计算为单一矩阵,因此不能同时存在3×3矩阵和4×4矩阵。将3×3矩阵拓展为4×4矩阵相对容易,通过一个4×4矩阵可整合平移矩阵和旋转矩阵。