rotationMatrix in landscape mode changing? Augmented reallity on iPhone - augmented-reality

I'm building au augmented reality app that shows buildings in the places given by some points of interest. When you point to that point with your iPhone (in Portrait mode), an OpenGL 3D model appears just in the position indicated by the latitud and the longitude (it converts from that GPS coordinates to screen coordinates using the rotationMatrix from CMDeviceMotion and getting the values x and y).
My problem is that I want it to work in landscape mode too. I've done all the job rotating the views, adapting the heading depending on the current device orientation...but when you point to the building in landscape mode, the model isn't fixed to that coordinates but it moves over the screen. I think the problem is that the rotationMatrix must change when you change the orientation of the device, but I cannot find the way to solve this problem. Any help?
- (void)onDisplayLink:(id)sender {
//Obtenemos los datos de movimiento del dispositivo
CMDeviceMotion *d = motionManager.deviceMotion;
//Si no son nulos (la localizacion esta activada y el magnetometro calibrado)
if (d != nil) {
//Obtenemos la matriz de rotacion
CMRotationMatrix r = d.attitude.rotationMatrix;
transformFromCMRotationMatrix(cameraTransform, &r);
//Indicamos a la vista que necesita ser renderizada de nuevo
[self setNeedsDisplay];
}
}
- (void)drawRect:(CGRect)rect {
//vistaGPS.transform = CGAffineTransformMakeRotation([gestorOrientacion >devolverAnguloSegunOrientacion]);
//Si aun no tenemos puntos de interes, salimos
if (placesOfInterestCoordinates == nil) {
return;
}
//Multiplica la matriz de proyeccion y la de rotacion ¿¿¿para obtener la rotacion en >coordenadas openGL
mat4f_t projectionCameraTransform;
multiplyMatrixAndMatrix(projectionCameraTransform, projectionTransform, >cameraTransform);
//Inicializamos el contador
int i = 0;
CLHeading *heading = locationManager.heading;
CLLocationDirection gradosDiferenciaNorteSinCorregir = heading.trueHeading;
//NSLog(#"%f , %f", gradosDiferenciaNorteSinCorregir, >gradosDiferenciaNorteSinCorregir+90);
CLLocationDirection gradosDiferenciaNorte = [gestorOrientacion >devolverHeadingCorregidoSegunOrientacion:gradosDiferenciaNorteSinCorregir];
////float bearing = [self getHeadingForDirectionFromCoordinate:newLocation.coordinate >toCoordinate: poi.coordenadas.coordinate];
labelHeading.text = [NSString stringWithFormat:#"Heading: %f", gradosDiferenciaNorte];
NSArray *subvistas = [self subviews];
for (PuntoInteres *poi in [puntosDeInteres objectEnumerator]) {
if ([subvistas containsObject:poi.vistaGL]) {
vec4f_t v;
//Multiplicamos la matriz por el vector de coordenadas del punto de interes
multiplyMatrixAndVector(v, projectionCameraTransform, >placesOfInterestCoordinates[i]);
float x = (v[0] / v[3] + 1.0f) * 0.5f;
float y = (v[1] / v[3] + 1.0f) * 0.5f;
[vistaGPS cambiarTextoLabelLatitud:x LabelLongitud:y LabelPrecision:88];
//Si la coordenada Z del vector es negativa, el modelo debe verse
if (v[2] < 0.0f) {
//Centramos la vista en el punto adecuado
poi.vistaGL.center = CGPointMake(x*self.bounds.size.width, >self.bounds.size.height-y*self.bounds.size.height);
//Indicamos que deje de estar oculta
poi.vistaGL.hidden = NO;
[poi.vistaGL.modeloAPintar establecerRotacionEnX:0.0 Y:gradosDiferenciaNorte >Z:0.0];
//Le decimos que comience a dibujarse
[poi.vistaGL startAnimation];
} else {
//Indicamos que este oculta
poi.vistaGL.hidden = YES;
//Le decimos que deje de dibujarse
[poi.vistaGL stopAnimation];
}
}
i++;
}
}
void transformFromCMRotationMatrix(vec4f_t mout, const CMRotationMatrix *m) {
mout[0] = (float)m->m11;
mout[1] = (float)m->m21;
mout[2] = (float)m->m31;
mout[3] = 0.0f;
mout[4] = (float)m->m12;
mout[5] = (float)m->m22;
mout[6] = (float)m->m32;
mout[7] = 0.0f;
mout[8] = (float)m->m13;
mout[9] = (float)m->m23;
mout[10] = (float)m->m33;
mout[11] = 0.0f;
mout[12] = 0.0f;
mout[13] = 0.0f;
mout[14] = 0.0f;
mout[15] = 1.0f;
}

This is a copy of my answer On stackoverflow
The rotation matrix doesn't rotate around the Z axis when the screen orientation changes. The angle properties do correct for this, but I'd rather use just the rotation matrix. Here's the code I have for that:
GLKMatrix4 deviceMotionAttitudeMatrix;
if (_cmMotionmanager.deviceMotionActive) {
CMDeviceMotion *deviceMotion = _cmMotionmanager.deviceMotion;
// Correct for the rotation matrix not including the screen orientation:
// TODO: Let the device notify me when the orientation changes instead of querying on each update.
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
float deviceOrientationRadians = 0.0f;
if (orientation == UIDeviceOrientationLandscapeLeft) {
deviceOrientationRadians = M_PI_2;
}
if (orientation == UIDeviceOrientationLandscapeRight) {
deviceOrientationRadians = -M_PI_2;
}
if (orientation == UIDeviceOrientationPortraitUpsideDown) {
deviceOrientationRadians = M_PI;
}
GLKMatrix4 baseRotation = GLKMatrix4MakeRotation(deviceOrientationRadians, 0.0f, 0.0f, 1.0f);
CMRotationMatrix a = deviceMotion.attitude.rotationMatrix;
deviceMotionAttitudeMatrix
= GLKMatrix4Make(a.m11, a.m21, a.m31, 0.0f,
a.m12, a.m22, a.m32, 0.0f,
a.m13, a.m23, a.m33, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
deviceMotionAttitudeMatrix = GLKMatrix4Multiply(baseRotation, deviceMotionAttitudeMatrix);
}
else
{
// Look straight forward (we're probably in the simulator, or a device without a gyro)
deviceMotionAttitudeMatrix = GLKMatrix4MakeRotation(-M_PI_2, 1.0f, 0.0f, 0.0f);
}

Related

Yaw range on iPhone 5s

I'm using CMDeviceMotion and the attitude's quaternion to obtain the pitch and yaw values, which are then applied to a CC3Camera in a Cocos3D scene to rotate the camera around.
#define RadiansToDegrees(x) ((180 / M_PI) * x)
- (void)initializeScene
{
//...
CC3Camera *cam = [CC3Camera nodeWithName:#"Camera"];
cam.location = cc3v(0, 10, 0.0001);
cam.targetLocation = cc3v(0, 0, 0);
_cameraBoom = [CC3Node nodeWithName:#"CameraBoom"];
_cameraBoom.location = cc3v(0, 0, 0);
[_cameraBoom addChild:cam];
[self addChild:_cameraBoom];
[self setActiveCamera:cam];
_cameraBoom.rotation = cc3v(0, 90, 0);
//...
_motionManager = [[CMMotionManager alloc] init];
_referenceAttitude = nil;
_initialCameraRotation = _cameraBoom.rotation;
[self enableMotion];
}
- (void)enableMotion
{
CMDeviceMotion *deviceMotion = _motionManager.deviceMotion;
_referenceAttitude = deviceMotion.attitude;
_initialCameraRotation = _cameraBoom.rotation;
[_motionManager startDeviceMotionUpdates];
if (!_gyroTimer) {
_gyroTimer = [NSTimer scheduledTimerWithTimeInterval:1 / 30.0
target:self
selector:#selector(doGyroUpdate)
userInfo:nil
repeats:YES];
}
}
- (void)doGyroUpdate
{
CMDeviceMotion *deviceMotion = _motionManager.deviceMotion;
CMAttitude *attitude = deviceMotion.attitude;
if (_referenceAttitude != nil) {
[attitude multiplyByInverseOfAttitude:_referenceAttitude];
}
CMQuaternion quat = attitude.quaternion;
double pitch = RadiansToDegrees(atan2(2 * (quat.x * quat.w + quat.y * quat.z), 1 - 2 * (quat.x * quat.x + quat.z * quat.z)));
double yaw = RadiansToDegrees(asin(2 * (quat.x * quat.y + quat.w * quat.z)));
_cameraBoom.rotation = CC3VectorAdd(_initialCameraRotation, cc3v(pitch, yaw, 0));
}
The pitch is in range [-π, π]. When the device is faced up the pitch = 0 and it becomes π/2 as I take the device from the table and point it to take a picture (portrait mode). The [-π, π] range enables me to rotate the device 360°. When faced down (i.e. device is upside down) the pitch value is π.
The yaw range is only [-π/2, π/2]. It starts at 0 and goes to π/2 when I rotate the device to the left. But if I rotate it beyond π/2, the yaw value starts to decrease.
Can I get the yaw value in range [-π, π], just like the pitch? It would be more useful to be able to rotate the camera sideways by 180° (to the left and to the right, to have a full 360° view) instead of flipping the device vertically to look behind with the camera.
Here's how I did it eventually with the built-in functions:
- (void)doGyroUpdate
{
CMDeviceMotion *deviceMotion = _motionManager.deviceMotion;
CMAttitude *attitude = deviceMotion.attitude;
if (_referenceAttitude != nil) {
[attitude multiplyByInverseOfAttitude:_referenceAttitude];
}
CMQuaternion quat = attitude.quaternion;
CC3Quaternion cc3Quat = CC3QuaternionMake(quat.x, quat.y, quat.z, quat.w);
CC3Vector rot = CC3RotationFromQuaternion(cc3Quat);
_cameraBoom.rotation = cc3v(-rot.x, -rot.z, rot.y);
}
The result:
Rotating the camera like so enables you to look around at the skybox as if you would normally look at the world through the device's back camera. My CC3Camera object is inside a sphere with a HDRi image mapped on to it, on the inside (see this post).
To smoothly rotate the camera:
[_cameraBoom runAction:[CC3ActionRotateTo actionWithDuration:0.15 rotateTo:cc3v(-rot.x, -rot.z, rot.y)]];
Hope this helps someone else too.

Accelerometer and Sprite Face Direction

I am making a simple game where my sprite is moved through the use of accelerometer. My sprite is a circle with eyes on it. I want to rotate the sprite in a way that it is always facing towards the direction it is moving. The below code successfully moves the sprite using the accelerometer but I am having trouble rotating the sprite to face the direction of the movement.
-(void) moveHeroFromAccelaration
{
GLKVector3 raw = GLKVector3Make(_motionManager.accelerometerData.acceleration.x,_motionManager.accelerometerData.acceleration.y,_motionManager.accelerometerData.acceleration.z);
if(GLKVector3AllEqualToScalar(raw, 0))
return;
static GLKVector3 ax, ay, az;
ay = GLKVector3Make(0.63f, 0.0f, -0.92f);
az = GLKVector3Make(0.0f, 1.0f, 0.0f);
ax = GLKVector3Normalize(GLKVector3CrossProduct(az, ay));
CGPoint accel2D = CGPointZero;
accel2D.x = GLKVector3DotProduct(raw, az); accel2D.y = GLKVector3DotProduct(raw, ax);
accel2D = CGPointNormalize(accel2D);
static const float steerDeadZone = 0.18;
if (fabsf(accel2D.x) < steerDeadZone) accel2D.x = 0; if (fabsf(accel2D.y) < steerDeadZone) accel2D.y = 0;
float maxAccelerationPerSecond = 160.0f;
_hero.physicsBody.velocity =
CGVectorMake(accel2D.x * maxAccelerationPerSecond, accel2D.y * maxAccelerationPerSecond);
//1
if (accel2D.x!=0 || accel2D.y!=0) {
//2
float orientationFromVelocity = CGPointToAngle(CGPointMake(_hero.physicsBody.velocity.dx,
_hero.physicsBody.velocity.dy));
float angleDelta = 0.0f;
//3
if (fabsf(orientationFromVelocity-_hero.zRotation)>1) { //prevent wild rotation
angleDelta = (orientationFromVelocity-_hero.zRotation);
} else {
//blend rotation
const float blendFactor = 0.25f; angleDelta =
(orientationFromVelocity - _hero.zRotation) * blendFactor; angleDelta =
ScalarShortestAngleBetween(_hero.zRotation, _hero.zRotation + angleDelta);
}
_hero.zRotation += angleDelta;
// face the hero in the moving direction
[_hero runAction:[SKAction rotateToAngle:orientationFromVelocity duration:0.25 shortestUnitArc:YES]]; <---- THIS IS WHERE I NEED HELP!
}
}

GLKMathUnproject : detecting a tap on an object

So, it seems that GLKit has GLKMathUnproject which can be used to work out where you clicked in 3D space (awesome)
However, I cant get it to work, I have copied a few different examples in and it still does not detect me clicking on my cube at 0,0,0. I basically do a for next loop and see if my ray hits my cube.
-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
NSSet* allTouches = [event allTouches];
UITouch*touch1 = [[allTouches allObjects] objectAtIndex:0];
CGPoint touch1Point = [touch1 locationInView:self.view];
GLKVector3 window_coord = GLKVector3Make(touch1Point.x,touch1Point.y, 0.0f);
bool result;
GLint viewport[4] = {};
glGetIntegerv(GL_VIEWPORT, viewport);
GLKVector3 near_pt = GLKMathUnproject(window_coord, _baseModelViewMatrix, _projectionMatrix, &viewport[0], &result);
window_coord = GLKVector3Make(touch1Point.x,touch1Point.y, 1.0f);
GLKVector3 far_pt = GLKMathUnproject(window_coord, _baseModelViewMatrix, _projectionMatrix, &viewport[0], &result);
//need to get z=0 from
//assumes near and far are on opposite sides of z=0
float z_magnitude = fabs(far_pt.z-near_pt.z);
float near_pt_factor = fabs(near_pt.z)/z_magnitude;
float far_pt_factor = fabs(far_pt.z)/z_magnitude;
GLKVector3 final_pt = GLKVector3Add( GLKVector3MultiplyScalar(near_pt, far_pt_factor), GLKVector3MultiplyScalar(far_pt, near_pt_factor));
float xDif = (final_pt.x - near_pt.x) / 1000;
float yDif = (final_pt.y - near_pt.y) / 1000;
float zDif = (final_pt.z - near_pt.z) / 1000;
for (int i = 0; i < 100; i ++)
{
if ((near_pt.x + (xDif * i)) > self.cube.position.x - self.cube.scale.x && (near_pt.x + (xDif * i)) < self.cube.position.x + self.cube.scale.x &&
(near_pt.y + (yDif * i)) > self.cube.position.y - self.cube.scale.y && (near_pt.y + (yDif * i)) < self.cube.position.y + self.cube.scale.y &&
(near_pt.z + (zDif * i)) > self.cube.position.z - self.cube.scale.z && (near_pt.z + (zDif * i)) < self.cube.position.z + self.cube.scale.z)
{
NSLog(#"%f %f %f", final_pt.x, final_pt.y, final_pt.z);
NSLog(#"Hit cube");
}
}
}
I found the answer here
Updating OpenGL ES Touch Detection (Ray Tracing) for iPad Retina?
- (void)handleTap: (UITapGestureRecognizer *)recognizer
{
CGPoint tapLoc = [recognizer locationInView:self.view];
tapLoc.x *= [UIScreen mainScreen].scale;
tapLoc.y *= [UIScreen mainScreen].scale;
bool testResult;
GLint viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
float uiKitOffset = 113; //Need to factor in the height of the nav bar + the height of the tab bar at the bottom in the storyboard.
GLKVector3 nearPt = GLKMathUnproject(GLKVector3Make(tapLoc.x, (tapLoc.y-viewport[3]+uiKitOffset)*-1, 0.0), modelViewMatrix, projectionMatrix, &viewport[0] , &testResult);
GLKVector3 farPt = GLKMathUnproject(GLKVector3Make(tapLoc.x, (tapLoc.y-viewport[3]+uiKitOffset)*-1, 1.0), modelViewMatrix, projectionMatrix, &viewport[0] , &testResult);
farPt = GLKVector3Subtract(farPt, nearPt);
....
}

CMMotionManager Reference Frame

I'm developing an app that when a user opens there will be an image, controlled by CMMotionManager, which moves according to the direction the user tilts the device.
....
This is my code to start the device motion.
motionManager = [[CMMotionManager alloc] init];
motionManager.showsDeviceMovementDisplay = YES;
motionManager.deviceMotionUpdateInterval = 1.0 / 60.0;
[motionManager startDeviceMotionUpdatesUsingReferenceFrame:CMAttitudeReferenceFrameXArbitraryCorrectedZVertical];
The is the code I use to control my image in reference to the motion of the device.
- (void)drawRect:(CGRect)rect
{
if (placesOfInterestCoordinates == nil) {
return;
}
mat4f_t projectionCameraTransform;
multiplyMatrixAndMatrix(projectionCameraTransform, projectionTransform, cameraTransform);
int i = 0;
for (MovingImage *poi in [placesOfInterest objectEnumerator]) {
vec4f_t v;
multiplyMatrixAndVector(v, projectionCameraTransform, placesOfInterestCoordinates[i]);
float x = (v[0] / v[3] + 1.0f) * 0.5f;
float y = (v[1] / v[3] + 1.0f) * 0.5f;
if (v[2] < 0.0f) {
CGPoint movingTo = CGPointMake(x*self.bounds.size.width, self.bounds.size.height-y*self.bounds.size.height);
if (movingTo.x < -118) {
movingTo.x = -118;
}
if (movingTo.x > 542) {
movingTo.x = 542;
}
if (movingTo.y < 215) {
movingTo.y = 215;
}
if (movingTo.y > 390) {
movingTo.y = 390;
}
poi.view.center = movingTo;
poi.view.hidden = NO;
} else {
poi.view.hidden = YES;
}
i++;
}
}
The image is in the middle of the screen rarely when the user opens the app, the image is usually to the right or left 90 degrees of the starting position, or exactly in the middle consistently.
I assume that CMAttitudeReferenceFrameXArbitraryCorrectedZVertical is the issue, but I have also tried CMAttitudeReferenceFrameXArbitraryZVertical which doesn't work either.
If useful, my project is here, for anyone interested. I used Apple pARk sample code as well.
- (void)drawRect:(CGRect)rect
{
if (placesOfInterestCoordinates == nil) {
return;
}
mat4f_t projectionCameraTransform;
multiplyMatrixAndMatrix(projectionCameraTransform, projectionTransform, cameraTransform);
int i = 0;
for (MovingImage *poi in [placesOfInterest objectEnumerator]) {
vec4f_t v;
multiplyMatrixAndVector(v, projectionCameraTransform, placesOfInterestCoordinates[i]);
float x = (v[0] / v[3] + 1.0f) * 0.5f;
float y = (v[1] / v[3] + 1.0f) * 0.5f;
if (v[2] < 1.0f) { // change here
CGPoint movingTo = CGPointMake(x*self.bounds.size.width, self.bounds.size.height-y*self.bounds.size.height);
if (movingTo.x < -118) {
movingTo.x = -118;
}
if (movingTo.x > 542) {
movingTo.x = 542;
}
if (movingTo.y < 215) {
movingTo.y = 215;
}
if (movingTo.y > 390) {
movingTo.y = 390;
}
poi.view.center = movingTo;
poi.view.hidden = NO;
} else {
poi.view.hidden = YES;
}
i++;
}
}
try changing (v[2] < 0.0f) to (v[2] < 1.0f)
The viewing angle is different because it is looking for when the image comes into view, other than your device's perspective angle.

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.
I just rotate the orientation around the Z axis depending on device screen orientation. This isn't the prettiest but it seems to do exactly what I need, without going to euler and back (and thus, avoiding the gymbal lock problems)
GLKMatrix4 deviceMotionAttitudeMatrix;
if (_cmMotionmanager.deviceMotionActive) {
CMDeviceMotion *deviceMotion = _cmMotionmanager.deviceMotion;
// Correct for the rotation matrix not including the screen orientation:
// TODO: Let the device notify me when the orientation changes instead of querying on each update.
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
float deviceOrientationRadians = 0.0f;
if (orientation == UIDeviceOrientationLandscapeLeft) {
deviceOrientationRadians = M_PI_2;
}
if (orientation == UIDeviceOrientationLandscapeRight) {
deviceOrientationRadians = -M_PI_2;
}
if (orientation == UIDeviceOrientationPortraitUpsideDown) {
deviceOrientationRadians = M_PI;
}
GLKMatrix4 baseRotation = GLKMatrix4MakeRotation(deviceOrientationRadians, 0.0f, 0.0f, 1.0f);
CMRotationMatrix a = deviceMotion.attitude.rotationMatrix;
deviceMotionAttitudeMatrix
= GLKMatrix4Make(a.m11, a.m21, a.m31, 0.0f,
a.m12, a.m22, a.m32, 0.0f,
a.m13, a.m23, a.m33, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
deviceMotionAttitudeMatrix = GLKMatrix4Multiply(baseRotation, deviceMotionAttitudeMatrix);
}
else
{
// Look straight forward (we're probably in the simulator, or a device without a gyro)
deviceMotionAttitudeMatrix = GLKMatrix4MakeRotation(-M_PI_2, 1.0f, 0.0f, 0.0f);
}
Here's some code to clarify how to use the attitude.rotationMatrix
// initial model view matrix
GLKMatrix4 modelViewMatrix = GLKMatrix4MakeTranslation(0.0f, 0.0f, -5.f);
// convert CMRotationMatrix to GLKMatrix4
CMRotationMatrix r = motion.attitude.rotationMatrix;
GLKMatrix4 = GLKMatrix4Make(r.m11, r.m21, r.m31, 0.0f,
r.m12, r.m22, r.m32, 0.0f,
r.m13, r.m23, r.m33, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
// apply motion rotation matrix
modelViewMatrix = GLKMatrix4Multiply(modelViewMatrix, _motionRotationMatrix);
// apply matrix to effect
self.effect.transform.modelviewMatrix = modelViewMatrix;
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.

Resources