Arcball Rotation with Quaternions (using iOS GLKit)

纵饮孤独 提交于 2019-12-02 21:23:15

There seem to be a few issues going on here.

  1. You say that you're using [x,y] to pan, but it looks more like you're using them to pitch and yaw. To me, at least, panning is translation, not rotation.

  2. Unless I'm missing something, it also looks like your replacing the entire rotation everytime you try to update it. You rotate a vector by the inverse of the current rotation and then create a quaternion from that vector and some angle. I believe that this is equivalent to creating the quaternion from the original vector and then rotating it by the current rotation inverse. So you have q_e'*q_up. Then you multiply that with the current rotation, which gives q_e*q_e'*q_up = q_up. The current rotation is canceled out. This doesn't seem like it's what you want.

    All you really need to do is create a new quaternion from axis-and-angle and then multiply it with the current quaternion. If the new quaternion is on the left, the orientation change will use the eye-local frame. If the new quaternion is on the right, the orientation change will be in the global frame. I think you want:

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

    Do this, without the pre-rotation by inverse for all three cases.

  3. I've never used the GLKit, but it's uncommon to extract axis-angle when converting from Quaternion to Matrix. If the angle is zero, the axis is undefined. When it's near zero, you'll have numeric instability. It looks like you should be using GLKMatrix4MakeWithQuaternion and then multiplying the resulting matrix with your translation matrix and scale matrix:

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

I was recently asked a bit more about my resulting implementation of this problem, so here it is!

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

Hope you put it to good use :)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!