Reputation: 4359
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
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