场景图(SceneKit) - 如何获取 .dae 模型的动画?

8

好的,我在这里与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模型-

  1. iOS11中如何加载一组要应用于它们的SCNNode的动画?

  2. 如何使这些动画在无论模型在哪里都能运行(不将其直接定位到其他位置)?


我也遇到了完全相同的问题,尝试使用SCNSceneSource加载动画,但是没有成功。如果您找到任何解决方案,请告诉我。 - Claus
.dae格式是否包含动画?你尝试使用Alembic (.abc)格式了吗? - drewster
1个回答

1
首先,我应该确认在iOS和macOS中,CoreAnimation框架及其一些方法(如实例方法animation(forKey:))已经被弃用。但是,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)
}

1
嗨,安迪,请告诉我“walking”和“walk_version02”的名称是从哪里得来的? - Anurag Sharma

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接