【问题标题】:Why does my camera rotate around a point with this math?为什么我的相机会绕着这个数学点旋转?
【发布时间】:2012-02-02 01:32:22
【问题描述】:

当我尝试改变方向时,我的相机会围绕一个点旋转。如果我在 Y 轴上旋转我的相机,例如 30 度,而不是相机向右看 30 度,相机围绕它正在看的点旋转。

o is the camera, A and B are 3D models. The lines show line-of-sight.
This is what I expect:
     A    B
     | > /
     |  /
     | /
     |/
     o

This is what actually happens:
     A    B
     |\
     | \
     |  \
     | > \
          o

现在,据我了解,为了移动相机,我必须将世界移动该数量的倒数。因此,如果我想在 Z 轴上移动 +1,我会在 Z 轴上平移世界 -1。因为我使用四元数来表示方向,所以我使用相机四元数的逆(因为方向始终是单位四元数,我通过使用共轭而不是计算逆来优化)将世界旋转适量。

这是我将四元数转换为矩阵的方法,其中 q 是反转的四元数:

[1 - 2 * (q.y * q.y + q.z * q.z)   2 * (q.x * q.y - q.w * q.z)       2 * (q.x * q.z + q.w * q.y)         0]
|2 * (q.x * q.y + q.w * q.z)       1 - 2 * (q.x * q.x + q.z * q.z)   2 * (q.y * q.z - q.w * q.x)         0|
|2 * (q.x * q.z - q.w * q.y)       2 * (q.y * q.z + q.w * q.z)       1 - 2 * (q.x * q.x + q.y * q.y)     0|
[0                                 0                                 0                                   1]

之后,我设置了矩阵的平移分量:

[...   ...   ...  -x]
|...   ...   ...  -y|
|...   ...   ...  -z|
[0     0     0     1]

最后我将它乘以模型视图矩阵堆栈,然后渲染我的所有对象。 我很确定这个数学是正确的,但它不会产生我期望的结果。显然,前向和右向向量是问题所在,所以我唯一的问题是为什么它们是错误的,如果我想得到我期望的结果,应该如何设置它们。谢谢。

编辑: 我从this guy's quaternion camera class 找到了解决方案。首先,我像以前一样构造一个旋转矩阵,然后我从第一列、第二列和第三列(分别为 xa、ya 和 za)获取矩阵的列向量。然后我像这样设置矩阵的平移分量:

[...  ...  ...  -xa.dotProduct(cameraPos)]
|...  ...  ...  -ya.dotProduct(cameraPos)|
|...  ...  ...  -za.dotProduct(cameraPos)|
[...  ...  ...  ...                      ]

然后可以将得到的矩阵乘以模型视图矩阵堆栈,并且可以完美地工作。

【问题讨论】:

  • 让您的编辑成为解决方案并接受它。这就是我们在此处标记已解决问题的方式。另外,我认为您应该对发生的事情进行一些解释。我会为此写一个答案。

标签: c++ opengl camera quaternions


【解决方案1】:

编辑:我从这个人的四元数相机课程中找到了解决方案。首先我构建一个 像我以前做的那样旋转矩阵,但后来我拿了专栏 来自第一列、第二列和第三列的矩阵向量 (xa, ya 和 za 分别)。然后我设置的平移分量 像这样的矩阵:

[...  ...  ...  -xa.dotProduct(cameraPos)]
|...  ...  ...  -ya.dotProduct(cameraPos)|
|...  ...  ...  -za.dotProduct(cameraPos)|
[...  ...  ...  ...                      ]

然后得到的矩阵可以乘到模型视图矩阵上 堆栈,它完美地工作。

是的,这正是我的建议,只是有点不同。你要明白,OpenGL没有摄像头,你只是把世界往相反的方向移动,所以你需要找到逆变换矩阵。

相机只是旋转和移动。这使事情变得非常简单。平移的逆向是符号相反的同一个向量,旋转矩阵的逆向是它的转置(列和行交换)。现在看看像 OpenGL 这样的齐次变换矩阵使用它们:

R t
0 1

左上3×3是旋转部分,最右列是平移向量。我想其余的你自己已经想好了。

【讨论】:

    【解决方案2】:

    说实话,试图找到一个矩阵来乘以模块视图矩阵确实很复杂并且很容易出错。有很多混乱和特殊情况。例如,如果您向上看 90 度,则您的两个轴变得相同。一个合乎逻辑的问题是:如果你向后滚动头,所以你通过顶点,你的向上向量应该是反转的,对吧?但是如果你错过了 0.0001 度呢?那么你应该把头转向那个点,这样你的向上向量仍然是向上的。

    在我看来,最好的方法是从另一个角度解决问题。让我们假设两种情况:

    • 不可能颠倒:
      • 为您的相机位置保留一个点,并为方向保留一个纬度/经度。和 简单的 sin/cos 运算就可以得到一个方向向量。你的向上向量是 (0, 1, 0)
      • 转弯只是改变经纬度
    • 可能颠倒:
      • 除了摄像头位置之外,还要保持向上和目标向量。
      • 转弯时,计算 right=target x up 然后将 target 更改为 x*right+y*up
      • 然后您需要对目标向量进行归一化并计算新的向量。很多案件要处理 不过。

    完成所有这些后,您只需致电gluLookAt

    【讨论】:

    • “老实说,试图找到一个矩阵来乘以模块视图矩阵真的很复杂,而且很容易出错。”不,这不对。矩阵是考虑相对坐标方向的最直接的方法。前 3 列中的每一列都是变换坐标系的基向量之一。第 4 列是相对翻译。从视图向量和目标向量中写下相机矩阵要容易得多,然后使用中间的所有三角函数。
    • 我知道。我要说的是,例如,如果您有 3 种不同类型的运动(例如,移动、扭转和滚动)直到下一帧,那么使用位置/纬度/经度并最终将其转换为矩阵要容易得多,而不是尝试将每个操作应用于前一个矩阵。
    猜你喜欢
    • 2013-09-04
    • 2010-09-22
    • 1970-01-01
    • 1970-01-01
    • 2013-09-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-01
    相关资源
    最近更新 更多