You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 13:13:21