SceneKit Collada animation with child node - ios

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).

Related

Swift/IOS: SCNNode appeared to return to its original position after SCNAction is finished, but its actual position was changed by SCNAction

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).

SceneKit nodes aren't changing position with scene's root node

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.)

How can I export a simple rigged model from Maya for use in Scenekit?

I am attempting to experiment with Apple’s Fox game SceneKit example (link below) by adding a model with a simple animation like the ‘panda.scn’ and ‘walk.scn’ assets.
I can create a static model with no joints or animation that works: e.g. In Maya (2017) I add a simple sphere, export selection to FBX_DAE (COLLADA) file, drag it into the project in XCode and convert it to a SCN file. I can then drag that model into the ‘level.scn’, position and scale it as I’d expect.
However as soon as I add any animation or joints to my model I lose the ability to position and scale the model in XCode.
In Maya I add two joints to my sphere select the sphere and joints and export as above. When I examine the model SCN in XCode (either in isolation or as a reference within another scene) I find that I cannot apply any translation or scaling. XCode lets me move the xyz locators in the GUI and update scale but the model does not change. I can see the mesh and joints in the outline view and I have tried moving the joints instead of the mesh, but they do nothing. I have even tried ignoring the GUI and positioning the model in code just as the panda character is set up, but applying positions or transforms to the node does nothing - it always appears at the origin and default scale.
Ignoring that for the moment, my understanding from looking at the ‘walk.scn’ file is that an animation is just an export of the joints with keyframes. I have tried to reproduce that by exporting only the joints to a separate DAE and importing it, then applying that in code as they do with the ‘walkAnimation’. This seems to do nothing as well.
I have experimented with various settings of the FBX_DAE export dialog including baking animations (By the way - what is the difference between baking an animation on export vs baking it in Maya before export? The former seems to do something and the other does nothing in my tests.)
I would dearly love a workflow for creating some simple character animations in Maya and getting them into SceneKit. Any help is greatly appreciated.
For reference:
Apple’s source: https://developer.apple.com/library/content/samplecode/Fox/Introduction/Intro.html
Maya scene for my trivial ball model with two joints:
http://pat.net/misc/ball1.mb
and the DAE output from Maya for that:
http://pat.net/misc/ball1.dae
UPDATE:
Mnuages's answer appears to be correct in that when I added a parent control over the geometry and joints SceneKit then allowed me to move them. But even after brushing up on my understanding of how these nodes and their transforms relate in Maya I do not feel that I have a real understanding of how SceneKit is interpreting them. (Would love to read some docs on that would illuminate this more if they exist).
UPDATE #2:
I was finally able to create an animation by doing the following: 1) Export either the full scene or just the joint with the animation being sure to select the "bake animation" option in the DAE export dialog or bake the entire animation using Key->Bake Animation. 2) It only works if I load the DAE file in scenekit instead of converting it to an SCN. Converting to SCN format seems to lose the animation.
what happens is that the node named joint1 is animated by the joint1-anim animation. So even if you move joint1 in the editor, what you see on screen is the result after the animation is evaluated.
If you create an intermediate node, say joint1-parent, and make joint1 as child node of joint1-parent, then you'll be able to translate and rotate joint1-parent freely and see the effects on joint1.
As for why moving pSphere does not change anything, it's the same idea. Just like the animation overrides the position, the skeleton will reposition the mesh.

Removing SKNodes When Not Visible On Screen

In my game, the size of the level can be larger than the screen of the phone and the camera will follow the player around the level, so there can be a decent amount of content(such as SKEmitterNodes) in the scene that is not visible at any given time. I've been reading through some of the SpriteKit documentation and found this quote in the SMEmitterNode section:
"Consider removing a particle emitter from the scene when it is not
visible onscreen. Add it just before it becomes visible."
Is this something that can be done in my type of game design? I don't want the nodes to be completely removed since they will eventually be put on the screen, but is there a good way for me to add/remove the EmitterNodes (or other SpriteNodes) that are a certain distance from the screen/is this a good idea to do? I'm looking to improve my frame-rate and don't want costly nodes like SMEmitterNodes working while they're not even being displayed, but will adding/removing them as the player moves around reduce the performance?
Here is the idea I currently have: create a rectangle that extends a certain distance around the screen and detect when a node comes into that rectangle, and if it's not already added to the scene, go ahead and add it. Thank you for any suggestions.
SKNodes really aren't a problem because when they are off screen they are not being rendered anyway, just evaluated. So the main thing to worry about with SKNodes are any physics bodies attached to them,
SKEmitterNodes however require some processing power, and that is why apple is recommending not having them emit if they are not on screen. I would just subclass my SKScene class, and do a checks only on SKEmitterNodes whether or not they are in frame, and emit based on that.
So, I would throw all your SKEmitterNodes into a container like an array, and have a loop function to have the node do a CGRectIntersectsRect check based on your camera location and viewable screen size. and if they intersect, add it to the scene, if not remove it from the scene. The array will keep a strong reference so you do not have to worry about it deiniting on you

SceneKit - Adding a new SCNNode to the scene causes severe lag

I found out that adding SCNNodes (with SCNGeometry) to the scene causes a severe lag spike.
According to the Time Profiler it has to generate the geometry (at least the functions/methods are called like that). It does that at the time when the node is added to the scene, not when the node is created. Hence, creating a pool with SCNNodes will not work.
Is there a way to get rid of this lag? I'd like to be able to add nodes to the scene without any FPS drop.
The only idea I have so far is adding everything to the scene already and then hiding / un-hiding it, though this is not really a clean solution.
Here's a shot from Time Profiler:
looks like your are adding a node with an SCNShape or SCNText attached to it and these kinds of geometries are expensive to create (you have to discretize and triangulate the Bézier curve, and eventually have to compute and offset curve for the chamfer).
You can try to preload the following methods from SCNSceneRenderer : -prepareObject:shouldAbortBlock:, -prepareObjects:withCompletionHandler:

Resources