SceneKit - 如何获得 .dae 模型的动画? [英] SceneKit -– How to get animations for a .dae model?

查看:40
本文介绍了SceneKit - 如何获得 .dae 模型的动画?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

好的,我在这里使用 ARKit 和 SceneKit,但我在查看仅处理 SceneKit 的其他问题时遇到了麻烦,尝试使用 .dae 格式的模型并加载各种动画该模型运行 - 现在我们在 iOS11 中似乎某些解决方案不起作用.

以下是我获取模型的方法 - 从没有应用动画的基本 .dae 场景中获取.我正在用 Maya 导入这些 -

var modelScene = SCNScene(命名为:art.scnassets/ryderFinal3.dae")!如果让 d = modelScene.rootNode.childNodes.first {theDude.node = dtheDude.setupNode()}

然后在 Dude 课上:

func setupNode() {node.scale = SCNVector3(x:修饰符,y:修饰符,z:修饰符)中心(节点:节点)}

需要对轴进行缩放和居中,因为我的模型不在原点.那行得通.然后现在有了一个名为Idle.dae"的不同场景.我尝试加载动画以稍后在模型上运行:

func animationFromSceneNamed(path: String) ->CA动画?{让场景 = SCNScene(命名:路径)var 动画:CAAnimation?场景?.rootNode.enumerateChildNodes({ child, stop in如果让 animKey = child.animationKeys.first {动画 = child.animation(forKey: animKey)stop.pointee = true}})返回动画}

我打算为我导入到 Xcode 中的所有动画场景执行此操作,并将所有动画存储在

var animations = [CAAnimation]()

首先 Xcode 说 animation(forKey: 已弃用,这似乎不起作用(据我所知)将我的模型去中心和缩放回原来的巨大尺寸. 它搞砸了它的位置,因为我希望让模型在动画中移动,例如,会使我的游戏中的实例化模型对齐到相同的位置.

和其他尝试导致崩溃.我对场景工具包非常陌生,并试图掌握如何正确地为 .dae 模型设置动画,我在场景中的任何地方实例化 -

  1. 在 iOS11 中如何加载一系列动画以应用于其 SCNNode?

  2. 你是如何制作这些动画的,无论模型在哪里(而不是将其捕捉到其他位置)?

解决方案

首先我应该确认 CoreAnimation 框架和它的一些方法,比如 animation(forKey:)实例方法在 iOS 和 macOS 中真的被弃用了.但是CoreAnimation 框架的某些部分现在已经实现到SceneKit 和其他模块中.在 iOS 11+ 和 macOS 10.13+ 中,您可以使用 SCNAnimation 类:

let animation = CAAnimation(scnAnimation: SCNAnimation())

这里 SCNAnimation 类有三个有用的初始化器:

SCNAnimation(caAnimation: CAAnimation())SCNAnimation(contentsOf: URL())SCNAnimation(命名:String())

另外我应该补充一点,你不仅可以使用 .dae 文件格式的动画,还可以使用 .abc.scn> 和 .usdz.

此外,您可以使用 SCNSceneSource 类(iOS8+ 和 macOS 10.8+) 检查 SCNScene 文件的内容或有选择地提取场景的某些元素而不保留整个场景及其包含的所有资产.

以下是实现了 SCNSceneSource 的代码的样子:

@IBOutlet var sceneView: ARSCNView!var 动画 = [字符串:CAAnimation]()var idle: Bool = true覆盖 func viewDidLoad() {super.viewDidLoad()场景视图.delegate = self让场景 = SCNScene()场景视图.场景 = 场景加载多个动画()}func loadMultipleAnimations() {让 idleScene = SCNScene(命名为:art.scnassets/model.dae")!让节点 = SCNNode()对于 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)加载动画(withKey:行走",场景名称:art.scnassets/walk_straight",动画标识符:walk_version02")}

...

func loadAnimation(withKey: String, sceneName: String, animationIdentifier: String) {让sceneURL = Bundle.main.url(forResource:sceneName, withExtension:dae")让sceneSource = SCNSceneSource(url:sceneURL!, options: nil)如果让 animationObj = sceneSource?.entryWithIdentifier(animationIdentifier,withClass: CAAnimation.self) {animationObj.repeatCount = 1animationObj.fadeInDuration = CGFloat(1)animationObj.fadeOutDuration = CGFloat(0.5)动画[withKey] = animationObj}}

...

func playAnimation(key: String) {sceneView.scene.rootNode.addAnimation(animations[key]!, forKey: key)}

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

解决方案

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

这篇关于SceneKit - 如何获得 .dae 模型的动画?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆