Question

Please bear with me, I'm really awful at matrix math. I have a layer that I want to remain "stationary" with gravity at the referenceAttitude while the phone rotates to other attitudes. I have a motionManager working nicely, am using multiplyByInverseOfAttitude on the current attitude, and applying the resulting delta as a rotation to my layer using a CMRotationMatrix (doing separate CATransform3DRotates for the pitch, roll, and yaw caused considerable wackiness near the axes). It's basically inspired by code like this example.

I concat this with another transform to apply the m34 perspective trick before I apply the rotation to my layer.

[attitude multiplyByInverseOfAttitude:referenceAttitude];

CATransform3D t = CATransform3DIdentity;
CMRotationMatrix r = attitude.rotationMatrix;
t.m11=r.m11;    t.m12=r.m12;    t.m13=r.m13;    t.m14=0;
t.m21=r.m21;    t.m22=r.m22;    t.m23=r.m23;    t.m24=0;
t.m31=r.m31;    t.m32=r.m32;    t.m33=r.m33;    t.m34=0;
t.m41=0;        t.m42=0;        t.m43=0;        t.m44=1;

CATransform3D perspectiveTransform = CATransform3DIdentity;
perspectiveTransform.m34 = 1.0 / -650;
t = CATransform3DConcat(t, perspectiveTransform);

myUIImageView.layer.transform = t;

The result is pretty and works like you'd expect, the layer staying stationary with gravity as I move my phone around, except for a single axis, the y-axis; holding the phone flat and rolling it, the layer rolls double-time in the direction the phone is, instead of remaining stationary.

I don't know why this one axis moves wrong while the other moves correctly after applying the multiplyByInverseOfAttitude. When using separate CATransform3DRotates for the pitch, yaw, roll, I was able to easily correct the problem by multiplying the roll vector by -1, but I have no idea how to apply that to a rotation matrix. The problem obviously is only visible once you introduce perspective into the equation, so perhaps I'm doing that wrong. Inverting my m34 value fixes the roll but creates the same problem on the pitch. I either need to figure out why the rotation on this axis is backwards, invert the rotation on that axis via my matrix, or correct the perspective somehow.

Was it helpful?

Solution

You have to take into account the following:

  1. In your case, CMRotationMatrix needs to be transposed (http://en.wikipedia.org/wiki/Transpose) which means swapping columns and rows.
  2. You don't need to set the transform as CATransform3DIdentity, because you're overwriting each value, so you can start with an empty matrix. If you want to use CATransform3DIdentity you can omit setting 0s and 1s since they've already been defined. (CATransform3DIdentity is an identity matrix, see http://en.wikipedia.org/wiki/Identity_matrix)
  3. To also correct the rotation around the Y axis, you need to multiply your vector with [1 0 0 0; 0 -1 0 0; 0 0 1 0; 0 0 0 1].

Make the following changes to your code:

CMRotationMatrix r = attitude.rotationMatrix;
CATransform3D t;
t.m11=r.m11;    t.m12=r.m21;    t.m13=r.m31;    t.m14=0;
t.m21=r.m12;    t.m22=r.m22;    t.m23=r.m32;    t.m24=0;
t.m31=r.m13;    t.m32=r.m23;    t.m33=r.m33;    t.m34=0;
t.m41=0;        t.m42=0;        t.m43=0;        t.m44=1;

CATransform3D perspectiveTransform = CATransform3DIdentity;
perspectiveTransform.m34 = 1.0 / -650;
t = CATransform3DConcat(t, perspectiveTransform);
t = CATransform3DConcat(t, CATransform3DMakeScale(1.0, -1.0, 1.0));

Or, with setting t to CATransform3DIdentity just leave the 0s and 1s out:

...
CATransform3D t = CATransform3DIdentity;
t.m11=r.m11;    t.m12=r.m21;    t.m13=r.m31;
t.m21=r.m12;    t.m22=r.m22;    t.m23=r.m32;
t.m31=r.m13;    t.m32=r.m23;    t.m33=r.m33;
....
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top