I'm using SceneKit with ARKit, and right now have a simple app where I tap on the screen and it adds an ARAnchor and a SCNNode to my scene.
At some point, I'm going to want to move the entire scene, so I tried changing sceneView.scene.rootNode.position.x += 10 to test this out. If I call this on any particular node, that node does move appropriately. But calling this on rootNode, nothing happens, where I'd expect every child node (which is every node in the scene) to move along with it.
Why are my other nodes not moving appropriately, and is there something I can do to fix this? Or am I thinking about this wrong?
Per the docs for SCNScene.rootNode:
You should not modify the transform property of the root node.
The root node defines the origin of the world coordinate system — all other measurements are relative to it. Hence, it's not meaningful (and is often problematic) to change its position, orientation, scale, or any other aspect of its transform.
If you want to move all the content in your SceneKit scene, create a new node to contain all of the others, and change that node's transform. (You can't do this for nodes added by ARSCNView, because ARKit makes those direct children of the root node, but the whole point of those is positioning them in world space.)
Related
I am very new to Swift and IOS development so this could be a simple question, but I struggle to find the answer on the internet.
I was trying to animate a static DAE model by running a SCNAction on one of its nodes. However, after the SCNAction was completed (and the node was moved), the node position will appear to go back to its original position immediately (same position when the static DAE model was loaded). But when I print the node's position, I noticed that the node's position was actually changed because of the SCNAction. And when I ran the SCNAction again on the same node, the node will go back to the end position resulted from the last SCNAction and start the SCNAction from there. I wonder why there's such mismatch between the node's actual position and the position appeared in the scene.
Another interesting thing was when I put SCNActions in sequence ([action1, action2]), the node will not return to its original position between actions. But if SCNAction.wait was added in between ([action1, SCNAction.wait, action2]), the node will return to its original position during the wait, and will start action2 again from action1's end position.
I am trying to maintain the positions of all nodes at the end of SCNActions. Is there any way to prevent it from going back to the original position?
Not sure if the question is clear enough. Any thoughts and ideas are appreciated.
Have you verified that the node does not come with an animation from the Collada file? Animations and actions are evaluated one after the other. The actions may override the effect of the animation, until they are done (or paused).
Unlike actions, animations don't write in the model tree (node.position) but only in the presentation tree (node.presentationNode.position).
I have an imported DAE file in SceneKit and am trying to add a particle system to it. It's a cigar smoking character and I want smoke to appear from the end of his cigar. Like this:
The problem is, when his animation begins, the particle system doesn't move with the cigar, despite the fact it is a child of the cigar node.
What am I missing here?
I figured it out. Two things that need to happen:
The node has to be a child of the node that is being animated, which
in this case is the node with the bones as the character was rigged.
Also, in the particle system you need to make sure the emitter is set
to world space so it doesn't rotate with the parent node (smoke would
always rise vertically regardless of the rotation of the head).
I have a series of (flat plane) nodes in my scene that I need to have constantly facing the camera.
How can I adjust the transform/rotation to get this working?
Also, where do I make this calculation?
Currently I am trying to make it happen on user interaction in the SCNSceneRendererDelegate renderer:updateAtTime: delegate method.
How about an SCNBillboardConstraint? That restricts you to iOS 9/El Capitan/tvOS. Add the constraint to each of your flat plane (billboard) nodes.
From the SceneKit Framework Reference: https://developer.apple.com/library/ios/documentation/SceneKit/Reference/SCNBillboardConstraint_Class/index.html
An SCNBillboardConstraint object automatically adjusts a node’s orientation so that it always points toward the pointOfView node currently being used to render the scene.
In the more general case, SCNLookAtConstraint will keep any node's minus-Z axis pointed toward any other node.
I currently have a scene which contains a central node at the root of the scene with earth-like geometry and a node representing a flying vehicle.
However I cannot find the right approach to control the movement of the vehicle. I need the ability to turn left and right while orbiting at a static altitude and speed.
I have tried many combinations of animations and physics body forces all leading to undesirable results.
The closest I've come is:
Setting the pivot property of the vehicle to the centre of the scene
Then setting an Action like below to control moving forward
[_vehicleNode runAction:[SCNAction repeatActionForever:[SCNAction rotateByX:-1 y:0 z:0 duration:10.0]]];
Then finally applying forces for turning left and right with
[_vehicleNode.physicsBody applyTorque:SCNVector4Make(0, 1, 0, 1) impulse:YES];
However I cannot seem to set the pivot and/or position to the right value to get the desired result.
Edit: It appears as the above method would be the solution I'm looking for, however for some reason when I add geometry to the vehicle node, it's position in the scene graph gets changed dramatically. When I add hardcoded buttons to change it's position to where it belongs it appears correct for only that single frame then straight back to being in the middle of nowhere.
Edit 2: After replacing all geometry with a primitive sphere for testing the node is now rotating as intended but is now unaffected by physics forces appearing to ignore it's declaration as a dynamicBody.
If I understand what you are trying to achieve correctly, you can try this:
add a first node to your scene, positioned at (0,0,0) and make it rotate forever along the Y axis using an SCNAction
add your ship node as a child of the first node. Position it at (X,0,0) so that it orbits around the earth
rotate your ship node along the X axis with an action or an animation
I'm so freaking confused about anchorpoint in SpriteKit.
If I have a Node consisting of multiple childnodes, and I change the anchorpoint of the Node, then all the childnodes gets misplaced. Is there any way around this?
I think it's really annoying to position nodes if I always use the default anchorpoint (0.5,0.5), so sometimes I change the anchorpoint to for example 1.0,0.0 so it's easily placed in the right lower corner. But if this node has childnodes, then they are all misplaced when I change the anchorpoint.
What am I missing?
Avoid changing the default anchorPoint whenever possible.
If you do change anchorPoint, make sure you do so only on nodes without children.
In your case (and in general) the fix is relatively easy. Instead of adding child nodes to the sprite node whose anchorPoint got changed, use a common parent node (SKNode). Add the sprite node to the parent node, change the sprite's anchorPoint but don't add any children to it. Instead add those children to the parent node. You can then use the parent node to position this branch of the node tree together.
Alternatively create a subclass of (or category on) SKSpriteNode with methods that allow you to align the node to a certain border, taking the sprite's frame size and anchorPoint into account. For example you could add two properties verticalAlign and horizontalAlign with center, left/top and right/bottom alignment. Whenever the position property is changed, the point is offset before being passed to super setPosition so that the alignment mode is adhered to.