这个答案可能比必要的内容更长。如果您已经理解了大部分矩阵数学,可以直接跳到最后两段。
从一维问题开始可能是最容易的。在一维中,我们有一条线上的点。我们可以缩放它们或平移它们。考虑三个点j,k和变换矩阵M。
M = [ s t ]
[ 0 1 ]
i = [1] j = [-2] k = [0]
[1] [ 1] [1]
j k i
─┴──┴──┴──┴──┴─
-2 -1 0 1 2
当我们乘以M时,我们得到:
i' = Mi = [ s t ][ 1] = [ s+t ]
[ 0 1 ][ 1] [ 1 ]
j' = Mj = [ s t ][-2] = [-2s+t]
[ 0 1 ][ 1] [ 1 ]
k' = Mk = [ s t ][ 0] = [ t ]
[ 0 1 ][ 1] [ 1 ]
如果我们给s和t赋值,那么我们就可以对我们的一维“三角形”进行各种变换。缩放会改变“点”之间的距离,而纯平移则会将它们相对于原点移动,同时保持间距不变:
s=1 t=0 s=2 t=1 s=1 t=2
j k i j k i j k i
─┴──┴──┴──┴──┴─ ─┴──┴──┴──┴──┴─ ─┴──┴──┴──┴──┴─
-2 -1 0 1 2 -3 -1 1 3 5 0 1 2 3 4
需要注意的是,变换的顺序至关重要。这些一维变换先进行缩放,然后再进行平移。如果您首先进行平移,则“点”与原点的距离将不同,因此缩放因子会对其产生不同的影响。出于这个原因,变换通常保持在单独的矩阵中,以便清楚地表明顺序。
如果我们升级到二维,则得到矩阵N:
[1 0 tx][ cos(a) sin(a) 0][sx 0 0] [ sx*cos(a) sx*sin(a) tx ]
N =[0 1 ty][-sin(a) cos(a) 0][ 0 sy 0]=[-sy*sin(a) sy*cos(a) ty ]
[0 0 1 ][ 0 0 1][ 0 0 1] [ 0 0 1 ]
这个矩阵将会
1)按
sx,sy缩放点,
2)将点绕原点旋转
a度,然后
3)将点平移
tx,ty。请注意,该矩阵是在假定点被表示为列向量的情况下构建的,并且乘法将以
Np进行。正如dantenwolf所说,如果您想使用点的行向量表示,但应用相同的变换,则可以转置所有内容并交换顺序。这是矩阵乘法的一般属性:
(AB)^T = (B^T)(A^T)。
话虽如此,我们可以根据对象、世界和眼睛坐标来谈论变换。如果眼睛坐落在世界原点上,朝向世界负z轴,+x向右,+y向上,物体是一个立方体,位于-z轴下10个单位(以z轴为中心),在世界x轴上宽度为2,在z轴上深度为3,在世界y轴上高度为4。然后,如果立方体的中心是对象的本地参考系,其本地轴与世界轴方便地对齐。那么盒子在对象坐标中的顶点是
[+/-1,+/-2,+/-1.5]^T
的变化。从眼睛的角度来看,近端、顶部、右侧的顶点具有
对象坐标[1,2,1.5]^T
,在
世界坐标中,同一顶点为
[1,2,-8.5]^T
(1.5-10=-8.5)。由于眼睛所处的位置、指向的方向以及我们将眼睛定义为OpenGL相同的方式,该顶点具有与
世界坐标相同的
眼睛坐标。因此,让我们移动和旋转眼睛,使得眼睛的
x为
right(rt),眼睛的
y为
up,眼睛的
-z为
look(lk),并且眼睛位于
[eyeright(ex) eyeup(ey) eyelook(ez)]^T
。因为我们希望将对象坐标转换为眼睛坐标(意味着我们将把眼睛视为原点),我们将取这些变换的逆,并将其应用于物体顶点(在它们被转换为世界坐标之后)。所以我们将有:
ep = [WORLD_TO_EYE]*[OBJECT_TO_WORLD]*wp
更具体地说,对于我们感兴趣的顶点,我们将会有:
[ rt.x rt.y rt.z 0][1 0 0 -ex][1 0 0 0 ][ 1 ]
[ up.x up.y up.z 0][0 1 0 -ey][0 1 0 0 ][ 2 ]
[-lk.x -lk.y -lk.z 0][0 0 1 -ez][0 0 1 -10][1.5]
[ 0 0 0 1][0 0 0 1 ][0 0 0 1 ][ 1 ]
为了方便起见,我已经将眼睛的旋转和翻译分开进行了翻译。实际上,现在我写了这么多,这可能是混淆的重点。您提供的矩阵将进行旋转,然后进行翻译。我假设眼睛的平移是在世界坐标中进行的。但正如您在问题中所写的那样,它实际上是在眼坐标中执行翻译。我还否定了lk,因为我们已经定义眼睛向下看负z轴,但为了制作标准的旋转矩阵,我们希望使用正值。
无论如何,我可以继续进行下去,但也许这已经回答了您的问题。
接着:
进一步解释上面的内容:将眼睛的变换拆分成两个组件也使其更容易找到逆变换。很容易看出,如果平移tx将眼睛相对于世界中的物体移动到某个位置,通过移动世界中的所有对象-tx并保持眼睛不动,我们可以保持眼睛和世界中点之间的相对位置不变。
同样地,考虑眼睛的方向,由其默认的right,up和look向量定义:
[1] [0] [ 0]
d_rt=[0] d_up=[1] d_lk=[ 0]
[0] [0] [-1]
创建一个旋转矩阵,使得这三个向量指向新方向很容易。 我们只需要把我们的三个新轴 rt、up、lk 对齐(作为列向量)即可。
[rt.x up.x -lk.x 0]
[rt.y up.y -lk.y 0]
[rt.z up.z -lk.z 0]
[ 0 0 0 1]
易见,如果增加d_rt、d_up和d_lk并乘以上述矩阵,则可以分别得到rt、up和lk。因此,我们已经应用了所需的变换。为了成为适当的旋转,这三个向量必须正交。这实际上只是一种基础变换。由于这个事实,我们可以通过取其转置来方便地找到该矩阵的逆。这就是我在上面所做的。如果将该转置矩阵应用于世界坐标中的所有点并保持眼睛静止,则这些点将保持相对于眼睛的同一位置,就像眼睛已经旋转了一样。
例如:
在世界坐标中进行分配:
[ 0] [0] [-1] [-2] [1.5]
rt=[ 0] up=[1] lk=[ 0] eye=[ 0] obj=[ 0 ]
[-1] [0] [ 0] [ 1] [-3 ]
![Simple camera/grid example](https://istack.dev59.com/m7c5o.webp)