продолжайте вращать узел сцены, пока устройство не вернется в исходное положение

экспериментируя с набором сцен, я использую self.motionManager.deviceMotion.attitude.quaternion для поворота узла сцены (камеры) в 3D-сцене. Допустим, пользователь запускает приложение, а устройство каким-то образом наклонено, поэтому эта начальная ориентация должна считаться точкой покоя, и в этом положении не должно происходить вращения. когда пользователь наклоняет устройство (влево ‹--› вправо и / или вверх ‹--› вниз), оно должно постепенно поворачиваться, пока пользователь не вернет устройство в исходную / исходную ориентацию, при которой вращения не произойдет. Согласно этому ответу я знаю, как фильтровать шум и случайное покачивание

эти следующие моменты важны:

  1. иметь ориентацию в состоянии покоя, при которой вращения не происходит
  2. когда устройство наклонено, затем поворачивайте постепенно
  3. при достижении вышеуказанных пунктов пользователю не нужно переворачивать устройство, чтобы получить полное вращение :-)

Я понятия не имею, как этого добиться. любая помощь приветствуется.

изменить: добавление кода, пытающегося реализовать ответ Рикстера

Мне нужно получить значения крена, рыскания, тангажа в startDeviceMotionUpdatesToQueue:withHandler:, иначе все равно нулю

-(void) awakeFromNib
{
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)
    {
        if (firstValue == NO)
        {
           firstValue = YES;
           yaw = self.motionManager.deviceMotion.attitude.yaw;
           roll = self.motionManager.deviceMotion.attitude.roll;
           pitch = self.motionManager.deviceMotion.attitude.pitch;
        }
    }
}];
}

Я пытаюсь сначала повернуть по оси x на 5 градусов для простоты:

- (void)renderer:(id<SCNSceneRenderer>)aRenderer didSimulatePhysicsAtTime:(NSTimeInterval)time
{
    currentYaw = self.motionManager.deviceMotion.attitude.yaw;
    currentRoll = self.motionManager.deviceMotion.attitude.roll;
    currentPitch = self.motionManager.deviceMotion.attitude.pitch;
    SCNVector4 q =_cameraNode.presentationNode.rotation;
  float phi = atan((2*(q.x*q.y + q.z*q.w))/(1-2*(pow(q.y,2)*pow(q.z,2))));
  if (currentRoll > 0)
  {
    [_cameraNode runAction:[SCNAction rotateToAxisAngle:SCNVector4Make(1, 0, 0, ( phi + DEGREES_TO_RADIANS(5))) duration:1]];
  }
  else if(currentRoll < 0 )
  {
    [_cameraNode runAction:[SCNAction rotateToAxisAngle:SCNVector4Make(1, 0, 0, (phi - DEGREES_TO_RADIANS(5))) duration:1]];
  }

}

вывод отладки для переменных:

отладка: q = (x = 0,999998092, y = 0, z = 0, w = -0,0872662216)

phi = 0

currentRoll = -1,1897298305515105

на самом деле он вообще не вращается. значение phi выглядит не очень хорошо. Что я делаю неправильно?

примечание: как сделать вращение сразу для всех осей? умножить кватернион oldRotation на x, затем на y, затем на z? это правильный порядок?


person Hashmat Khalil    schedule 28.12.2014    source источник
comment
просто хочу отметить, что ротация в приведенном выше коде очень ошибочна.   -  person Hashmat Khalil    schedule 30.12.2014


Ответы (1)


Чтобы отслеживать ориентацию в состоянии покоя, вам необходимо отслеживать первый CMAttitude образец. Затем вы можете использовать multiplyByInverseOfAttitude:, чтобы получать разницу между этим отношением и текущим каждый раз, когда вы сэмплируете. (Если вы уже работаете с кватернионами из-за фильтрации, вы можете выполнить эквивалентную операцию с GLKQuaternionInvert и GLKQuaternionMultiply.)

Чтобы выполнить инкрементное вращение, о котором вы говорите, может быть проще всего использовать углы Эйлера - относительно разницы в положении, которое вы только что обнаружили, так что нулевой поворот означает отсутствие изменений по сравнению с нейтральной ориентацией, в которой начал пользователь (независимо от о том, что это за ориентация, - это абсолютные термины). Затем, когда угол поворота положительный в течение заданного временного шага (например, в вашем методе обновления SCNSceneRendererDelegate), вы можете увеличить поворот узла камеры, и наоборот.

Фактически, если вы выполняете инкрементное вращение таким образом, вам может не понадобиться шаг фильтрации (из моего другого ответа, на который вы ссылались). Вместо этого вы, вероятно, сможете обойтись без грубого ввода отношения и порога. Например, увеличивайте крен узла только тогда, когда крен относительно положения больше 5 градусов. В этом случае вы можете просто получить углы Эйлера из CMAttitude (отличное отношение от ранее в этом ответе) и не беспокоиться об извлечении углов Эйлера из кватерниона самостоятельно (не то чтобы это так сложно).

person rickster    schedule 28.12.2014
comment
Я как бы ожидал, что вы ответите на мой вопрос :-) Я собираюсь реализовать это согласно вашему предложению с углом Эйлера. У меня могут быть дополнительные вопросы. Спасибо большое. - person Hashmat Khalil; 28.12.2014
comment
Я добавил код и уточняющий вопрос. Не могли бы вы взглянуть? - person Hashmat Khalil; 29.12.2014