【问题标题】:Calculating a LookAt matrix计算 LookAt 矩阵
【发布时间】:2010-09-25 19:56:03
【问题描述】:

我正在编写一个 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

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

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

【问题讨论】:

标签: math graphics 3d projection


【解决方案1】:

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

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

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

[ 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 的行em> 是旧基向量的新基向量(因此变量名称 xaxis.x, .. xaxis 是发生基更改后的 x 轴)。然而,由于反转,行和列被调换了。

【讨论】:

  • 矩阵乘法不可交换。
  • 这是最好的答案,比目前公认的答案更有说服力。
  • 这意味着 LookAt 矩阵是正交基,否则转置将不等于它的逆矩阵,对吗?
  • @JohnLeidegren 是的,由于这个原因,旋转部分在构造上是正交的。
【解决方案2】:

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

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

【讨论】:

  • 您不应该通过计算相机方向的逆世界矩阵来创建视图矩阵吗?
  • @xcrypt 你的意思是相机的逆变换矩阵吗?
  • 如果我在这里错了,请纠正我,但您的描述似乎是 viewing 变换(即 view 矩阵),而 OP似乎正在显示 look-at 矩阵。有一次,我认为 viewlook-at 矩阵是相同的,但会被烧毁(代价高昂),现在我将它们视为 2 个不同的矩阵。这是错的吗? look-at 矩阵是否与 view matrix完全相同,只是构建方式不同?
  • @code_dredd LookAt() 函数有时会给出“世界矩阵”,它是“视图矩阵”的倒数。但由于求逆的代价非常高,最好 LookAt 已经返回了视图矩阵。
【解决方案3】:

只是一些一般信息:

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

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

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

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

【讨论】:

    【解决方案4】:

    该翻译组件通过创建orthonormal basis 来帮助您,其中您的“眼睛”位于原点,其他所有内容都以该原点(您的“眼睛”)和三个轴表示。

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

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

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

    【讨论】:

    • 所以根据我的理解,矩阵是用正确的翻译设置的,好吧,但是为什么计算中的点积呢?不能只是 -eye.x、-eye.y、-eye.z 吗?
    【解决方案5】:

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

    【讨论】:

      【解决方案6】:

      lookat 矩阵执行以下两个步骤:

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

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

      【讨论】:

        【解决方案7】:

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

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

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

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

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

        干杯

        【讨论】:

          【解决方案8】:

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

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

          【讨论】:

          • 什么是“轴空间”?我以前从未听说过这个词。你是说物体空间吗?直立空间?相机空间?
          猜你喜欢
          • 1970-01-01
          • 2015-09-11
          • 2019-10-28
          • 2013-01-29
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多