Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SceneKit -– How to get animations for a .dae model?

Ok, I am working with ARKit and SceneKit here and I am having trouble looking at the other questions dealing with just SceneKit trying to have a model in .dae format and load in various animations to have that model run - now that we're in iOS11 seems that some solutions don't work.

Here is how I get my model - from a base .dae scene where no animations are applied. I am importing these with Maya -

var modelScene = SCNScene(named: "art.scnassets/ryderFinal3.dae")!

if let d = modelScene.rootNode.childNodes.first {
    theDude.node = d
    theDude.setupNode()
}

Then in Dude class:

func setupNode() {
    node.scale = SCNVector3(x: modifier, y: modifier, z: modifier)
    center(node: node)
}

the scaling and centering of axes is needing because my model was just not at the origin. That worked. Then now with a different scene called "Idle.dae" I try to load in an animation to later run on the model:

func animationFromSceneNamed(path: String) -> CAAnimation? {
    let scene  = SCNScene(named: path)
    var animation:CAAnimation?
    scene?.rootNode.enumerateChildNodes({ child, stop in
        if let animKey = child.animationKeys.first {
            animation = child.animation(forKey: animKey)
            stop.pointee = true
        }
    })
    return animation
}

I was going to do this for all my animations scenes that I import into Xcode and store all the animations in

var animations = [CAAnimation]()

First Xcode says animation(forKey: is deprecated and This does not work it seems to (from what I can tell) de-center and de-scale my model back to the huge size it was. It screws up its position because I expect making the model move in an animation, for example, would make the instantiated model in my game snap to that same position.

and other attempts cause crashes. I am very new to scene kit and trying to get a grip on how to properly animate a .dae model that I instantiate anywhere in the scene -

  1. How in iOS11 does one load in an array of animations to apply to their SCNNode?

  2. How do you make it so those animations are run on the model WHEREVER THE MODEL IS (not snapping it to some other position)?

like image 979
blue Avatar asked Sep 14 '17 02:09

blue


People also ask

How do you animate in SceneKit?

Animation There are two classes which can be used to perform animations in SceneKit: SCNAction objects are very useful for simple and reusable animations, such as movement, rotation and scale. You can combine any number of actions together into a custom action object.

How do you detect user interaction in SceneKit?

User Interaction User interaction is handled in SceneKit by a combination of the UIGestureRecognizer class and hit tests. To detect a tap, for example, you first add a UITapGestureRecognizer to a SCNView, determine the tap's position in the view, and see if it is in contact with or hits any of the nodes.

What can SceneKit's physics simulations tell us?

The functionality that SceneKit's physics simulations offer, is extensive, ranging from basic velocities, accelerations and forces, to gravitational and electrical fields, and even collision detection.

How do you animate a button in a scene in Java?

In the sceneTapped (_:) method, we obtain a reference to the node the user has tapped and check whether this is the button in the scene. If it is, we animate its material from red to white, using the SCNTransaction class, and move it along the y axis in a negative direction using an SCNAction instance.


1 Answers

At first I should confirm that CoreAnimation framework and some of its methods like animation(forKey:) instance method are really deprecated in iOS and macOS. But some parts of CoreAnimation framework are now implemented into SceneKit and other modules. In iOS 11+ and macOS 10.13+ you can use SCNAnimation class:

let animation = CAAnimation(scnAnimation: SCNAnimation)

and here SCNAnimation class has three useful initializers:

SCNAnimation(caAnimation: CAAnimation)
SCNAnimation(contentsOf: URL)
SCNAnimation(named: String)

In addition I should add that you can use not only animations baked in .dae file format, but also in .abc, .scn and .usdz.

Also, you can use SCNSceneSource class (iOS 8+ and macOS 10.8+) to examine the contents of a SCNScene file or to selectively extract certain elements of a scene without keeping the entire scene and all the assets it contains.

Here's how a code with implemented SCNSceneSource might look like:

@IBOutlet var sceneView: ARSCNView!
var animations = [String: CAAnimation]()
var idle: Bool = true

override func viewDidLoad() {
    super.viewDidLoad()
    sceneView.delegate = self

    let scene = SCNScene()
    sceneView.scene = scene
    
    loadMultipleAnimations()
}

func loadMultipleAnimations() {

    let idleScene = SCNScene(named: "art.scnassets/model.dae")!
    
    let node = SCNNode()
    
    for child in idleScene.rootNode.childNodes {
        node.addChildNode(child)
    }       
    node.position = SCNVector3(0, 0, -5)
    node.scale = SCNVector3(0.45, 0.45, 0.45)
    
    sceneView.scene.rootNode.addChildNode(node)
    
    loadAnimation(withKey: "walking", 
                sceneName: "art.scnassets/walk_straight", 
      animationIdentifier: "walk_version02")
}

...

func loadAnimation(withKey: String, sceneName: String, animationIdentifier: String) {

    let sceneURL = Bundle.main.url(forResource: sceneName, withExtension: "dae")
    let sceneSource = SCNSceneSource(url: sceneURL!, options: nil)

    if let animationObj = sceneSource?.entryWithIdentifier(animationIdentifier, 
                                                 withClass: CAAnimation.self) {
        animationObj.repeatCount = 1
        animationObj.fadeInDuration = CGFloat(1)
        animationObj.fadeOutDuration = CGFloat(0.5)

        animations[withKey] = animationObj
    }
}

...

func playAnimation(key: String) {

    sceneView.scene.rootNode.addAnimation(animations[key]!, forKey: key)
}
like image 170
Andy Jazz Avatar answered Sep 23 '22 00:09

Andy Jazz