rgov
rgov

Reputation: 4359

Smooth interpolation of object orientation to track the camera

I have a SCNNode that represents an item held by the player in a first-person game (using ARKit).

I made the node a child of the camera so that it always floats a short distance in front of the viewer. But this simple setup makes the item very static, just glued to the screen.

More realistically, if I were holding an object in front of me, and then turned to face a different direction, my hand movement would lag a little bit behind my head. And if I tilted my head up or down, my perspective of the object would change slightly as well.

How could I emulate this in SceneKit?

This question has some ideas for a camera that chases a node with a delay, and that might work in reverse. For tilting, maybe I'd have to factor in the accelerometer, but constrain it so that you can't rotate the object too much.

Upvotes: 1

Views: 742

Answers (1)

rgov
rgov

Reputation: 4359

Instead of making the item a child of the camera, I made the item a child of a new invisible node called arms. The arms node is not a child of camera, but I used an SCNTransformConstraint to constrain its transformation, like this:

    // ~~ Not the final code ~~ Do not use ~~
    // Set up the viewer's "arms" to follow the camera using a dampened constraint
    arms = SCNNode()
    let armconstraint = SCNTransformConstraint.init(inWorldSpace: false) {
        (node: SCNNode, _) -> SCNMatrix4 in

        // Bind the arm's transformation to the camera's
        return self.sceneView.pointOfView!.convertTransform(SCNMatrix4Identity, to: node)
    }
    armconstraint.influenceFactor = 0.5
    arms!.constraints = [ armconstraint ]
    sceneView.scene.rootNode.addChildNode(arms!)

The idea of using a low influenceFactor so that the arms are not rigidly held in front of the camera, but follow it with a small delay.

This works so-so; it can be noticeably jerky. So I tried splitting it up into two separate constraints: a SCNDistanceConstraint that maintains a distance of 0 between the camera and arms, and a SCNTransformConstraint which syncs the arms orientation but not its position.

What I found is that while the distance constraint was flawless, using a fractional influenceFactor on the orientation caused the arms to go berserk, spinning wildly across the screen! If it was 1.0 then the arms node follows the camera rigidly but without glitching.

It turns out, in the documentation of SCNConstraint.influenceFactor, it says:

This property has no effect on SCNTransformConstraint objects.

Huh, I wonder why—an node's transform, position, and orientation are animatable so it seems they could be interpolated smoothly no problems.

It turns out there is a technique called Slerp which is a way to interpolate between quaternions. So rather than use influenceFactor, each time my SCNTransformConstraint is invoked I can interpolate between the current position of arms and the position of the camera. This is acceptably smooth.

Upvotes: 1

Related Questions