SCNNode scale changes when animation plays using a dae file - ios

Trying to use a dae file in scenekit for my model as well as my animations. When I try to scale the model, it scales correctly. After the animation starts playing, it resets to the original scale. Here is what I am trying to do at the moment:
let playerNode = gameScene.rootNode.childNode(withName: "Player", recursively: true)
let animation = CAAnimation.animationWithSceneNamed(name: "GameAssets.scnassets/Objects/WalkAnimation.dae")
playerNode.addAnimation(animation, forKey: "WalkAnimation")

As we don't have access to your Collada file, let's take the example of walk.dae from the SceneKitAnimations sample code.
In that file you will find the following:
<library_animations>
<animation id="WalkID">
...
<source id="node-Bip01_matrix-output">
...
<technique_common>
<accessor source="#node-Bip01_matrix-output-array" count="29" stride="16">
<param name="TRANSFORM" type="float4x4"/>
</accessor>
</technique_common>
You can see that the animation file does not have separate animations for positions and rotations, but instead it has a single animation that targets the whole transforms (cf TRANSFORM and float4x4).
This means that evaluating the animation will override the scale of the node. You'll have to have different animations just for the position and rotation properties instead of an animation for the transform property if you don't want the scale to be overridden.

Related

How can I access multiple animations in Swift?

Image of the file hierarchy in xcode of my animation file
Issue:
xcode is recognizing multiple animations for a single Collada (.dae) file. But I can't find any documentation on how to access these animations directly. I tried using the fox game example, but it only loads one of the animations.
Here's my code:
let modelNode = self.addModel_DAE_return(x: 0, y: 0, z: 0, scaleFactor: 0.0005, fileName: "models.scnassets/export_014/export_014_model.dae")
// add the animation to the model
let modelAnim = self.loadAnim_DAE(fileName: "models.scnassets/export_014/export_014_anim.dae")
modelNode.addAnimationPlayer(modelAnim, forKey: "headMove")
modelAnim.play()
// add the model to the scene
node.addChildNode(modelNode)
How can I access and load in the other animations?
Context:
I'm making an AR app. I'm using the Apple Image Recognition example as a base.
Here's a link to it:
https://developer.apple.com/documentation/arkit/recognizing_images_in_an_ar_experience
I animated a skeleton in Maya and exported the animation to a COLLADA (.DAE) file using the OpenCollada extension for Maya.
I exported separate files for the model and the animation, because if I export them as a single file, none of my animations export and xcode crashes every time I try to access the file to check if it registers any animations.
I want to access the "Entities" of my animation file so I can just loop over, load and attach the animations, but I can't
also I have looked into GameKit kind of but, is there not a way to do this with SceneKit?
Each joint in the rig has animation information
Originally I was only getting the information the first joint that had animations on it and not its children that also had animations attached
i.e. lets say your rig hierarchy is
hips > rightShoulder > arm > elbow > wrist
and your animations were on the shoulder, arm, elbow, and wrist joints
you do not have any animations on your hip joint
using enumerateChildNodes will only grab the information from the shoulder joint
using enumerateHierarchy will grab all the animation information from the shoulder, the elbow, AND the wrist joint
see below for my function that I used:
note that I had separately loaded and saved my 3D model onto an SCNNode and that was passed in so I could attach the animations to it
func loadAttachAnim_DAE(fileName: String, modelNode: SCNNode){
let scene = SCNScene(named: fileName)!
//find top level animation
var animationPlayer: SCNAnimationPlayer! = nil
scene.rootNode.enumerateHierarchy{ (child, stop) in
if !child.animationKeys.isEmpty {
print ("child = \(child) -----------------")
animationPlayer = child.animationPlayer(forKey: child.animationKeys[0])
modelNode.addAnimationPlayer(animationPlayer, forKey: "\(child)")
animationPlayer.play()
}
}
}

Model in dae format can't be moved or scaled, can it be locked?

I am trying to work with a dae model, but somehow can't modify the position or scale it at all. Other models work fine though. Can these dae models be locked somehow?
let objScene = SCNScene(named: "art.scnassets/test.dae")!
self.objNode = objScene.rootNode.childNode(withName: "test", recursively: true)
let action = SCNAction.scale(by: 0.25, duration: 1.0)
self.objNode.runAction(action)
self.objNode?.position = SCNVector3(0.0,0.0,-2.0)
self.arSceneView.scene.rootNode.addChildNode(self.objNode!)
This can happen if your Collada file contains animations that target the "test" node.
If you programmatically set the node's position or scale, and then an animation targeting the node's transform is evaluated it will override everything giving the impression that the node can't be modified.
You can always nest a node targeted by an animation under a dummy parent node, that you can freely translate, rotate or scale.

How to scale DAE models correctly in ARKit and SceneKit?

I'm currently trying to combine the following sources:
Apples SceneKit Vehicle Demo, Resp. its Swift version,
ARKit by example, and resp. its Swift version.
Each project on its own works like a charm (although I changed the vehicle demo so that the car can be controlled by on-screen buttons).
Now, when I try to combine both projects to create an augmented reality racing game, I run into problems regarding the size of the .dae model of the car: it's too big.
I can scale the model using the (chassis) nodes .scale property, but as soon as I add the SCNPhysicsVehicle properties and behaviour, the car gets reset(?) to its original size. I tried to scale the model in Xcode (open dae file, change scale), but its bounding box remains the same - that tells me that the rescaling didn't work properly.
Any hints?
1)you can scale the dae models by art.scnassets directly.
art.scnassets -> car.dae -> node inspector -> transforms -> scale the object
2) can scale 3dmodel by SCNAction
let scene = SCNScene(named: "art.scnassets/cup.dae")!
let node = scene.rootNode.childNode(withName: "cup", recursively: true)!
let action = SCNAction.scale(by: sender.scale, duration: 1.0)
node.runAction(action)
What I like to do is use Blender or some other 3d modeling program to resize your dae model to work in meters. Everything in ARKit is based on meters, so by sticking to the same metric you can get all your models to play well together without having to guess what the scale factor needs to be.
I'm not sure how to fix the model directly in Xcode. However, you can fix it in blender. Start by importing the object into blender. Select the object and observe it's dimensions. Scale the object to the desired dimensions and apply them by hittin Ctrl + A, and selecting scale. Alternatively, from the object menu, you can select Apply -> Scale. Now you can export your model with the corrected size.

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.

How to add custom animations in ios scene kit swift

I am making a game with scene kit and part of it rolls some dice to generate a number, i have made the dice in 3DS max 2016. I can make the animations easily on 3DS max, but how would i load it into my scene? I have loaded in a dice with no animations, but I am not sure how I can load the dice animations so that it rolls.
What I intend to do is make xcode generate a number, and with that number is chooses a file out of different files, e.g. animation1, animation2. Say the number generated was 2 it would run animation2.
Thanks
You can export animations from 3DS Max with OpenCOLLADA plugin.
Then you can get animations with SCNSceneSource, like:
let src = SCNSceneSource(URL: yourSceneURL, options: nil)
let node = src.entryWithIdentifier("yourNodeID", withClass: SCNNode.self) as SCNNode
let animation = node.entryWithIdentifier("yourAnimationID", withClass: CAAnimation.self) as CAAnimation
Extract animations to array, and attach random one to your node with SCNNode's addAnimation(forKey:)

Resources