轨迹球旋转与四元(使用的是iOS GLKit)(Arcball Rotation with Quat

2019-08-04 23:52发布

我在寻找一个简单的实施对3D模型轨迹球旋转与四元数, 特别是使用iOS上的GLKit。 到目前为止,我已经研究了以下资料:

  • 与GLKit轨迹球旋转
  • 如何旋转与使用OpenGL触摸3D对象

我也一直在试图理解源代码和数学从这里和这里 。 我可以旋转我的对象,但它保持在一定的角度跳来跳去,所以我担心万向节锁定在作怪。 我用手势识别来控制旋转(全景手势影响滚转和偏航,旋转手势影响间距)。 我安装我的四元数处理代码以及模型视图矩阵变换。

变量:

  • 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));
}

模型变换矩阵变换(内部引出环路):

// 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。

Answer 1:

似乎有这里发生了一些问题。

  1. 你说你正在使用[X,Y]平移,但它看起来更像你使用他们俯仰和偏航。 对我来说,至少,平移是翻译,不是旋转。

  2. 除非我失去了一些东西,它也看起来像你更换整个旋转每次你尝试更新它。 您旋转当前旋转的逆矢量,然后创建从矢量和一些角四元数。 我认为,这是相当于创建从原来的矢量四元数,然后由当前旋转反旋转它。 所以,你必须q_e'*q_up 。 然后,你乘上与当前的旋转,这使q_e*q_e'*q_up = q_up 。 当前的旋转抵消。 这似乎并不像它就是你想要的。

    你真正需要做的是创建轴和倾斜角的新的四元数,然后与当前四元数相乘。 如果新的四元数是在左边,方位的变化将用眼局部框架。 如果新的四元数在右边,方位的变化将是在全球框架。 我想你想:

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

    做到这一点,没有预先旋转通过逆为所有三种情况。

  3. 我从来没有使用GLKit,而是把从四元数矩阵时,它的罕见提取轴角。 如果角度为零,则轴是未定义的。 当它接近零,你就会有数值不稳定。 它看起来像你应该使用GLKMatrix4MakeWithQuaternion ,然后用你的翻译矩阵和规模矩阵产生的矩阵相乘:

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


Answer 2:

最近,我问多一点对我产生这个问题的实现,所以在这里它是!

- (void)rotate:(GLKVector3)r
{
    // Convert degrees to radians for maths calculations
    r.x = GLKMathDegreesToRadians(r.x);
    r.y = GLKMathDegreesToRadians(r.y);
    r.z = GLKMathDegreesToRadians(r.z);

    // 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(-r.x, right), q);
    q = GLKQuaternionMultiply(GLKQuaternionMakeWithAngleAndVector3Axis(-r.y, up), q);
    q = GLKQuaternionMultiply(GLKQuaternionMakeWithAngleAndVector3Axis(-r.z, front), q);

    // ModelView Matrix
    GLKMatrix4 modelViewMatrix = GLKMatrix4Identity;
    modelViewMatrix = GLKMatrix4Multiply(modelViewMatrix, GLKMatrix4MakeWithQuaternion(q));
}

希望你把它用好:)



文章来源: Arcball Rotation with Quaternions (using iOS GLKit)