请帮助我正确应用设备旋转数据。

5
我有一个项目,想获取设备相对于重力的旋转和相对于起点的平移,基本上是获取设备的“跟踪”数据。我计划制作一个三维点来模拟我后来从设备记录的数据。为了实现这个目标,我认为最好使用场景工具包,这样我就可以像记录数据一样在三维中看到事物。目前,我一直在尝试让飞船旋转,以便它始终看起来像是遵循重力(就像在地面上一样),无论设备旋转如何。我想一旦我掌握了这个技巧,将把它应用到一个点上。所以我写了下面的代码:
if let attitude = motionManager.deviceMotion?.attitude {
        print(attitude)


        ship.eulerAngles.y = -Float(attitude.roll)
        ship.eulerAngles.z = -Float(attitude.yaw)
        ship.eulerAngles.x = -Float(attitude.pitch)

    }

当您只运行其中一个旋转线时,一切都很完美。它在该轴上的行为是正确的。但是,当我同时进行三个轴时,它变得混乱,并且表现远非预期,出现抖动等问题。
我想问的是: 有人知道如何修复上面的代码,使飞船无论朝向如何都保持“直立”吗?

这个问题太过宽泛了。 - nhgrif
1
@nhgrif,我在上面列出了我的主要问题。尽管其中一些更多是理论而非应用,但根据我的定义,第一个问题并不宽泛。我清楚地说明了我希望得到什么以及当我这样做时出了什么问题。 - J.Doe
问题1本身并不算太宽泛,我认为。您应该考虑将此帖子的范围缩小到仅涉及该问题,以避免因过于宽泛而被关闭。 - nhgrif
1个回答

12

J.Doe!

首先,有一个小技巧。如果您想将iPhone放置在默认位置,您需要注意SceneKit使用的轴与DeviceMotion使用的轴不同。请检查轴:

deviceMotion axis sceneKit axis
(来源:apple.com)

首先,您需要设置相机位置。当您启动SceneKit项目时,它会在位置(0,0,15)处创建您的相机。但这存在问题:

欧拉角的值为(0,0,0)意味着对象将位于xz平面上,但只要您从Z方向看,您就只能从侧面看到它。为了使其等效于将iPhone放置在桌面上,您需要将相机设置为从上方观察,这样就像您正在从手机上观看它(类似于相机,不知道)。

// create and add a camera to the scene
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
scene.rootNode.addChildNode(cameraNode)

// place the camera
cameraNode.position = SCNVector3(x: 0, y: 15, z: 0)
// but then you need to make the cameraNode face the ship (the origin of the axis), rotating it
cameraNode.eulerAngles.x = -Float(M_PI)*0.5 //or Float(M_PI)*1.5

现在我们要从上方观察这艘船,所以第一部分完成了。 接下来我们需要使用设备旋转使船保持“静止”(朝向地面)。

//First we need to use SCNRendererDelegate
class GameViewController : UIViewController SCNSceneRendererDelegate{
    private let motion = CMMotionManager();
...

然后在viewDidLoad中:

//important if you remove the sceneKit initial action from the ship.
//The scene would be static, and static scenes do not trigger the renderer update, setting the playing property to true forces that:
scnView.playing = true;
if(motion.deviceMotionAvailable){
    motion.startDeviceMotionUpdates();
    motion.deviceMotionUpdateInterval = 1.0/60.0;
}

然后我们进入更新方法。

看一下坐标轴:如果将SceneKit坐标系和DeviceMotion坐标系进行比较,Y和Z轴被"交换"。在手机上,Z轴向上,而在场景中为侧面,而Y轴在场景中向上,而在手机上为侧面。因此,分别与X、Y和Z轴相关联的俯仰、滚转和偏航角将被应用为俯仰、偏航和滚转。

注意我将滚动值设置为正值,这是因为还有其他的"交换"。这有点难以想象。请注意,设备运动的Y轴与场景的Z轴相关联。现在想象一个对象沿着这个轴旋转,在同一个方向(例如顺时针方向),由于轴的摆放方向,它们将朝着相反的方向移动。(您也可以将滚动设置为负值,以查看错误之处)

func renderer(renderer: SCNSceneRenderer, updateAtTime time: NSTimeInterval) {
    if let rot = motion.deviceMotion?.attitude{
        print("\(rot.pitch) \(rot.roll) \(rot.yaw)")
        ship.eulerAngles.x = -Float(rot.pitch);
        ship.eulerAngles.y = -Float(rot.yaw);
        ship.eulerAngles.z = Float(rot.roll);
    }

希望这可以帮助到你!再见!


非常感谢您提供如此详尽的答案! - J.Doe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接