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

Ric*_*eda 5 opengl-es quaternions arcball ios glkit

我正在寻找带有四元数的3D模型上的弧形旋转的简单实现,特别是在iOS上使用GLKit.到目前为止,我已经检查了以下来源:

我也一直试图从这里这里了解源代码和数学.我可以旋转我的物体,但它在某些角度不停跳跃,所以我担心万向节锁在起作用.我正在使用手势识别器来控制旋转(平移手势会影响滚动和偏航,旋转手势会影响音高).我将附加我的代码用于四元数处理以及模型视图矩阵转换.

变量:

  • 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));
}
Run Code Online (Sandbox Code Playgroud)

模型视图矩阵变换(内部绘制循环):

// 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);
Run Code Online (Sandbox Code Playgroud)

非常感谢任何帮助,但我确实希望尽可能简单并坚持使用GLKit.

JCo*_*per 6

这里似乎有一些问题.

  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);
    
    Run Code Online (Sandbox Code Playgroud)

    这样做,没有对所有三种情况进行反向预旋转.

  3. 我从未使用过GLKit,但是从Quaternion转换为Matrix时提取轴角度并不常见.如果角度为零,则轴未定义.当它接近零时,你将有数字不稳定.看起来你应该使用GLKMatrix4MakeWithQuaternion然后将得到的矩阵与你的平移矩阵和比例矩阵相乘:

    GLKMatrix4 modelviewMatrix = 
      GLKMatrix4Multiply( GLKMatrix4MakeTranslation(0.0f, 0.0f, -0.55f),
                          GLKMatrix4MakeWithQuaternion( self.rotationE ) );
    modelviewMatrix = GLKMatrix4Scale( modelviewMatrix, 0.5f, 0.5f, 0.5f );
    
    Run Code Online (Sandbox Code Playgroud)