簡體   English   中英

如何從SceneKit中的Collada文件中分割出多個動畫

[英]How to split out multiple animations from Collada file in SceneKit

我將第三方.dae Collada文件作為場景加載到SceneKit項目中。

.dae文件中有許多不同的動畫,設置在不同的時間/幀。 我試圖弄清楚如何將這些分開並通過引用名稱引用每個單獨的動畫。 dae文件中沒有可理解的引用名稱 - 動畫都設置為單個動畫。

我能夠將動畫解析為CAAnimation對象,並使用以下代碼驗證我是否成功完成了此操作:

SCNScene *scene = [SCNScene sceneNamed:@"art.scnassets/man.dae"];
SCNNode *man = [scene.rootNode childNodeWithName:@"Bip01" recursively:YES];
CAAnimation *animation = [man animationForKey:@"test_Collada_DAE-1"];
[man removeAllAnimations];
[man addAnimation:animation forKey:@"animation"];

有沒有辦法為我的CAAnimation對象設置開始和結束幀或時間? 解析各種動畫的最佳方法是什么? 我希望我不必手動將dae文件拆分成多個並單獨加載每個文件。

3d工具通常將多個動畫導出為具有子動畫的單個動畫。 在這種情況下,SceneKit會將這些動畫加載為具有子動畫的CAAnimationGroup。 因此,一個選項是“解析”動畫組的子動畫並檢索所需的動畫。 另一種選擇是使用SCNSceneSource按名稱檢索(子)動畫(但這僅在您的3d工具導出DAE時導出名稱時才有效)。

如果您需要“裁剪”動畫(即從較長的動畫中提取以t0開頭且持續時間為D的動畫),CoreAnimation有一個API:

  • 創建一個動畫組以“裁剪”持續時間D.

  • 將要裁剪的動畫添加為子動畫,並將其timeOffset設置為t0。

正如Toyos在他的回答中提到的,使用SCNSceneSource枚舉CAAnimationGroup並檢索CAAnimation對象,如下所示:

NSURL *daeURL = [[NSBundle mainBundle] URLForResource:@"exportedFilename" withExtension:@"dae"];

SCNSceneSource *sceneSource = [SCNSceneSource sceneSourceWithURL:daeURL options:nil];

NSMutableArray *myAnimations = [@[] mutableCopy];

for (NSString *singleAnimationName in [sceneSource identifiersOfEntriesWithClass:[CAAnimation class]]) {
    CAAnimation *thisAnimation = [sceneSource entryWithIdentifier:singleAnimationName withClass:[CAAnimation class]];
    [myAnimations addObject:thisAnimation];
}

下面是將幀數轉換為時間的代碼,然后通過使用CAAnimationGroup作為@Toyos描述,僅播放動畫的那部分。 此示例代碼通過重復fullAnimation 10幀到第160幀來播放“空閑”動畫:

func playIdleAnimation() {
    let animation = subAnimation(of:fullAnimation, startFrame: 10, endFrame: 160)
    animation.repeatCount = .greatestFiniteMagnitude
    addAnimation(animation, forKey: "animation")
}

func subAnimation(of fullAnimation:CAAnimation, startFrame:Int, endFrame:Int) -> CAAnimation {
    let (startTime, duration) = timeRange(startFrame:startFrame, endFrame:endFrame)
    let animation = subAnimation(of: fullAnimation, offset: startTime, duration: duration)
    return animation
}

func subAnimation(of fullAnimation:CAAnimation, offset timeOffset:CFTimeInterval, duration:CFTimeInterval) -> CAAnimation {
    fullAnimation.timeOffset = timeOffset
    let container = CAAnimationGroup()
    container.animations = [fullAnimation]
    container.duration = duration
    return container
}

func timeRange(startFrame:Int, endFrame:Int) -> (startTime:CFTimeInterval, duration:CFTimeInterval) {
    let startTime = timeOf(frame:startFrame)
    let endTime = timeOf(frame:endFrame)
    let duration = endTime - startTime
    return (startTime, duration)
}

func timeOf(frame:Int) -> CFTimeInterval {
    return CFTimeInterval(frame) / framesPerSecond()
}

func framesPerSecond() -> CFTimeInterval {
    // number of frames per second the model was designed with
    return 30.0
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM