在某个角度跳跃旋转(或万向节锁定)的问题

时间:2014-12-30 12:45:22

标签: ios rotation quaternions scenekit

我将设备的旋转捕获为不发生旋转的静止点。用户倾斜ipad / iphone后,我检查新角度以5度为增量左右旋转。在某些时候,我看到旋转的“跳跃”或万向节锁定。在跳跃发生之前,跳跃发生的速度比往常慢。也许我没有正确地规范化矢量或四元数。如何在没有万向锁的情况下实现流畅的动画?

-(void) awakeFromNib
{
  tmp = GLKQuaternionIdentity;
  self.motionManager = [[CMMotionManager alloc] init];
  self.motionManager.deviceMotionUpdateInterval = 1.0/60.0;

  [self.motionManager startDeviceMotionUpdatesToQueue:[NSOperationQueue currentQueue] withHandler:^(CMDeviceMotion *motion, NSError *error) {
      if (error == nil && onceSampled == NO)
      {
             onceSampled = YES;
             roll = GLKMathRadiansToDegrees(atan2(2*(startingQuaternion.y*startingQuaternion.w - startingQuaternion.x*startingQuaternion.z), 1 - 2*startingQuaternion.y*startingQuaternion.y - 2*startingQuaternion.z*startingQuaternion.z)) ;
             pitch = GLKMathRadiansToDegrees(atan2(2*(startingQuaternion.x*startingQuaternion.w + startingQuaternion.y*startingQuaternion.z), 1 - 2*startingQuaternion.x*startingQuaternion.x - 2*startingQuaternion.z*startingQuaternion.z));
             yaw = GLKMathRadiansToDegrees(asin(2*startingQuaternion.x*startingQuaternion.y + 2*startingQuaternion.w*startingQuaternion.z));
      }
   }];
}

- (void)renderer:(id<SCNSceneRenderer>)aRenderer didSimulatePhysicsAtTime:(NSTimeInterval)time
{
   tmp.x = self.motionManager.deviceMotion.attitude.quaternion.x ;
   tmp.y = self.motionManager.deviceMotion.attitude.quaternion.y ;
   tmp.z = self.motionManager.deviceMotion.attitude.quaternion.z ;
   tmp.w = self.motionManager.deviceMotion.attitude.quaternion.w;

   double myRoll = GLKMathRadiansToDegrees(atan2(2*(tmp.y*tmp.w - tmp.x*tmp.z), 1 - 2*tmp.y*tmp.y - 2*tmp.z*tmp.z)) ;
   double myPitch = GLKMathRadiansToDegrees(atan2(2*(tmp.x*tmp.w + tmp.y*tmp.z), 1 - 2*tmp.x*tmp.x - 2*tmp.z*tmp.z));
   double myYaw = GLKMathRadiansToDegrees(asin(2*tmp.x*tmp.y + 2*tmp.w*tmp.z));

   SCNQuaternion oldRotScnQuat = _cameraNode.presentationNode.rotation;
   GLKQuaternion glQuatOldRot = GLKQuaternionMakeWithAngleAndAxis(oldRotScnQuat.w, oldRotScnQuat.x, oldRotScnQuat.y, oldRotScnQuat.z);

   GLKQuaternion netRotY = GLKQuaternionIdentity;

   if(myPitch >= pitch + 1 || myPitch <= pitch - 1)
    {
        int dir = myPitch > pitch ? 1: -1;
        GLKVector3 vec = GLKVector3Normalize(GLKVector3Make(0, dir, 0));
        netRotY = GLKQuaternionMakeWithAngleAndAxis(GLKMathDegreesToRadians(5), vec.x, vec.y , vec.z);
    }
    glQuatOldRot = GLKQuaternionMultiply(glQuatOldRot, netRotY);
    axis = GLKQuaternionAxis(glQuatOldRot);
    angle = GLKQuaternionAngle(glQuatOldRot);

    [_cameraNode runAction:[SCNAction rotateToAxisAngle:SCNVector4Make(axis.x, axis.y, axis.z, angle) duration:1.2]];
}

编辑:实际上,如果设备从静止点向左/向右或向上/向下倾斜,我想同时在X和Y上旋转。如果有人能够解释它会很棒。

编辑:我一直在努力让这个工作。当我阅读有关四元数的更多信息时,我发现我在创建四元数时犯了一个错误。我想,正确的方法应该是:

if(myPitch >= pitch + 1 || myPitch <= pitch - 1)
 {
   int angle = myPitch > pitch ? 5: -5; // left or right tilt
   GLKVector3 vec = GLKVector3Normalize(GLKVector3Make(0, 1, 0));//rotate on y-axis (-1) is wrong
   double result = sinf(GLKMathDegreesToRadians(angle)/2);
   netRotY = GLKQuaternionMakeWithAngleAndAxis(cosf(GLKMathDegreesToRadians(angle)/2), vec.x *result, vec.y * result, vec.z * result);
   netRotY = GLKQuaternionNormalize(netRotY);
  }

其余代码仍然如上所示,但我仍然看到轮换故障。

1 个答案:

答案 0 :(得分:0)

经过长时间的测试和观察,我发现没有万向节锁定。我编辑的计算是正确的:

if(myPitch >= pitch + 1 || myPitch <= pitch - 1)
 {
   int angle = myPitch > pitch ? 5: -5; // left or right tilt
   GLKVector3 vec = GLKVector3Normalize(GLKVector3Make(0, 1, 0));//rotate on y-axis (-1) is wrong
   double result = sinf(GLKMathDegreesToRadians(angle)/2);
   netRotY = GLKQuaternionMakeWithAngleAndAxis(cosf(GLKMathDegreesToRadians(angle)/2), vec.x *result, vec.y * result, vec.z * result);
   netRotY = GLKQuaternionNormalize(netRotY);
  }

问题是动画链和持续时间,我不得不在新问题中提出。