Jes*_*ese 18 objective-c quaternions euler-angles core-motion scenekit
我很难将设备运动(传感器融合)映射到SceneKit节点旋转.问题的前提如下,
我有球体,并且相机定位在球体内部,使得球体的几何中心和相机节点的中心重合.我想要实现的是当我围绕一个点物理旋转时,运动也需要准确地映射到相机上.
实施细节如下:
我有一个节点,一个球体作为几何,并且是一个子节点.我正在使用传感器融合来获得姿态四元数,然后将它们转换为欧拉角.代码是:
- (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);
}
Run Code Online (Sandbox Code Playgroud)
转换方程式来自 3D Math Primer for Graphics and Game Development.我曾经预订作为参考,没有读过它.但绝对在我的阅读清单上.
现在模拟SceneKit中的物理旋转,我正在旋转包含SCNCamera的节点.这是rootNode的孩子.我正在使用.rotation属性来做同样的事情.这里需要注意的一点是,现在我的设备动作更新线程看起来像这样
[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];
}];
Run Code Online (Sandbox Code Playgroud)
这里需要注意的是设备和SceneKit节点的欧拉角是不同的.链接解释了他们.
在我的理解中,两者之间的映射就是这样的.
![[图片]](https://i.stack.imgur.com/cNda7.jpg)
现在我面临的问题是,相机的360度旋转在我的物理旋转到一个点之前结束了.我试图通过以下图片进行调整.
![[图像2]](https://i.stack.imgur.com/5lo7f.jpg)
我怀疑四元数 - >欧拉角转换是否会导致错误,四元数数学现在已经超出了我的想象.
我希望我已经提供了所有信息,如果需要更多信息我很乐意添加.
Ruu*_*ser 11
感谢您对问题的描述和解决方案的开始!我很确定这不能用欧拉角来完成,因为万向节锁定(松散的1自由度).
适用的解决方案是获得姿态并使用四元数来设置摄像机的方向:
[self.motionManager startDeviceMotionUpdatesUsingReferenceFrame:CMAttitudeReferenceFrameXArbitraryCorrectedZVertical toQueue:myQueue withHandler:^(CMDeviceMotion *motion, NSError *error) {
CMAttitude *currentAttitude = motion.attitude;
[SCNTransaction begin];
[SCNTransaction setDisableActions:YES];
SCNQuaternion quaternion = [self orientationFromCMQuaternion:currentAttitude.quaternion];
_cameraNode.orientation = quaternion;
[SCNTransaction commit];
}];
- (SCNQuaternion)orientationFromCMQuaternion:(CMQuaternion)q
{
GLKQuaternion gq1 = GLKQuaternionMakeWithAngleAndAxis(GLKMathDegreesToRadians(-90), 1, 0, 0); // add a rotation of the pitch 90 degrees
GLKQuaternion gq2 = GLKQuaternionMake(q.x, q.y, q.z, q.w); // the current orientation
GLKQuaternion qp = GLKQuaternionMultiply(gq1, gq2); // get the "new" orientation
CMQuaternion rq = {.x = qp.x, .y = qp.y, .z = qp.z, .w = qp.w};
return SCNVector4Make(rq.x, rq.y, rq.z, rq.w);
}
Run Code Online (Sandbox Code Playgroud)
如果 CoreMotion 和 SceneKit 不使用相同的欧拉角约定,那么您可能可以使用中间节点来简化转换。例如,通过具有如下层次结构:
YawNode
|
|___PitchNode
|
|___RollNode
|
|___CameraNode
Run Code Online (Sandbox Code Playgroud)
YawNode、PitchNode、RollNode 仅绕一个轴旋转。然后,通过按照层次结构顺序进行操作,您可以重现 CoreMotion 的约定。
话虽这么说,我不确定转换四元数 -> 欧拉是个好主意。我怀疑你不会在 0 / PI / 2PI 等角度获得连续/平滑的过渡...我会尝试使用 quaternion->matrix4 并更新节点的“变换”。
| 归档时间: |
|
| 查看次数: |
5922 次 |
| 最近记录: |