SceneKit –映射物理360度旋转 [英] SceneKit – Mapping physical 360 rotation

查看:307
本文介绍了SceneKit –映射物理360度旋转的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我很难将设备运动(传感器融合)映射到SceneKit节点旋转.问题的前提如下,

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.

实现细节如下:

我有一个节点,球体为风水学,是根节点的子节点.我正在使用传感器融合来获取姿态四元数,然后 将它们转换为欧拉角.的代码是:

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.

现在要模拟SceneKit中的物理旋转,请旋转包含SCNCamera的节点.这是rootNode的子级.并正在使用.rotation 属性也要这样做.这里要注意的一件事是 现在我的设备动作更新线程看起来像这样

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];
}];

此处需要注意的一点是,设备和SceneKit节点的欧拉角不同.链接解释了它们.

Something of caution here is the euler angles are different for device and for SceneKit node. The links explain them.

SceneKit欧拉角

据我所知,两者之间的映射是这样的.

And in my understanding the mapping between two goes something like this.

现在我面临的问题是,在我绕某个点进行物理旋转之前,相机的360度旋转已经结束. 试图通过下图显示.

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.

推荐答案

感谢您对问题的描述以及解决方案的开始! 我非常确定,由于万向节锁(1度松动,不存在欧拉角),无法做到这一点.自由).

Thanks for your description of your problem and the beginning of a solution! I am quite sure that this can not be done with the Euler angles, because of the gimbal lock (loose of 1 degree of freedom).

有效的解决方案是获取姿态并使用四元数来设置相机的方向:

The solution that worked for is to get the attitude and use the quaternion to set the orientation of the camera:

[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);
}

这篇关于SceneKit –映射物理360度旋转的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆