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

如何将Data对象加载到SCNScene?USDZ加载异常排查

问题

我想要将3D USDZ二进制数据加载到视图中,但仅持有Data对象,尝试通过SCNSceneSource初始化场景却未能成功。使用URL直接加载该USDZ文件可正常生成SCNScene,但使用同一URL读取的Data对象加载则失败。苹果文档指出数据应为NSData类型,但这似乎存在问题。以下是Playground中的代码及报错信息:

import SceneKit

let url = URL(string: "file:///Users/thilo/Desktop/Input/UU2.usdz")!
// working
let src_ok = SCNSceneSource(url: url)
let scn_ok = src_ok?.scene(options: nil, statusHandler: {
    a,b,c,d in print("OK: \(a) \(b) \(String(describing: c)) \(d) ")
})
print("Ok: \(scn_ok)")

// Not working?
let data    = try! Data(contentsOf: url)
let src_bad = SCNSceneSource(data: data)
let scn_bad = src_bad?.scene(options: nil, statusHandler: {
    a,b,c,d in print("BAD: \(a) \(b) \(String(describing: c)) \(d) ")
})
print("Failed: \(scn_bad)")

运行输出:

Ok: Optional(<SCNScene: 0x6000038e1200>)
BAD: 0.0 SCNSceneSourceStatus(rawValue: 4) nil 0x000000016fa948bf 
BAD: 0.0 SCNSceneSourceStatus(rawValue: 4) nil 0x000000016fa942af 
BAD: 0.0 SCNSceneSourceStatus(rawValue: -1) Optional(Error Domain=NSCocoaErrorDomain Code=260 "Could not load the scene" UserInfo={NSLocalizedDescription=Could not load the scene, NSLocalizedRecoverySuggestion=An error occurred while parsing the COLLADA file. Please check that it has not been corrupted.}) 0x000000016fa942af 
Failed: nil
解决方案

问题核心在于USDZ是基于Zip的压缩包格式:

  • 通过URL加载时,SCNSceneSource能通过文件扩展名识别出这是USDZ文件,自动处理压缩包解压逻辑,读取内部3D资源。
  • 直接传入Data对象时,没有文件扩展名这类上下文信息,SCNSceneSource会默认尝试把二进制数据当作单个COLLADA(.dae)文件解析,因此失败。

修复方法是初始化SCNSceneSource时,通过options参数手动指定数据的文件类型为.usdz:

import SceneKit

let url = URL(string: "file:///Users/thilo/Desktop/Input/UU2.usdz")!
// 正常工作的URL加载方式
let src_ok = SCNSceneSource(url: url)
let scn_ok = src_ok?.scene(options: nil, statusHandler: {
    a,b,c,d in print("OK: \(a) \(b) \(String(describing: c)) \(d) ")
})
print("Ok: \(scn_ok)")

// 修复后的Data加载方式
let data = try! Data(contentsOf: url)
// 指定文件类型为USDZ
let options = [SCNSceneSource.LoadingOption.fileType: SCNFileType.usdz.rawValue]
let src_fixed = SCNSceneSource(data: data, options: options)
let scn_fixed = src_fixed?.scene(options: nil, statusHandler: {
    a,b,c,d in print("FIXED: \(a) \(b) \(String(describing: c)) \(d) ")
})
print("Fixed: \(scn_fixed)")

这样SCNSceneSource就会正确识别Data是USDZ压缩包,执行对应的解压和加载逻辑,即可成功生成SCNScene。

内容的提问来源于stack exchange,提问作者thilo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 15:35:50