iOS SceneKit无法完整播放从Sketchfab导入的3D动画资源
问题:SceneKit播放Sketchfab导入的3D动画仅部分播放即停止
从Sketchfab下载的3D动画资源导入Xcode后,在Xcode内置3D编辑器中能完整正常播放,但通过SceneKit的animationPlayer实现播放时,动画仅运行部分内容就停止,无法完整播放全程或循环。
实现代码
struct SceneKitView: UIViewRepresentable { func makeUIView(context: Context) -> SCNView { let view = SCNView() view.allowsCameraControl = false view.autoenablesDefaultLighting = true view.antialiasingMode = .multisampling2X view.backgroundColor = .clear if let scene = SCNScene(named: "Purple_Lightning_Rainstorm.scn") { playAnimationKeys(for: scene.rootNode) view.scene = scene } else { print("Failed to load the scene.") } return view } func updateUIView(_ uiView: SCNView, context: Context) { } func playAnimationKeys(for node: SCNNode) { let animationKeys = node.animationKeys for key in animationKeys { print("Node: \(node.name ?? "Unnamed"), Animation Key: \(key)") if let animationPlayer = node.animationPlayer(forKey: key) { animationPlayer.play() } else { print(" -> No Animation Player found for key \(key)") } } for child in node.childNodes { playAnimationKeys(for: child) } }}
现象对比
- Xcode编辑器效果:动画完整循环,所有帧均正常展示
- 实际代码播放效果:动画仅执行前几帧就停止,后续动画内容无法触发
修复方案
1. 强制设置动画循环模式
Sketchfab导出的动画默认可能未配置循环,Xcode编辑器会自动处理循环逻辑,但代码中需手动指定:
修改playAnimationKeys中的播放逻辑:
if let animationPlayer = node.animationPlayer(forKey: key) { // 设置无限循环,若需单次完整播放可设为1 animationPlayer.animation.repeatCount = .infinity animationPlayer.play() }
2. 调整动画触发时机
场景加载后立即播放可能导致部分动画资源未初始化完成,可借助Coordinator跟踪首次加载状态,在updateUIView中触发播放:
struct SceneKitView: UIViewRepresentable { class Coordinator: NSObject { var hasPlayedAnimation = false } func makeCoordinator() -> Coordinator { Coordinator() } func makeUIView(context: Context) -> SCNView { let view = SCNView() view.allowsCameraControl = false view.autoenablesDefaultLighting = true view.antialiasingMode = .multisampling2X view.backgroundColor = .clear if let scene = SCNScene(named: "Purple_Lightning_Rainstorm.scn") { view.scene = scene } else { print("Failed to load the scene.") } return view } func updateUIView(_ uiView: SCNView, context: Context) { guard !context.coordinator.hasPlayedAnimation, let scene = uiView.scene else { return } playAnimationKeys(for: scene.rootNode) context.coordinator.hasPlayedAnimation = true } func playAnimationKeys(for node: SCNNode) { let animationKeys = node.animationKeys for key in animationKeys { if let animationPlayer = node.animationPlayer(forKey: key) { animationPlayer.animation.repeatCount = .infinity animationPlayer.play() } } node.childNodes.forEach { playAnimationKeys(for: $0) } } }
3. 检查动画节点遍历完整性
查看控制台打印的动画Key,确认是否所有需要的动画都被触发。若存在遗漏,可手动定位目标节点播放:
// 在场景加载后添加: if let targetNode = scene.rootNode.childNode(withName: "YourTargetNodeName", recursively: true) { playAnimationKeys(for: targetNode) }
4. 启用视图自动驱动动画
开启SCNView的isPlaying属性,让视图自动管理动画时钟:
let view = SCNView() view.isPlaying = true // 添加此行 // ...其他视图配置
内容的提问来源于stack exchange,提问作者Godofsleepy
相关产品推荐
相关产品推荐

