Cómo dividir varias animaciones del file Collada en SceneKit

Estoy cargando un file .dae Collada de un tercero como una escena en un proyecto de SceneKit.

El file .dae tiene muchas animaciones diferentes, configuradas en diferentes times / cuadros. Estoy intentando descubrir cómo puedo dividirlos y hacer reference a cada animation individual por nombre de reference. No hay nombres de reference inteligibles en el file dae: las animaciones están todas configuradas como una única animation.

Puedo analizar las animaciones en un object CAAnimation y verificar que lo he hecho con éxito con el siguiente código:

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"]; 

¿Hay alguna forma de establecer un marco o time de inicio y finalización en mi object CAAnimation? ¿Cuál es la mejor manera de analizar las diferentes animaciones? Espero que no tenga que dividir manualmente el file dae en muchos y cargar cada uno individualmente.

Las herramientas 3D a menudo exportan varias animaciones como una única animation con sub animaciones. En ese caso, SceneKit cargará estas animaciones como un CAAnimationGroup con sub animaciones. Entonces, una opción es "analizar" las sub animaciones del grupo de animation y recuperar las que desee. Otra opción es recuperar (sub) animaciones por nombre usando SCNSceneSource (pero esto solo funcionará si su herramienta 3D exportó nombres cuando exportó su DAE).

Si necesita "recortar" la animation (es decir, extraer una animation que comienza en t0 con la duración D de una animation más larga), CoreAnimation tiene una API para eso:

  • crear un grupo de animation para "recortar" con la duración D.

  • agregue la animation que desea recortar como sub-animation y configure su time de respuesta en t0.

Como Toyos mencionó en su respuesta, enumere el CAAnimationGroup utilizando SCNSceneSource y recupere los objects CAAnimation siguiente manera:

 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]; } 

Aquí hay un código que convierte los numbers de fotogtwigs a veces y luego reproduce solo esa parte de la animation mediante un CAAnimationGroup como @Toyos descrito. Este código de ejemplo reproduce una animation "inactiva" al repetir los cuadros 10 a 160 de fullAnimation :

 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 }