SceneKit - 如何获取 .dae 模型的动画?

Posted

技术标签:

【中文标题】SceneKit - 如何获取 .dae 模型的动画?【英文标题】:SceneKit -– How to get animations for a .dae model? 【发布时间】:2018-02-22 20:58:58 【问题描述】:

好的,我在这里使用 ARKit 和 SceneKit,但我无法查看其他仅处理 SceneKit 的问题,该问题试图拥有 .dae 格式的模型并加载各种动画以运行该模型 - 现在我们在 ios11 似乎有些解决方案不起作用。

这是我获取模型的方法 - 从一个未应用动画的基本 .dae 场景。我正在使用 Maya 导入这些 -

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

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

然后在Dude课上:

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

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

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

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

var animations = [CAAnimation]()

第一个 Xcode 说 animation(forKey: 已弃用,这似乎不起作用(据我所知)我的模型去中心化并缩小到原来的巨大尺寸。它搞砸了它的位置,因为我希望让模型在动画中移动,例如,会使我的游戏中的实例化模型捕捉到相同的位置。

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

    在 iOS11 中如何加载一组动画以应用于其 SCNNode?​​p>

    你是怎么做到的,所以这些动画可以在模型上运行,无论模型在哪里(而不是将它捕捉到其他位置)?

【问题讨论】:

遇到完全相同的问题,我也尝试使用 SCNSceneSource 加载动画,但它不起作用。如果您找到任何解决方案,请告诉我 .dae 格式是否包含动画?我是否尝试过为此使用 Alembic (.abc)? 【参考方案1】:

首先我应该确认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(named: String)

另外我要补充一点,您不仅可以使用以.dae 文件格式烘焙的动画,还可以使用.abc.scn.usdz 格式的动画。

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

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

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

【讨论】:

嗨,安迪,请告诉我“walking”和“walk_version02”的名字是从哪里得到的?

以上是关于SceneKit - 如何获取 .dae 模型的动画?的主要内容,如果未能解决你的问题,请参考以下文章

如何创建要在 SceneKit 中使用的 DAE 文件?

如何使用 SceneKit 从 COLLADA (.dae) 文件中获取几何图形

在 SceneKit 中支持 Collada/DAE 模型都有哪些要求?

Scenekit:如何获取节点的所有材质?

SceneKit - 具有 DAE 文件格式的动画

如何在 iOS SceneKit 中使用具有不同场景图形的 DAE 文件