I am having a hard time mapping device motion (sensor fusion) to SceneKit node rotation. The premise of the problem is as follows,
I have sphere, and the camera is positioned to be inside the the sphere such that the geometric center of sphere and camera node's center coincide. What i want to achieve is when i rotate physically around a point, the motion needs to be mapped accurately on the camera as well.
The implementaion details are as follows:
I have a node, with a sphere as geomertry and is a child to root node. I am using sensor fusion to get attitude quternions and then converting them to euler angles. The code for that is:
- (SCNVector3)eulerAnglesFromCMQuaternion:(CMQuaternion) {
GLKQuaternion gq1 = GLKQuaternionMakeWithAngleAndAxis(GLKMathDegreesToRadians(90), 1, 0, 0);
GLKQuaternion gq2 = GLKQuaternionMake(q.x, q.y, q.z, q.w);
GLKQuaternion qp = GLKQuaternionMultiply(gq1, gq2);
CMQuaternion rq = {.x = qp.x, .y = qp.y, .z = qp.z, .w = qp.w};
CGFloat roll = atan2(-rq.x*rq.z - rq.w*rq.y, .5 - rq.y*rq.y - rq.z*rq.z);
CGFloat pitch = asin(-2*(rq.y*rq.z + rq.w*rq.x));
CGFloat yaw = atan2(rq.x*rq.y - rq.w*rq.z, .5 - rq.x*rq.x - rq.z*rq.z);
return SCNVector3Make(roll, pitch, yaw);
}
The conversion equation is from 3D Math Primer for Graphics and Game Development. I have used to book as a reference, haven't read it. But definitely on my reading list.
Now to simulate the physical rotation in SceneKit, am rotating my node containing SCNCamera. This is a child to rootNode. And am using .rotation property to do the same. One thing to note here is that Now my device motion update thread looks something like this
[self.motionManager startDeviceMotionUpdatesUsingReferenceFrame:CMAttitudeReferenceFrameXArbitraryCorrectedZVertical toQueue:mq withHandler:^(CMDeviceMotion *motion, NSError *error) {
CMAttitude *currentAttitude = motion.attitude;
[SCNTransaction begin];
[SCNTransaction setDisableActions:YES];
SCNVector3 v = [self eulerAnglesFromCMQuaternion:currentAttitude.quaternion];
self.cameraNode.eulerAngles = SCNVector3Make( v.y, -v.x, 0); //SCNVector3Make(roll, yaw, pitch)
[SCNTransaction commit];
}];
Something of caution here is the euler angles are different for device and for SceneKit node. The links explain them.
And in my understanding the mapping between two goes something like this.
Now the problem I am facing is, the camera's 360 degree rotation is over before my physical rotation about a point is. Which am trying to dpecit via the following image.
I doubt the quaternion -> euler angle conversion is causing the error, and quaternion math is way over my head as of now.
I hope i have provided all the information, if anything more is required am only glad to add.
See Question&Answers more detail:os