Gene M.
Gene M.

Reputation: 130

Keep node's X and Z axes parallel to ground while rotating Y axis to face camera

I'm trying to keep an SCNNode always one meter away from the front of the camera, and manipulate the node so that the X and Z axes are always parallel to the ground, while the node rotates around the Y-axis so that the node is always facing the camera.

The code below achieves my goal for the most part, but when turning more than 90˚ clockwise or counterclockwise, the node starts turning. How can I fix that?

override func viewDidLoad() {
    super.viewDidLoad()

    boxParent.position = (sceneView.pointOfView?.position)!
    boxParent.orientation = (sceneView.pointOfView?.orientation)!
    boxParent.eulerAngles = (sceneView.pointOfView?.eulerAngles)!
    sceneView.scene.rootNode.addChildNode(boxParent)

    boxOrigin.position = SCNVector3(0,0,-1)
    boxParent.addChildNode(boxOrigin)

    box = SCNNode(geometry: SCNBox(width: 0.5, height: 0.2, length: 0.3, chamferRadius: 0))
    box.geometry?.firstMaterial?.diffuse.contents = UIColor.blue
    box.position = SCNVector3(0,0,0)
    boxOrigin.addChildNode(box)
}
    func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) {
    boxParent.eulerAngles = (sceneView.pointOfView?.eulerAngles)!
    boxParent.orientation = (sceneView.pointOfView?.orientation)!
    boxParent.position = (sceneView.pointOfView?.position)!

    box.position = boxOrigin.worldPosition
    box.eulerAngles.y = (sceneView.pointOfView?.eulerAngles.y)!
    print(box.eulerAngles)

    sceneView.scene.rootNode.addChildNode(box)
}

Upvotes: 1

Views: 770

Answers (1)

Andy Jazz
Andy Jazz

Reputation: 58103

You're simultaneously using two types of rotation. It's wrong!

boxParent.orientation = (sceneView.pointOfView?.orientation)! //quaternion

This variable uses the node’s orientation, expressed as quaternion (4 components: x, y, z, w).

boxParent.eulerAngles = (sceneView.pointOfView?.eulerAngles)!

The node’s rotation, expressed as pitch, yaw, and roll angles, in radians (3 components: x, y, z).

You need to decide which var you'll be using: orientation or eulerAngles. I suppose you'll choose orientation.

Read this useful article and this one about Quaternions and what a Gimbal Lock is.

Also, use SCNLookAtConstraint object (node's negative z-axis points toward the constraint's target node) or SCNBillboardConstraint object (automatically adjusts a node's orientation so that its local z-axis always points toward the node's pointOfView) for automatically adjusting a node’s orientation, so you camera'll be always pointing toward another node.

Upvotes: 1

Related Questions