Search code examples
iosscenekitarkitscnscenearscnview

ARSCNView's root node's "heading" doesn't match the device heading


I want a node which I add to my scene to point north. I get the heading data from Core Location, so that represents the direction the device is currently facing at the point my scene was created (and thus the direction my root node faces), and then I add the heading to my new sceneNode's eulerAngles.y, to rotate it so it faces north.

func renderer(_ renderer: SCNSceneRenderer, didRenderScene scene: SCNScene, atTime time: TimeInterval) {
    if sceneNode == nil,
        let heading = self.locationManager.heading {
        sceneNode = SCNNode()
        sceneNode.eulerAngles.y += Float(heading).degreesToRadians
        sceneView.scene.rootNode.addChildNode(sceneNode)
    }
}

The heading information is correct, and so rotating it by that much does rotate it by the required amount, presuming that the heading is the same direction that my root node is facing. But I'm finding that my root node's direction is not equivalent to where the device's heading is, and can sometimes by wildly off. So that means the assumption that the heading is the same as the scene node's "heading" is incorrect, and I need to be able to know how far out from the heading it is, so I can then correct it properly within my sceneNode.


Solution

  • Change your session configuration's worldAlignment to .gravityAndHeading.

    With the default .gravity alignment, there's no absolute reference for where the x and z axes of the AR world coordinate system point — their directions are based on the initial orientation of your device when the session starts.

    With the .gravityAndHeading option, the x and z axes are aligned to compass directions, so you can safely orient content relative to compass directions.