如何将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
相关产品推荐
相关产品推荐

