3D相机旋转


9

拜托,请原谅我,但我需要帮助,而我在这个问题上已经停留了几个星期,我没有取得任何进展,无论我走到哪里,我都会看到一个不同的答案,我尝试的所有方法都无法正常工作。我已经有了足够的技巧和建议,现在我真的只需要一个人给我答案,我就可以从此倒退,因为我不明白这一点。

使该主题最令人困惑的是每个人使用一组不同的约定或规则的方式,他们的答案基于他们自己的约定而没有定义它们的含义。

因此,这是我根据似乎最常见和合乎逻辑的内容形成的一组约定:

  1. 轴的右手法则。
  2. 正Y向上,正Z朝向观看者,正X朝向右侧。
  3. 行主矩阵,发送到着色器时转置。
    • 螺距:绕X轴旋转
    • 偏航:绕y轴旋转
    • 滚动:绕z轴旋转
  4. 轮换顺序:横摇,俯仰,偏航(这是正确的吗?有人可以对此进行检查吗?)
  5. 从轴的正端向下看,正旋转值会导致顺时针旋转。
  6. 沿所有轴旋转0的默认方向是向下指向负Y的向量。

..鉴于这些约定(如果它们约定不对,请务必纠正我!),如何做:

  • 写一个LookAt函数?(lookAt(矢量位置,矢量眼焦点,矢量向上))
  • 计算旋转矩阵。(旋转(x,y,z))

至少在过去的3周内,我尝试自己回答了这两个问题,我至少重写了LookAt&Rotation Matrix函数30次,测试了数十种方法,并通读了我所见过的材料。数百个网站,阅读了许多回答的问题,复制了别人的代码,到目前为止,我所做的一切都没有奏效,所有事情都产生了错误的结果。其中一些产生了一些非常怪异的输出,甚至没有接近正确的旋转。

除昨晚外,我每天晚上都在为此工作,因为我对反复的失败感到非常沮丧,不得不停下来休息一下。

拜托,请告诉我正确的方法是什么,以便我可以逆向工作并弄清楚它是如何工作的,我只是没有得到正确的答案,这使我有些疯狂!

我正在用Java编写,但是我会接受用任何语言编写的代码,我的大多数3D渲染代码实际上都运行得非常出色,这只是我无法理解的数学。

更新:已解决

感谢您的帮助!现在,我有了一个我真正理解的可以正常工作的LookAt函数,而且我再也高兴不起来了(如果有人想问一下,请问)。

我确实曾尝试过根据俯仰/偏航/侧倾变量创建旋转矩阵,但它似乎还是失败了,但是我决定放弃尝试将euler角用于freelook相机,因为它似乎不适合用于角色,而不是我要创建一个四元数类,沿着这条路径走运可能会更好,否则,我将诉诸于使用螺距/偏航作为球面坐标,并依靠新的工作LookAt函数进行旋转。

如果还有其他人遇到类似的问题并想问我问题,请随时。

至少我不会再受困了,谢谢您的帮助!

Answers:


15

您可以在这个很好的说明中找到所需的内容:http : //www.songho.ca/opengl/gl_transform.html

但是由于我没有手握就发现它有点混乱,因此我将尝试在此处进行解释。

此时,您需要考虑5个坐标系以及它们之间的关系。这些是窗口坐标,规范化的设备坐标,眼睛坐标,世界坐标和对象坐标。

窗口坐标可以看作是屏幕上的“物理”像素。它们是窗口系统所参考的坐标,如果您以显示器的原始分辨率进行操作,则它们实际上是单个像素。窗口坐标系是2D整数,并且是相对于窗口的。在此,x +左,y +向下,原点在左上角。例如,当您致电时,就会遇到这些问题glViewport

第二组是标准化的设备坐标。这些指的是通过活动视口设置的空间。视口的可见区域从-1到+1,因此原点位于中心。x +左,y +向上。您还可以使z +不在场景中。这就是您在1.中描述的内容。

您无法控制从标准化设备坐标到窗口坐标的方式,这是为您隐式完成的。您拥有的唯一控制权是通过glViewport或类似控制。

使用openGL时,最终结果将始终位于标准化的设备坐标中。结果,您需要担心如何在这些场景中渲染场景。如果将投影矩阵和模型视图矩阵设置为单位矩阵,则可以直接绘制这些坐标。例如,在应用全屏效果时可以完成此操作。

接下来是眼睛坐标。从相机上看这就是世界。结果,原点在相机中,并且像设备坐标一样应用了相同的轴坐标。

要从眼睛坐标到设备坐标,您需要构建投影矩阵。最简单的是正交投影,它可以适当地缩放值。透视图投影更为复杂,涉及模拟透视图。

终于有了世界坐标系。这是定义世界的坐标系,相机是该世界的一部分。在此重要的是要注意,轴方向与定义的方向相同。如果您更喜欢z +,那就完全可以了。

要从世界坐标转换为眼睛坐标,可以定义视图矩阵。可以使用lookAt。该矩阵的作用是“移动”整个世界,以便相机位于原点并向下看z轴。

要计算视图矩阵非常简单,您需要进行摄像机的转换。您基本上需要制定以下矩阵:

中号=X[1个]ÿ[1个]ž[1个]-p[1个]X[2]ÿ[2]ž[2]-p[2]X[3]ÿ[3]ž[3]-p[3]0001个

x,y和z向量可以直接从相机获取。从观察的情况下,您将从目标,眼睛(中心)和上限值派生它们。像这样:

ž=ñØ[R一个一世žËËÿË-Ť一个[RGËŤX=ñØ[R一个一世žËüpמÿ=žX

但是,如果您恰好拥有这些价值观,您可以直接采用它们。

获取p有点棘手。它不是世界坐标中的位置,而是相机坐标中的位置。一个简单的解决方法是初始化两个矩阵,一个矩阵仅包含x,y和z,第二个矩阵使用-eye并将它们相乘。结果是视图矩阵。

有关代码中的外观:

mat4 lookat(vec3 eye, vec3 target, vec3 up)
{
    vec3 zaxis = normalize(eye - target);    
    vec3 xaxis = normalize(cross(up, zaxis));
    vec3 yaxis = cross(zaxis, xaxis);     

    mat4 orientation(
       xaxis[0], yaxis[0], zaxis[0], 0,
       xaxis[1], yaxis[1], zaxis[1], 0,
       xaxis[2], yaxis[2], zaxis[2], 0,
         0,       0,       0,     1);

    mat4 translation(
              1,       0,       0, 0,
              0,       1,       0, 0, 
              0,       0,       1, 0,
        -eye[0], -eye[1], -eye[2], 1);

    return orientation * translation;
}

完整的代码

最后,为了完整起见,您还具有对象坐标系。这是存储网格的坐标系。借助模型矩阵,将网格坐标转换为世界坐标系。在实践中,模型和视图矩阵被组合到所谓的模型-视图矩阵中。


1
如果我能投票一百次,我会。感谢您提供彻底而完整的答案,以解决我所困惑的所有问题,并提供代码和链接!我整天都在阅读有关该主题的数学书籍,并提供您的答案以及示例代码和链接页面,如果这不足以让我弄清楚这一点,那么我现在应该退出。如果我只想澄清一下,在最后的代码示例中,我说这些矩阵按列优先顺序排列,而上面的矩阵按行优先排列,是否正确?
Grady 2014年

这有点令人困惑,矩阵是主列,但列在行中。因此,要将实际数学映射到代码,您需要对矩阵进行转置。参见github.com/rioki/glm/blob/master/src/matrix.h#l72这正好映射到openGL以及使用时的情况float[16]
rioki 2014年

啊,我确实是这么认为的,但是只是想确定一下,再次感谢!您提供了巨大的帮助,我非常感谢。
Grady 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.