SceneKit load node with animation from separate sc

2019-04-10 05:14发布

问题:

I have a view that creates SCNView dynamically. It's scene is empty, but when I press a button I would like to add a node from separate scn file. This file contains animation, and I would like it to animate in main scene. The problem is that after adding object to the scene it's not animating. When I use this file as SCNView scene it works. isPlaying and loops are enabled. What else do I need to do to import such node with animation? Sample code below:

override func viewDidLoad() {
    super.viewDidLoad()

    let scene = SCNScene()
    let sceneView = SCNView(frame: CGRect(x: 0, y: 0, width: 300, height: 300))
    sceneView.scene = scene
    sceneView.loops = true
    sceneView.isPlaying = true
    sceneView.autoenablesDefaultLighting = true
    view.addSubview(sceneView)


    let subNodeScene = SCNScene(named: "Serah_Animated.scn")!
    let serah = subNodeScene.rootNode.childNode(withName: "main", recursively: false)!

    scene.rootNode.addChildNode(serah)


}

回答1:

All you need is retrieving animations:

        [childNode enumerateChildNodesUsingBlock:^(SCNNode *child, BOOL *stop) {
        for(NSString *key in child.animationKeys) {               // for every animation key
            CAAnimation *animation = [child animationForKey:key]; // get the animation
            animation.usesSceneTimeBase = NO;                     // make it system time based
            animation.repeatCount = FLT_MAX;                      // make it repeat forever
            [child addAnimation:animation forKey:key];            // animations are copied upon addition, so we have to replace the previous animation
        }
    }];


回答2:

You need to fetch the animation from your scene Serah_Animated.scn, which will be a CAAnimation object. You then add that animation object to the rootNode of your main scene.

let animScene = SCNSceneSource(url:<<URL to your scene file", options:<<Scene Loading Options>>)
let animation:CAAnimation = animScene.entryWithIdentifier(<<animID>>, withClass:CAAnimation.self)

You can find the animID from the .scn file using scene editor in Xcode, as shown below.

Now you can add the animation object to your root node.

scene.rootNode.addAnimation(animation, forKey:<<animID>>)

Note that we are reusing animID, that will allow you to also remove the animation from the node.

scene.rootNode.removeAnimation(forKey:<<animId>>)
  • My solution above assumes your animation is a single animation. If you see a bunch of animations, you need to add all the animation nodes. In my workflow, I have files in Blender which I export to Collada format and then use the Automated Collada Converter to ensure I have single animation nodes.
  • Related SO answer
  • You can also fetch the animID programmatically using entriesWithIdentifiersOfClass(CAAnimation.self), useful when you have a bunch of animations instead of a single animation as above or if you just want to add the animation without bothering about the animID before hand.
  • Apple Sample Code for scene kit animations, note the sample code is in ObjC but translation to Swift should be straight forward.