四元数的Arcball旋转(使用iOS GLKit) [英] Arcball Rotation with Quaternions (using iOS GLKit)

查看:307
本文介绍了四元数的Arcball旋转(使用iOS GLKit)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm looking for a simple implementation for arcball rotation on 3D models with quaternions, specifically using GLKit on iOS. So far, I have examined the following sources:

  • Arcball rotation with GLKit
  • How to rotate a 3D object with touches using OpenGL

我也一直试图从此处此处.我可以旋转我的物体,但它会一直以一定角度跳动,所以我担心云台锁定装置在起作用.我正在使用手势识别器来控制旋转(平移手势会影响滚动和偏航,旋转手势会影响音高).我将为四元数处理以及模型视图矩阵转换附加代码.

I've also been trying to understand source code and maths from here and here. I can rotate my object but it keeps jumping around at certain angles, so I fear gimbal lock is at play. I'm using gesture recognizers to control the rotations (pan gestures affect roll and yaw, rotate gestures affect pitch). I'm attaching my code for the quaternion handling as well as the modelview matrix transformation.

变量:

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

Modelview矩阵变换(内部绘制循环):

Modelview Matrix Transformation (Inside Draw Loop):

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

Any help is greatly appreciated, but I do want to keep it as simple as possible and stick to GLKit.

推荐答案

这里似乎存在一些问题.

There seem to be a few issues going on here.

  1. 您说您正在使用[x,y]平移,但看起来更像是您在使用它们进行俯仰和偏航.至少对我而言,平移是平移,而不是旋转.

  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.

除非我丢失了某些内容,否则每次您尝试更新轮换时,它看起来都像是替换了整个轮换.将向量旋转为当前旋转的反方向,然后从该向量和某个角度创建一个四元数.我相信这等效于从原始向量创建四元数,然后通过当前旋转逆数对其进行旋转.所以你有q_e'*q_up.然后,将其乘以当前旋转,得到q_e*q_e'*q_up = q_up.当前旋转被抵消.看来这不是您想要的.

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.

我从没使用过GLKit,但是从四元数转换为矩阵时提取轴角度并不常见.如果角度为零,则轴未定义.当它接近零时,您将遇到数值不稳定的情况.看来您应该使用GLKMatrix4MakeWithQuaternion,然后将结果矩阵与平移矩阵和比例矩阵相乘:

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

这篇关于四元数的Arcball旋转(使用iOS GLKit)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆