![](/img/trans.png)
[英]How to rotate a 3D model in a USDZ file programmatically in Swift?
[英]How to programmatically export 3D mesh as USDZ using ModelIO?
是否可以使用 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)
}
當我按下保存按鈕時,出現錯誤。
2021 年 6 月 24 日。
目前蘋果開發者可以使用canExportFileExtension(_:)類型方法導出.usd
、 .usda
和.usdc
文件:
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)
Andy Jazz 的答案是正確的,但需要修改才能在 SwiftUI 沙盒應用程序中工作:
首先,需要渲染 SCNScene 才能正確導出。 您不能創建一堆節點,將它們塞入場景的根節點並調用 write() 並獲得正確渲染的 usdz。 它必須首先放在 SwiftUI SceneView
的屏幕上,這會導致加載所有資產等。我想你可以實例化一個SCNRenderer
並在根節點上調用prepare()
,但這有一些額外的復雜性。
其次,沙盒阻止直接導出到.fileExporter()
提供的 URL。 這是因為Scene.write()
分兩步工作:它首先創建一個.usdc
導出,然后將生成的文件壓縮到一個.usdz
中。 中間文件沒有.fileExporter()
提供的 URL 的寫入權限(假設您已將沙盒“用戶選擇的文件”權限設置為“讀/寫”),因此Scene.write()
失敗,即使如果目標 URL 是可寫的,如果目標目錄在沙箱之外。
我的解決方案是編寫自定義 FileWrapper,如果 WriteConfiguration UTType 是 .usdz,我會返回它:
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)
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.