如何使用ModelIO以编程方式将三维网格导出为USDZ



是否可以使用ModelIO和MetalKit框架以编程方式将3D网格导出为.usdz文件格式?

这是一个代码:

import ARKit
import RealityKit
import MetalKit
import ModelIO
let asset = MDLAsset(bufferAllocator: allocator)
asset.add(mesh)
let filePath = FileManager.default.urls(for: .documentDirectory, 
in: .userDomainMask).first!

let usdz: URL = filePath.appendingPathComponent("model.usdz")
do {
try asset.export(to: usdz)               
let controller = UIActivityViewController(activityItems: [usdz], 
applicationActivities: nil)
controller.popoverPresentationController?.sourceView = sender
self.present(controller, animated: true, completion: nil)
} catch let error {
fatalError(error.localizedDescription)
}

当我按下保存按钮时,我会收到一个错误。

Andy Jazz的答案是正确的,但需要修改才能在SwiftUI Sandboxed应用程序中工作:

首先,需要渲染SCNScene才能正确导出。您不能创建一堆节点,将它们填充到场景的根节点中,然后调用write((并获得正确渲染的usdz。它必须首先放在SwiftUISceneView的屏幕上,这会导致加载所有资产,等等。我想你可以实例化一个SCNRenderer并在根节点上调用prepare(),但这会带来一些额外的复杂性。

其次,沙盒阻止直接导出到.fileExporter()提供的URL。这是因为Scene.write()分为两个步骤:它首先创建一个.usdc导出,并将生成的文件压缩为一个单独的.usdz。中间文件没有.fileExporter()提供的URL所具有的写入权限(假设您已将沙盒"用户选择的文件"权限设置为"读/写"(,因此即使目标URL是可写的,如果目标目录在沙盒之外,Scene.write()也会失败。

我的解决方案是编写一个自定义的FileWrapper,如果WriteConfiguration UTType是.usz:,我会返回它

public class USDZExportFileWrapper: FileWrapper {
var exportScene: SCNScene
public init(scene: SCNScene) {
exportScene = scene
super.init(regularFileWithContents: Data())
}
required init?(coder inCoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override public func write(to url: URL,
options: FileWrapper.WritingOptions = [],
originalContentsURL: URL?) throws {
let tempFilePath = NSTemporaryDirectory() + UUID().uuidString + ".usdz"
let tempURL = URL(fileURLWithPath: tempFilePath)
exportScene.write(to: tempURL, delegate: nil)
try FileManager.default.moveItem(at: tempURL, to: url)
}
}

ReferenceFileDocument:中的使用

public func fileWrapper(snapshot: Data, configuration: WriteConfiguration) throws -> FileWrapper {
if configuration.contentType == .usdz {
return USDZExportFileWrapper(scene: scene)
}
return .init(regularFileWithContents: snapshot)
}

2023年1月8日

目前iOS开发者仍然只能导出.usd.usda.usdc文件;您可以使用canExportFileExtension(_:(类型的方法进行检查:

let usd = MDLAsset.canExportFileExtension("usd")
let usda = MDLAsset.canExportFileExtension("usda")
let usdc = MDLAsset.canExportFileExtension("usdc")
let usdz = MDLAsset.canExportFileExtension("usdz")

print(usd, usda, usdc, usdz)

它打印:

true true true false

但是,您可以使用名为:write(to:options:delegate:progressHandler:)的实例方法轻松地将SceneKit的场景导出为.usdz文件。

let path = FileManager.default.urls(for: .documentDirectory,
in: .userDomainMask)[0]
.appendingPathComponent("file.usdz")

sceneKitScene.write(to: path, 
options: nil, 
delegate: nil, 
progressHandler: nil)

最新更新