46

我正在编写一个 3d 引擎,并且遇到了 DirectX 文档中描述的 LookAt 算法:

zaxis = normal(At - Eye)
xaxis = normal(cross(Up, zaxis))
yaxis = cross(zaxis, xaxis)

 xaxis.x           yaxis.x           zaxis.x          0
 xaxis.y           yaxis.y           zaxis.y          0
 xaxis.z           yaxis.z           zaxis.z          0
-dot(xaxis, eye)  -dot(yaxis, eye)  -dot(zaxis, eye)  1

现在我明白了它在旋转方面的工作原理,但我不太明白为什么它将矩阵的平移分量放在那些点积上。稍微检查一下,它似乎是根据新基向量在眼睛/相机位置上的投影来少量调整相机位置。

问题是为什么需要这样做?它有什么作用?

4

8 回答 8

64

请注意,给出的示例是左手行主矩阵

所以操作是:先平移到原点(通过 - eye移动),然后旋转,使eyeAt的向量与 +z 对齐:

如果您将旋转矩阵预乘以平移 -眼睛,基本上您会得到相同的结果:

[ 1 0 0 0 ] [ xaxis.x yaxis.x zaxis.x 0 ]
[ 0 1 0 0 ] * [ xaxis.y yaxis.y zaxis.y 0 ]
[ 0 0 1 0 ] [ xaxis.z yaxis.z zaxis.z 0 ]
[ -eye.x -eye.y -eye.z 1 ] [ 0 0 0 1 ]

  [ xaxis.x yaxis.x zaxis.x 0 ]
= [ xaxis.y yaxis.y zaxis.y 0 ]
  [ xaxis.z yaxis.z zaxis.z 0 ]
  [ 点(xaxis,-eye) 点(yaxis,-eye) 点(zaxis,-eye) 1 ]

补充笔记:

请注意,查看转换是(有意)反转的:您将每个顶点乘以该矩阵以“移动世界”,以便您想要查看的部分最终出现在规范视图体积中。

另请注意,LookAt 矩阵的旋转矩阵(称为R)分量是基矩阵的反向变化,其中R的行是旧基向量的新基向量(因此变量名称 xaxis.x, . . xaxis 是基础发生变化后新的 x 轴)。然而,由于反转,行和列被转置。

于 2011-07-23T18:29:03.140 回答
19

我通过创建一个 3x3 旋转矩阵来构建一个查看矩阵,就像您在此处所做的那样,然后将其扩展为一个 4x4,其中包含零和右下角的单个 1。然后我使用负眼点坐标(无点积)构建一个 4x4 平移矩阵,并将两个矩阵相乘。我的猜测是,这种乘法产生的结果相当于你的示例底行中的点积,但我需要在纸上解决它才能确定。

3D 旋转会改变您的坐标轴。因此,您不能直接使用眼点而不将其转换到这个新的坐标系中。这就是矩阵乘法——或者在本例中是 3 个点积值——完成的任务。

于 2008-12-09T14:44:53.663 回答
4

该平移组件通过在原点处创建“眼睛”以及以该原点(您的“眼睛”)和三个轴表示的所有其他内容来帮助您创建正交基础。

这个概念并不是矩阵正在调整相机位置。相反,它试图简化数学运算:当您想要渲染从“眼睛”位置可以看到的所有事物的图片时,最容易假装您的眼睛是宇宙的中心。

因此,简短的回答是,这使数学变得更容易。

回答评论中的问题:您不只是从所有内容中减去“眼睛”位置的原因与操作的顺序有关。可以这样想:一旦你处于新的参考系(即,由 xaxis、yaxis 和 zaxis 表示的头部位置)中,你现在想要根据这个新的(旋转的)参考系来表达距离。这就是为什么您使用新轴的点积与眼睛位置:这表示物体需要移动的相同距离,但它使用新坐标系。

于 2008-12-08T14:28:29.717 回答
4

只是一些一般信息:

观察矩阵是一个矩阵,它定位/旋转某些东西以从空间中的另一个点指向(查看)空间中的一个点。

该方法采用相机视图的所需“中心”,一个“向上”向量,它表示相机的“向上”方向(向上几乎总是(0,1,0),但不一定是),以及一个“眼睛”向量,它是相机的位置。

这主要用于相机,但也可用于其他技术,如阴影、聚光灯等。

坦率地说,我不完全确定为什么在这种方法中设置翻译组件。在gluLookAt(来自 OpenGL)中,平移分量设置为 0,0,0,因为相机始终被视为位于 0,0,0。

于 2008-12-09T17:44:23.003 回答
2

点积只是将一个点投影到轴上,以获得眼睛的 x、y 或 z 分量。您正在向后移动相机,因此从 (10, 0, 0) 和 (100000, 0, 0) 看 (0, 0, 0) 会产生不同的效果。

于 2008-12-08T10:12:45.990 回答
2

观察矩阵执行以下两个步骤:

  1. 将您的模型翻译为原点,
  2. 根据向上矢量和观察
    方向设置的方向旋转它。

点积只是意味着您先进行平移,然后再进行旋转。点积不是将两个矩阵相乘,而是将一行与一列相乘。

于 2008-12-09T17:50:38.420 回答
1

一个 4x4 变换矩阵包含两到三个分量:1. 旋转矩阵 2. 平移添加。3.规模(很多引擎不直接在矩阵中使用这个)。

它们的组合会将一个点从空间 A 变换到空间 B,因此这是一个变换矩阵 M_ab

现在,相机的位置在空间 A 中,因此它不是空间 B 的有效变换,因此您需要将此位置与旋转变换相乘。

唯一的悬而未决的问题是为什么这些点?好吧,如果你将这 3 个点写在纸上,你会发现 X、Y 和 Z 的 3 个点与旋转矩阵的乘法完全一样。

第四行/列的一个例子是在世界空间中取零点 - (0,0,0)。它不是相机空间中的零点,因此您需要知道相机空间中的表示是什么,因为旋转和缩放使其为零!

干杯

于 2009-02-15T07:25:36.637 回答
0

有必要将眼点放在您的轴空间中,而不是在世界空间中。当您用坐标单位基向量(x、y、z 之一)点一个向量时,它会为您提供空间中眼睛的坐标。您可以通过在最后一个位置(在本例中为最后一行)应用三个翻译来转换位置。然后用负数向后移动眼睛,相当于向前移动所有其余空间。就像在电梯里向上移动一样,你会觉得世界其他地方都从你的脚下掉了下来。

使用左手矩阵,将平移作为最后一行而不是最后一列,是一种宗教差异,与答案完全无关。然而,这是一个应该严格避免的教条。在绘制树形草图时,最好以自然的阅读顺序从左到右链接全局到局部(正向运动学)变换。使用左手矩阵会迫使您从右到左编写这些矩阵。

于 2014-04-24T01:10:39.193 回答