如何将SCNAnimationPlayer"裁剪"为特定的开始和结束时间,iOS 11

Aut*_*Tec 6 animation scenekit ios11 xcode9-beta arkit

我有一个带有长动画的.dae模型.动画包括步行,跑步,击球,死亡等部分.我知道每个部分的开始和结束的帧数.我也知道每秒帧速率.因此,获取每个细分的开始和结束时间非常简单.

我可以将完整的动画作为SCNAnimationPlayer对象.我一直在尝试的是制作完整动画的副本,然后设置动画的timeOffset和持续时间.

let walkPlayer = fullPlayer.copy() as! SCNAnimationPlayer
walkPlayer.stop()
walkPlayer.animation.timeOffset = walk.offset
walkPlayer.animation.duration = walk.duration
Run Code Online (Sandbox Code Playgroud)

然后我将walkPlayer添加回Bip01节点(我从中获得了完整的动画).

我可以通过调用animationPlayer(forKey:"walk")来轻松地完成游戏.?play()

我可以很容易地改变动画的持续时间和其他方面.但是动画总是从第0帧开始.无论我放入什么值.timeOffset,它都会被忽略.

如何从SCNAnimationPlayer中的SCNAnimation的起始帧到结束帧进行播放?

Aut*_*Tec 7

关键是寻找

CAAnimation(scnAnimation: animation)
Run Code Online (Sandbox Code Playgroud)

SCNAnimation(caAnimation: animation)
Run Code Online (Sandbox Code Playgroud)

一旦我找到了这些,我就可以使用CAAnimationGroup来"裁剪"完整的动画.

这是我正在研究的Troll.swift.当然,有很多工作要做,但现在我至少可以让可怜的野兽走路而死.

class Troll: SCNNode {
    var body:SCNNode!

    static func timeRange(forStartingAtFrame start:Int, endingAtFrame end:Int, fps:Double = 30) -> (offset:TimeInterval, duration:TimeInterval) {
        let startTime   = self.time(atFrame: start, fps: fps) //TimeInterval(start) / fps
        let endTime     = self.time(atFrame: end, fps: fps) //TimeInterval(end) / fps
        return (offset:startTime, duration:endTime - startTime)
    }

    static func time(atFrame frame:Int, fps:Double = 30) -> TimeInterval {
        return TimeInterval(frame) / fps
    }

    static func animation(from full:CAAnimation, startingAtFrame start:Int, endingAtFrame end:Int, fps:Double = 30) -> CAAnimation {
        let range = self.timeRange(forStartingAtFrame: start, endingAtFrame: end, fps: fps)
        let animation = CAAnimationGroup()
        let sub = full.copy() as! CAAnimation
        sub.timeOffset = range.offset
        animation.animations = [sub]
        animation.duration = range.duration
        return animation
    }


    func load() {

        guard let trollScene = SCNScene(named: "Models.scnassets/troll/troll.dae") else {
            fatalError("Can't load the scene")
        }

        guard let troll_body = trollScene.rootNode.childNode(withName: "troll", recursively: true) else {
            fatalError( "found no troll")
        }

        guard let troll_weapon = trollScene.rootNode.childNode(withName: "troll_weapon", recursively: true) else {
            fatalError( "found no troll_weapon")
        }

        guard let troll_bracelet = trollScene.rootNode.childNode(withName: "troll_bracelet", recursively: true) else {
            fatalError( "found no troll_bracelet")
        }

        guard let bips = trollScene.rootNode.childNode(withName: "Bip01", recursively: true) else {
            fatalError( "found no Bip01")
        }

        guard let fullKey = bips.animationKeys.first else {
            fatalError( "Bip01 got no animation")
        }

        guard let fullPlayer = bips.animationPlayer(forKey: fullKey) else {
            fatalError( "Bip01 got no player for \(fullKey)")
        }
        let fullAnimation = CAAnimation(scnAnimation: fullPlayer.animation)

        self.addChildNode(troll_body)
        self.addChildNode(troll_weapon)
        self.addChildNode(troll_bracelet)
        self.addChildNode(bips)

        self.body = bips
        self.body.removeAllAnimations()

        let walkAnimation = Troll.animation(from: fullAnimation, startingAtFrame: 10, endingAtFrame: 60)
        walkAnimation.repeatCount = .greatestFiniteMagnitude
        walkAnimation.fadeInDuration = 0.3
        walkAnimation.fadeOutDuration = 0.3
        let walkPlayer = SCNAnimationPlayer(animation: SCNAnimation(caAnimation: walkAnimation))
        self.body.addAnimationPlayer(walkPlayer, forKey: "walk")

        let deathAnimation = Troll.animation(from: fullAnimation, startingAtFrame: 1810, endingAtFrame: 1850)
        deathAnimation.isRemovedOnCompletion = false
        deathAnimation.fadeInDuration = 0.3
        deathAnimation.fadeOutDuration = 0.3
        let deathPlayer = SCNAnimationPlayer(animation: SCNAnimation(caAnimation: deathAnimation))
        self.body.addAnimationPlayer(deathPlayer, forKey: "death")

        self.scale     = SCNVector3(0.1,0.1,0.1)

    }

    func walk() {
        print( "+++ walk +++" )
        self.body.animationPlayer(forKey: "walk")?.play()
    }

    func death() {
        print( "+++ death +++" )
        self.body.animationPlayer(forKey: "walk")?.stop(withBlendOutDuration: 0.3)
        self.body.animationPlayer(forKey: "death")?.play()
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 感谢您发布解决方案。我对SCNAnimationPlayer本身不支持更细粒度的播放/传输控件本身感到有些失望。希望这会在将来的iOS版本中出现。 (2认同)