使用四元数的Arcball旋转(使用iOS GLKit)

我正在寻找一个四元数三维模型arcball旋转的简单实现, 特别是在iOS上使用GLKit 。 到目前为止,我已经检查了以下来源:

  • 使用GLKit进行Arcball旋转
  • 如何使用OpenGL触摸旋转3D对象

我也一直在尝试从这里和这里了解源代码和math。 我可以旋转我的物体,但是它一直在某个angular度跳跃,所以我担心万向节锁正在发挥作用。 我正在使用手势识别器来控制旋转(平移手势会影响滚动和偏航,旋转手势会影响音高)。 我附上我的四元数处理以及模型视图matrix转换的代码。

variables:

  • GLKQuaternion rotationE;

四元数处理:

 - (void)rotateWithXY:(float)x and:(float)y { const float rate = M_PI/360.0f; GLKVector3 up = GLKVector3Make(0.0f, 1.0f, 0.0f); GLKVector3 right = GLKVector3Make(1.0f, 0.0f, 0.0f); up = GLKQuaternionRotateVector3(GLKQuaternionInvert(self.rotationE), up); self.rotationE = GLKQuaternionMultiply(self.rotationE, GLKQuaternionMakeWithAngleAndVector3Axis(x*rate, up)); right = GLKQuaternionRotateVector3(GLKQuaternionInvert(self.rotationE), right); self.rotationE = GLKQuaternionMultiply(self.rotationE, GLKQuaternionMakeWithAngleAndVector3Axis(y*rate, right)); } - (void)rotateWithZ:(float)z { GLKVector3 front = GLKVector3Make(0.0f, 0.0f, -1.0f); front = GLKQuaternionRotateVector3(GLKQuaternionInvert(self.rotationE), front); self.rotationE = GLKQuaternionMultiply(self.rotationE, GLKQuaternionMakeWithAngleAndVector3Axis(z, front)); } 

Modelviewmatrix变换(内部绘制循环):

 // Get Quaternion Rotation GLKVector3 rAxis = GLKQuaternionAxis(self.transformations.rotationE); float rAngle = GLKQuaternionAngle(self.transformations.rotationE); // Set Modelview Matrix GLKMatrix4 modelviewMatrix = GLKMatrix4Identity; modelviewMatrix = GLKMatrix4MakeTranslation(0.0f, 0.0f, -0.55f); modelviewMatrix = GLKMatrix4Rotate(modelviewMatrix, rAngle, rAxis.x, rAxis.y, rAxis.z); modelviewMatrix = GLKMatrix4Scale(modelviewMatrix, 0.5f, 0.5f, 0.5f); glUniformMatrix4fv(self.sunShader.uModelviewMatrix, 1, 0, modelviewMatrix.m); 

任何帮助非常感谢,但我确实想保持尽可能简单,坚持GLKit。

似乎有几个问题在这里进行。

  1. 你说你正在用[x,y]来平移,但是看起来更像是你用它们来俯仰和偏航。 对我来说,至less,平移是翻译,而不是旋转。

  2. 除非我错过了某些东西,否则每次尝试更新时都会看起来像是replace了整个旋转。 通过当前旋转的逆向旋转vector,然后从该vector和某个angular度创build一个四元数。 我相信这相当于从原始vector创build四元数,然后通过当前的旋转反转来旋转它。 所以你有q_e'*q_up 。 然后你乘以当前的旋转,这给了q_e*q_e'*q_up = q_up 。 当前的旋转被取消。 这似乎不是你想要的。

    所有你真正需要做的是从轴和angular度创build一个新的四元数,然后乘以当前的四元数。 如果新的四元数在左侧,则方向改变将使用眼睛本地框架。 如果新的四元数在右侧,方向变化将在全局框架中。 我想你想要:

     self.rotationE = GLKQuaternionMultiply( GLKQuaternionMakeWithAngleAndVector3Axis(x*rate, up),self.rotationE); 

    做到这一点,没有所有三种情况下的反转预旋转。

  3. 我从来没有使用GLKit,但从四元数转换为matrix时,提取轴angular是不常见的。 如果angular度为零,则轴未定义。 当它接近零时,你会有数字不稳定。 看起来您应该使用GLKMatrix4MakeWithQuaternion ,然后将得到的matrix与您的转换matrix和缩放matrix相乘:

     GLKMatrix4 modelviewMatrix = GLKMatrix4Multiply( GLKMatrix4MakeTranslation(0.0f, 0.0f, -0.55f), GLKMatrix4MakeWithQuaternion( self.rotationE ) ); modelviewMatrix = GLKMatrix4Scale( modelviewMatrix, 0.5f, 0.5f, 0.5f ); 

最近我被问了一些关于这个问题的结果,所以在这里!

 - (void)rotate:(GLKVector3)r { // Convert degrees to radians for maths calculations rx = GLKMathDegreesToRadians(rx); ry = GLKMathDegreesToRadians(ry); rz = GLKMathDegreesToRadians(rz); // Axis Vectors w/ Direction (x=right, y=up, z=front) // In OpenGL, negative z values go "into" the screen. In GLKit, positive z values go "into" the screen. GLKVector3 right = GLKVector3Make(1.0f, 0.0f, 0.0f); GLKVector3 up = GLKVector3Make(0.0f, 1.0f, 0.0f); GLKVector3 front = GLKVector3Make(0.0f, 0.0f, 1.0f); // Quaternion w/ Angle and Vector // Positive angles are counter-clockwise, so convert to negative for a clockwise rotation GLKQuaternion q = GLKQuaternionIdentity; q = GLKQuaternionMultiply(GLKQuaternionMakeWithAngleAndVector3Axis(-rx, right), q); q = GLKQuaternionMultiply(GLKQuaternionMakeWithAngleAndVector3Axis(-ry, up), q); q = GLKQuaternionMultiply(GLKQuaternionMakeWithAngleAndVector3Axis(-rz, front), q); // ModelView Matrix GLKMatrix4 modelViewMatrix = GLKMatrix4Identity; modelViewMatrix = GLKMatrix4Multiply(modelViewMatrix, GLKMatrix4MakeWithQuaternion(q)); } 

希望你把它用好:)

Interesting Posts