OpenGL同时平移并围绕局部轴旋转

时间:2012-04-28 22:15:05

标签: opengl

我正在开发一个在视口交互中具有与MotionBuilder类似功能的应用程序。它有三个按钮: 按钮1根据X / Y鼠标拖动围绕X和Y旋转视口。 按钮2根据X / Y鼠标拖动将视口转换为X和Y. 按钮3通过沿Z。

进行平移来“缩放”视口

代码很简单:

glTranslatef(posX,posY,posZ);
glRotatef(rotX, 1, 0, 0);
glRotatef(rotY, 0, 1, 0);   

现在,问题是如果我先翻译,翻译将是正确的,但旋转则遵循世界轴。我也试过先旋转:

glRotatef(rotX, 1, 0, 0);
glRotatef(rotY, 0, 1, 0);
glTranslatef(posX,posY,posZ);

^旋转工作,但翻译按世界轴工作。

我的问题是,我怎样才能同时执行这两项操作,以便从代码段1和代码片段2中完成转换。

EDIT 我画了这个相当粗糙的图像来说明我的意思是世界和当地的轮换/翻译。我需要相机旋转并围绕其局部轴平移。 http://i45.tinypic.com/2lnu3rs.jpg

3 个答案:

答案 0 :(得分:1)

好的,图像使事情更加清晰。

如果你只是在谈论一个对象,那么你的第一个代码片段会很好,但是对于相机来说它是完全不同的。

由于技术上没有对象作为opengl中的“相机”,因此在构建相机时所做的只是移动所有内容,而不是移动相机的方式。即你不要在Y轴上向上移动相机+1,你只需在y轴上移动世界-1,这样就可以获得相机的相同视觉效果。

想象一下,你有一个位置相机(Cx,Cy,Cz),它有x / y旋转角度(CRx,CRy)。如果这只是一个常规对象,而不是相机,你可以通过以下方式对其进行转换:

glTranslate(Cx, Cy, Cz);
glRotate(CRx, 1, 0, 0);
glRotate(CRy, 0, 1, 0);

但是因为这是相机,我们需要反过来操作(我们只想通过(-Cx,-Cy和-Cz)移动世界来模拟“相机”的移动。要反转矩阵,您只需要对每个变换执行相反的操作,并按相反的顺序执行。

glRotate(-CRy, 0, 1, 0); 
glRotate(-CRx, 1, 0, 0);
glTranslate(-Cx, -Cy, -Cz);

我认为这会为你提供你在图片中提到的那种相机。

答案 1 :(得分:1)

我建议你咬苹果并实现一个相机类,它存储相机的当前状态(位置,视图方向,向上矢量,右矢量)并根据您的控制方案操纵该状态。然后,您可以使用gluLookAt()设置投影矩阵。然后,操作的顺序变得不重要。这是一个例子:

让camPos成为相机的当前位置,cam查看其视图方向,凸显向上矢量并凸轮右侧矢量。

要通过moveDelta翻译相机,只需将moveDelta添加到camPos即可。旋转有点困难,但是如果你理解了四元数,你就能很快理解它。

首先,您需要为两个旋转中的每一个创建四元数。我假设您的水平旋转始终是正Z轴(如果您愿意,它指向“天花板”)。设hquat是表示水平旋转的四元数。我进一步假设您想要围绕其右轴旋转相机以进行垂直旋转(创建俯仰效果)。为此,您必须将水平旋转应用于相机的当前角度。结果是垂直旋转hQuat的旋转轴。那么总旋转四元数是rQuat = hQuat * vQuat。然后将rQuat应用于相机的视图方向,向上和向右矢量。

Quat hRot(rotX, 0, 0, 1);      // creates a quaternion that rotates by angle rotX about the positive Z axis
Vec3f vAxis = hRot * camRight; // applies hRot to the camera's right vector
Quat vRot(rotY, vAxis);        // creates a quaternion that rotates by angle rotY about the rotated camera's right vector
Quat rQuat = hRot * vRot;      // creates the total rotation
camUp = rQuat * camUp;
camRight = rQuat * camRight;
camView = rQuat * camView;

希望这可以帮助您解决问题。

答案 2 :(得分:0)

glRotate始终围绕原点工作。如果你这样做:

glPushMatrix();
glTranslated(x,y,z);
glRotated(theta,1,0,0);
glTranslated(-x,-y,-z);
drawObject();
glPopMatrix();

然后'对象'围绕(x,y,z)而不是原点旋转,因为你将(x,y,z)移动到原点,进行旋转,然后推(x,y,z) )回到它开始的地方。

但是,我认为这不足以获得你所描述的效果。如果您总是希望对当前参考帧进行转换,那么您需要自己跟踪转换矩阵。这就是为什么人们使用基于四元数的相机。