如何围绕目标点旋转摄像机?


18

我正在绘制一个场景,其中摄影机可以在宇宙中自由移动。相机类跟踪视图(或注视)点,相机的位置以及向上矢量。然后将这些向量/点传递到gluLookAt。

平移和缩放几乎不容易实现。然而,我发现围绕转动一下点要多得多的问题。我想编写一个函数Camera.rotate,它具有2个角度,一个可以向上/向下旋转,另一个可以沿视点为中心的假想球向左/向右旋转。

是否有捷径可寻?

我已经(简要地)阅读了有关四元数的信息,但是我想看看鉴于场景的构造相对简单,是否有更简单的解决方案。


给定轴和角度,工具箱中是否有任何东西可以围绕原点旋转点?
sam hocevar

除了我对四元数的松散理解,没有。我越关注这个问题,我认为四元数可能就是答案。但是,我不确定如何计算四元数公式中使用的 x,y和z值。
路加福音

我不会告诉你四元数不是要走的路。他们是您问题的很好解决方案。但是您将需要一个四元数类以及与GL和GLU进行交互的方式,并且我认为您应该首先尝试熟悉转换矩阵。其他人可能不同意。
sam hocevar

考虑旋转的顺序。将旋转应用于移动到世界空间或移动到相机空间的方式有所不同
Charlie

Answers:


25

您要的是称为Arcball旋转。只有了解四元数的工作原理,四元数才是简单的解决方案。但是,无需四元数就可以实现相同的目的。

先决条件

您知道一般如何旋转对象吗?假设您在原点有一个对象。您知道如何旋转吗(提示:乘以某个旋转矩阵)?如果是,那么我假设您知道如果先平移对象然后旋转它会发生什么?

您必须知道如何从角度轴计算旋转矩阵(像馅饼一样容易,在线查看无数个方程式,其中许多方程式也为您提供了代码)

  • 拿相机的向上向右向量。请注意,应将它们标准化。
  • 获取从焦点到摄像机的矢量(camPosition-Focus)。这是您将要旋转的向量。我们将此称为camFocusVector
  • 确定要相对于摄像机旋转的角度/俯仰角度
  • 创建两个旋转矩阵。第一个旋转矩阵将使用摄像机的上方作为您确定的轴和偏航角。第二旋转矩阵将使用摄像机的右侧作为您确定的轴和俯仰角。
  • 现在,使用新的旋转矩阵旋转camFocusVector。现在,这是摄像机相对于原点的新位置。我们当然希望它相对于焦点...
  • 将焦点位置添加到camFocusVector。现在这是相机的新位置。相应地翻译您的相机。
  • 最后,通过调用lookAt()函数让相机聚焦在对焦点上

注意事项

您必须注意相机会停止工作的某些情况或奇异之处。例如,向下看/向上看。我会让你弄清楚如何处理这些问题。

EDIT1:如何重新计算相机的正交向量

您已经知道了相机的方向((cameraPos-focusPoint).normalize())。现在,假设您的相机的上轴为+ Y(或者您的世界当前的上轴为...取决于您)。现在,只需穿过方向向上,以获得正确的。做完了吗 不!您的向上向量不再与其他两个正交。要解决此问题,请与方向保持正确的对接,然后开始进行安装

请注意,实际上应使用Gram-Schmidt对向量进行正态化。

再次注意一下警告,因为在某些情况下这将无法正常工作(例如,方向向上平行)。


注意,可以使用来获得右向量normalize(up ^ camFocusVector)(如果是左撇子,则可以使用右向量)。
sam hocevar

到目前为止看起来不错,可以很好地进行左右旋转(我有up矢量,所以很容易)。您的@SamHocevar评论中的'^'是什么意思?那是交叉产品吗?另外,完成翻译后,如何重新计算up向量?
路加福音

@Luke:检查我的EDIT1
Samaursa,2011年

1
@Samaursa非常感谢。您的解决方案运行完美,在此过程中我学到了很多东西!
路加福音

2
这是一个很好的答案,非常感谢您的解释。在我的情况下,我希望摄像机仅绕XY平面中的目标点旋转,因此在执行所有计算之后,我总是将cameraRight.z设置为0,然后计算cameraUp向量。这产生了期望的效果。只是想分享
-Codemonkey

1

您需要的是典型的ArcBall摄像机,该摄像机基本上是保留目标位置并允许您以“球形”方式围绕目标移动摄像机的摄像机。

它在XNA中,但是IIRC我以前使用过此实现,并且效果很好:

http://roy-t.nl/index.php/2010/02/21/xna-simple-arcballcamera/


该实现似乎只能直接沿着正确的载体,这将接近一个轨迹球对于较小的值移动。他还移动了LookAt点,就像我要移动相机的位置一样(很近,但略有不同)。我相信Samaursa提供了实现这一目标的最简单的完整方法。
路加福音

感谢您的反馈意见。我必须承认,我将此实现用作“黑盒”,但没有发现任何问题。为了澄清您是否在谈论MoveCameraRight / MoveCameraForward方法?这些方法是为了平移摄像机而添加的,但不是Arcball界面的一部分。如果要围绕目标旋转摄像机,只需更改“偏航”或“俯仰”属性。
David Gouveia

抱歉,您是对的,这些是平移方法。我没注意到当偏航和俯仰改变时,他如何为矩阵设置脏标志。
路加福音

0

这是我旋转某个点的代码,发现自己经常重复使用它。

float distance;      // Straight line distance between the camera and look at point

// Calculate the camera position using the distance and angles
float camX = distance * -sinf(camAngleX*(M_PI/180)) * cosf((camAngleY)*(M_PI/180));
float camY = distance * -sinf((camAngleY)*(M_PI/180));
float camZ = -distance * cosf((camAngleX)*(M_PI/180)) * cosf((camAngleY)*(M_PI/180));

// Set the camera position and lookat point
gluLookAt(camX,camY,camZ,   // Camera position
          0.0, 0.0, 0.0,    // Look at point
          0.0, 1.0, 0.0);   // Up vector

1
基本上这就是我最初做的方式。这样做有很多问题(至少对我而言)。基本上,此实现仅绕2个固定轴旋转。假设您几乎向上旋转到北极。然后向右旋转。你会发现自己纺在一个很小的圈子,而不是下面的摄像头的右侧矢量周围的一路全球
路加福音

既然您已经提到了这一点,我想有两种方法可以解决问题。在我的应用程序中,我使用ArcBall摄像机绕着海洋上的目标岛屿旋转,如果使用3个自由轴,它将看起来是错误的(例如,将岛屿倒置或侧向观看)。
David Gouveia

如何在这里获取摄像机角度?
rafvasq

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.