I would like to use CMAttitude to know the vector normal to the glass of the iPad/iPhone\'s screen (relative to the ground). As such, I would get vectors like the following:
Thanks to Kay for the starting point on the solution. Here is my implementation for anyone that needs it. I made a couple of small tweeks to Kay's advice for my situation. As a heads up, I'm using a landscape only presentation. I have code that updates a variable _isLandscapeLeft to make the necessary adjustment to the direction of the vector.
Quaternion.h
@interface Quaternion : NSObject{
//double w;
//double x;
//double y;
//double z;
}
@property(readwrite, assign)double w;
@property(readwrite, assign)double x;
@property(readwrite, assign)double y;
@property(readwrite, assign)double z;
- (id) initWithValues:(double)w2 x:(double)x2 y:(double)y2 z:(double)z2;
- (Quaternion*) multiplyWithRight:(Quaternion*)q;
@end
Quaternion.m
#import "Quaternion.h"
@implementation Quaternion
- (Quaternion*) multiplyWithRight:(Quaternion*)q {
double newW = _w*q.w - _x*q.x - _y*q.y - _z*q.z;
double newX = _w*q.x + _x*q.w + _y*q.z - _z*q.y;
double newY = _w*q.y + _y*q.w + _z*q.x - _x*q.z;
double newZ = _w*q.z + _z*q.w + _x*q.y - _y*q.x;
_w = newW;
_x = newX;
_y = newY;
_z = newZ;
// one multiplication won't denormalise but when multipling again and again
// we should assure that the result is normalised
return self;
}
- (id) initWithValues:(double)w2 x:(double)x2 y:(double)y2 z:(double)z2 {
if ((self = [super init])) {
_x = x2; _y = y2; _z = z2; _w = w2;
}
return self;
}
@end
And my game class that uses the quaternion for shooting:
-(void)fireWeapon{
ProjectileBaseClass *bullet = [[ProjectileBaseClass alloc] init];
bullet.position = SCNVector3Make(0, 1, 0);
[self.rootNode addChildNode:bullet];
Quaternion *e = [[Quaternion alloc] initWithValues:0 x:0 y:0 z:1];
CMQuaternion cm = _currentAttitude.quaternion;
Quaternion *quat = [[Quaternion alloc] initWithValues:cm.w x:cm.x y:cm.y z:cm.z];
Quaternion *quatConjugate = [[Quaternion alloc] initWithValues:cm.w x:-cm.x y:-cm.y z:-cm.z];
quat = [quat multiplyWithRight:e];
quat = [quat multiplyWithRight:quatConjugate];
SCNVector3 directionToShoot;
if (_isLandscapeLeft) {
directionToShoot = SCNVector3Make(quat.y, -quat.x, -quat.z);
}else{
directionToShoot = SCNVector3Make(-quat.y, quat.x, -quat.z);
}
SCNAction *shootBullet = [SCNAction moveBy:directionToShoot duration:.1];
[bullet runAction:[SCNAction repeatActionForever:shootBullet]];
}