【问题标题】:Arcball Rotation with Quaternions (using iOS GLKit)四元数的弧球旋转(使用 iOS GLKit)
【发布时间】:2012-12-14 01:49:54
【问题描述】:

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

我也一直在尝试理解 herehere 的源代码和数学。我可以旋转我的对象,但它总是以特定角度跳跃,所以我担心万向节锁定在起作用。我正在使用手势识别器来控制旋转(平移手势影响滚动和偏航,旋转手势影响俯仰)。我附上了用于四元数处理以及模型视图矩阵转换的代码。

变量:

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

【问题讨论】:

    标签: ios opengl-es quaternions glkit arcball


    【解决方案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 );
      

    【讨论】:

    • 绝妙的答案,效果很好。这是我第一次尝试四元数,因此非常感谢清晰的解释-谢谢!我已经编辑了我的问题以澄清您在 (1) 中提出的观点,尽管手势被命名为“pan”(iOS 约定),但它实际上确实控制了我的模型的旋转。
    【解决方案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));
    }
    

    希望你好好利用它:)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-02-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-22
      • 1970-01-01
      相关资源
      最近更新 更多