Подтвердить что ты не робот

Как создать новую опорную рамку CMAttitude, чтобы заставить гравитацию быть на оси Y

Я хочу иметь возможность изменить рамку Reference Motion Manager (для гироскопа), чтобы у меня был вектор гравитации по оси Y.

Обычно, когда вы запускаете обновления Device Motion Manager, у вас будет только ось z телефона, выровненная с гравитацией.

Вы можете изменить это, чтобы использовать магнитометр, чтобы ось x была выровнена с магнитным или истинным северным полюсом. При этом у меня есть ось X, указывающая север и моя ось Z, указывающая вниз.

Я хочу, чтобы моя ось Y (отрицательная) указывала вниз (так, чтобы она выровнялась с гравитацией), а также имела мою ось X, указывающую истинный магнитный полюс.

Результат, который я хочу, таков, что, когда мой телефон стоит неподвижно в вертикальной (портретной) ориентации, право на телефон будет выровнено с северным полюсом, и все мои показания (roll, pitch, yaw) будут считаться 0. Затем с этим, если я поверну свой телефон по оси X, шаг изменится, и если я повернусь вокруг оси Y, изменение рыскания изменится.

До сих пор я знаю, что могу установить свой собственный референтный фрейм, если я умножусь на обратное отношение к ранее сохраненному отношению (например, я мог бы установить свой телефон в этой ориентации ВРУЧНУЮ, сохранить это отношение и просто продолжать умножать новое отношение по обратному этому сохраненному, и все мои чтения будут точно такими, какие я хочу).

Но настройка вручную не является вариантом, так как я могу сделать это программно?

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

Надеюсь, я ясно объяснил,

Буду признателен за любые предложения. спасибо

PD: Это координаты ориентации iPhone:

enter image description here

4b9b3361

Ответ 1

Псевдокод:

  1. запускать обновления движения устройства
  2. запустить предварительный просмотр камеры в фоновом режиме;)
  3. записать текущее значение силы тяжести с устройства как ускорение CMA... как только у вас появится гравитация, сохраните его в локальной переменной.
  4. Затем вы должны взять 2 вектора и получить angular между ними, в этом случае гравитация устройства (0,0, -1) и вектор реальной гравитации...
  5. затем мы превращаем theta в thetaPrime... преобразование, которое соответствует ссылочной ориентации CoreMotion
  6. Настройте таймер для анимации....
  7. во время анимации получите инверсию вращенияMatrix свойства motionManager deviceMotion.
  8. Примените Преобразования в правильном порядке, чтобы отразить текущее положение устройства (рыскание, тангаж, крен в эйлеровом режиме или вращение кватернионов устройств... 3 различных способа сказать одно и то же в принципе)

Вот код:

- (void) initMotionCapture
{
    firstGravityReading = NO;
    referenceAttitude = nil;

    if (motionManager == nil)
    {
        self.motionManager = [CMMotionManager new];
    }
    motionManager.deviceMotionUpdateInterval = 0.01;
    self.gravityTimer = [NSTimer scheduledTimerWithTimeInterval:1/60.0 
                                 target:self 
                                 selector:@selector(getFirstGravityReading) 
                                 userInfo:nil repeats:YES];
}


- (void) getFirstGravityReading
{
    CMAcceleration currentGravity; 

    CMDeviceMotion *dm = motionManager.deviceMotion;
    referenceAttitude = dm.attitude;
    currentGravity = dm.gravity;

    [motionManager startDeviceMotionUpdates];

    if (currentGravity.x !=0 && 
        currentGravity.y !=0 && currentGravity.z !=0)
    {
        NSLog(@"Gravity = (%f,%f,%f)", 
              currentGravity.x, currentGravity.y, currentGravity.z);

        firstGravityReading = YES;
        [gravityTimer invalidate];
        self.gravityTimer = nil;
        [self setupCompass];
    }
}

- (void) setupCompass
{
    //Draw your cube... I am using a quartz 3D perspective hack!
    CATransform3D initialTransform = perspectiveTransformedLayer.sublayerTransform;
    initialTransform.m34 = 1.0/-10000;


    //HERE IS WHAT YOU GUYS NEED... the vector equations!
    NSLog(@"Gravity = (%f,%f,%f)", 
          currentGravity.x, currentGravity.y, currentGravity.z);

    //we have current gravity vector and our device gravity vector of (0, 0, -1)
    // get the dot product
    float dotProduct = currentGravity.x*0 + 
                       currentGravity.y*0 + 
                       currentGravity.z*-1;
    float innerMagnitudeProduct = currentGravity.x*currentGravity.x + 
                                  currentGravity.y + currentGravity.y + 
                                  currentGravity.z*currentGravity.z;
    float magnitudeCurrentGravity = sqrt(innerMagnitudeProduct);
    float magnitudeDeviceVector = 1; //since (0,0,-1) computes to: 0*0 + 0*0 + -1*-1 = 1

    thetaOffset = acos(dotProduct/(magnitudeCurrentGravity*magnitudeDeviceVector));
    NSLog(@"theta(degrees) = %f", thetaOffset*180.0/M_PI);

    //Now we have the device angle to the gravity vector (0,0,-1)
    //We must transform these coordinates to match our 
    //device attitude by transforming to theta prime
    float theta_deg = thetaOffset*180.0/M_PI;
    float thetaPrime_deg = -theta_deg + 90; // ThetaPrime = -Theta + 90 <==> y=mx+b

    NSLog(@"thetaPrime(degrees) = %f", thetaOffset*180.0/M_PI);

    deviceOffsetRotation = 
        CATransform3DMakeRotation((thetaPrime_deg) * M_PI / 180.0, 1, 0, 0);
    initialTransform = CATransform3DConcat(deviceOffsetRotation, initialTransform);

    perspectiveTransformedLayer.sublayerTransform = initialTransform;

    self.animationTimer = [NSTimer scheduledTimerWithTimeInterval:1/60.0 
                                   target:self 
                                   selector:@selector(tick) 
                                   userInfo:nil 
                                   repeats:YES];

}

- (void) tick
{
    CMRotationMatrix rotation;

    CMDeviceMotion *deviceMotion = motionManager.deviceMotion;
    CMAttitude *attitude = deviceMotion.attitude;

    if (referenceAttitude != nil)
    {
        [attitude multiplyByInverseOfAttitude:referenceAttitude];
    }
    rotation = attitude.rotationMatrix;

    CATransform3D rotationalTransform = perspectiveTransformedLayer.sublayerTransform;

    //inverse (or called the transpose) of the attitude.rotationalMatrix
    rotationalTransform.m11 = rotation.m11;
    rotationalTransform.m12 = rotation.m21;
    rotationalTransform.m13 = rotation.m31;

    rotationalTransform.m21 = rotation.m12;
    rotationalTransform.m22 = rotation.m22;
    rotationalTransform.m23 = rotation.m32;

    rotationalTransform.m31 = rotation.m13;
    rotationalTransform.m32 = rotation.m23;
    rotationalTransform.m33 = rotation.m33;

    rotationalTransform = 
        CATransform3DConcat(deviceOffsetRotation, rotationalTransform);
    rotationalTransform = 
        CATransform3DConcat(rotationalTransform, 
                            CATransform3DMakeScale(1.0, -1.0, 1.0));


    perspectiveTransformedLayer.sublayerTransform = rotationalTransform;
}

Ответ 2

I hope this will help you

Вы можете изменить опорный кадр, используемый экземпляром CMAttitude. Для этого кешируйте объект отношения, который содержит этот опорный кадр, и передайте его как аргумент multiplyByInverseOfAttitude:. Аргумент отношения, принимающий сообщение, изменяется, чтобы представить изменение отношения к этой системе отсчета.

Чтобы узнать, как это может быть полезно, рассмотрите игру в бейсбол, в которой пользователь поворачивает устройство на свинг. Обычно, в начале поля, летучая мышь была бы в некоторой спокойной ориентации. После этого летучая мышь будет отображаться с ориентацией, определяемой тем, как отношение устройства изменилось с того места, где оно находилось в начале подачи.

-(void) startPitch {

// referenceAttitude is an instance variable

referenceAttitude = [motionManager.deviceMotion.attitude retain];

}

- (void)drawView {

CMAttitude *currentAttitude = motionManager.deviceMotion.attitude;

[currentAttitude multiplyByInverseOfAttitude: referenceAttitude];

// render bat using currentAttitude .....

[self updateModelsWithAttitude:currentAttitude];

[renderer render];

}

Подробнее см. ссылку ниже того же самого, что вы хотите.

http://db-in.com/blog/2011/04/cameras-on-opengl-es-2-x/