Search code examples
iosopengl-esaugmented-realitycore-motionglkit

Isolate and remove horizontal rotation from CoreMotion's attitude's rotationMatrix


I'm making something like an augmented reality app, in which I have an OpenGL scene that I want to stay aligned with gravity no matter how the iOS device moves. I thought I had it set up fine with a CMDeviceMotion.attitude.pitch, until I discovered that leaning an iPhone sidewards messes with that number. So I took some code from the pARk* example and I'm now trying to isolate out the rotation around the vertical access. The scene I'm drawing doesn't care which heading the user is facing, the figures will always be drawn a set distance from the viewer. I think that when I figure out the vertical axis rotation component I can reverse it and multiply it out of the rotation matrix so keep the OpenGL figures still when the user changes heading.

Here's my code:

CMDeviceMotion *d = motionManager.deviceMotion;
if (d != nil) {

    CMRotationMatrix r = d.attitude.rotationMatrix;
    transformFromCMRotationMatrix(cameraTransform, &r);


    mat4f_t projectionCameraTransform;
    multiplyMatrixAndMatrix(projectionCameraTransform, projectionTransform, cameraTransform);

    GLKMatrix4 rotMatrix = GLKMatrix4Make(projectionCameraTransform[0], 
                                          projectionCameraTransform[1], 
                                          projectionCameraTransform[2], 
                                          projectionCameraTransform[3], 
                                          projectionCameraTransform[4], 
                                          projectionCameraTransform[5], 
                                          projectionCameraTransform[6], 
                                          projectionCameraTransform[7], 
                                          projectionCameraTransform[8], 
                                          projectionCameraTransform[9], 
                                          projectionCameraTransform[10], 
                                          projectionCameraTransform[11], 
                                          projectionCameraTransform[12], 
                                          projectionCameraTransform[13], 
                                          projectionCameraTransform[14], 
                                          projectionCameraTransform[15]);

    }

I then use the rotMatrix as usual in OpenGL.

Thoughts, suggestions? Thanks in advance.

*The pARk sample code sets up a few points in real space, works out the user's location and the relative direction of those points and draws them onscreen so the appear to float at the horizon pointing towards their location.


Solution

  • I've taken a some hints from this answer and come up with a solution:

    https://stackoverflow.com/questions/5328848/simulating-an-image-floating-effect-using-coremotion-devicemotion-on-the-iphone/5442962#5442962

    if (d != nil) {
    
        GLKMatrix4 rotMatrix = GLKMatrix4MakeRotation(0, 0, 1, 0);
        float pitch = d.attitude.pitch;
    
        if (d.gravity.z > 0)
            pitch = -pitch;
    
        rotMatrix = GLKMatrix4Rotate(rotMatrix, pitch, -1, 0, 0);
        rotMatrix = GLKMatrix4Rotate(rotMatrix, d.attitude.roll, 0, -1, 0);
        rotMatrix = GLKMatrix4Rotate(rotMatrix, d.attitude.yaw, 0, 0, -1);
        rotMatrix = GLKMatrix4Multiply(rotMatrix, GLKMatrix4MakeRotation(M_PI/2, 1, 0, 0));
    }
    

    However this haywire when the phone is near vertical. So I'm still looking.