RealityKit - Memuat adegan Reality Composer dengan SwiftUI
Saya mencoba memuat model yang berbeda di wajah menggunakan SwiftUI, RealityKit dan ARKit.
struct AugmentedRealityView: UIViewRepresentable {
@Binding var modelName: String
func makeUIView(context: Context) -> ARView {
let arView = ARView(frame: .zero)
let configuration = ARFaceTrackingConfiguration()
arView.session.run(configuration, options: [.removeExistingAnchors,
.resetTracking])
loadModel(name: modelName, arView: arView)
return arView
}
func updateUIView(_ uiView: ARView, context: Context) { }
private func loadModel(name: String, arView: ARView) {
var cancellable: AnyCancellable? = nil
cancellable = ModelEntity.loadAsync(named: name).sink(
receiveCompletion: { loadCompletion in
if case let .failure(error) = loadCompletion {
print("Unable to load model: \(error.localizedDescription)")
}
cancellable?.cancel()
},
receiveValue: { model in
let faceAnchor = AnchorEntity(.face)
arView.scene.addAnchor(faceAnchor)
faceAnchor.addChild(model)
model.scale = [1, 1, 1]
})
}
}
Beginilah cara saya memuatnya tetapi ketika tampilan kamera terbuka dan memuat satu model maka model lainnya tidak akan dimuat. Bisakah seseorang membantu saya?
Jawaban
Ketika nilai Binding
perubahan Anda , SwiftUI memanggil updateUIView(_:,context:)
implementasi Anda , yang tidak mencatat.
Selain itu, Anda tidak menyimpan file AnyCancellable
. Ketika token yang dikembalikan oleh sink
dibatalkan alokasinya, permintaan akan dibatalkan. Itu bisa mengakibatkan kegagalan tak terduga saat mencoba memuat model lager.
Untuk memperbaiki kedua masalah ini, gunakan file Coordinator
. impor UIKit impor RealityKit impor SwiftUI impor Gabungkan impor ARKit
struct AugmentedRealityView: UIViewRepresentable {
class Coordinator {
private var token: AnyCancellable?
private var currentModelName: String?
fileprivate func loadModel(_ name: String, into arView: ARView) {
// Only load model if the name is different from the previous one
guard name != currentModelName else {
return
}
currentModelName = name
// This is optional
// When the token gets overwritten
// the request gets cancelled
// automatically
token?.cancel()
token = ModelEntity.loadAsync(named: name).sink(
receiveCompletion: { loadCompletion in
if case let .failure(error) = loadCompletion {
print("Unable to load model: \(error.localizedDescription)")
}
},
receiveValue: { model in
let faceAnchor = AnchorEntity(.camera)
arView.scene.addAnchor(faceAnchor)
faceAnchor.addChild(model)
model.scale = [1, 1, 1]
})
}
fileprivate func cancelRequest() {
token?.cancel()
}
}
@Binding var modelName: String
func makeCoordinator() -> Coordinator {
Coordinator()
}
static func dismantleUIView(_ uiView: ARView, coordinator: Coordinator) {
coordinator.cancelRequest()
}
func makeUIView(context: Context) -> ARView {
let arView = ARView(frame: .zero)
let configuration = ARFaceTrackingConfiguration()
arView.session.run(configuration, options: [.removeExistingAnchors,
.resetTracking])
context.coordinator.loadModel(modelName, into: arView)
return arView
}
func updateUIView(_ uiView: ARView, context: Context) {
context.coordinator.loadModel(modelName, into: uiView)
}
}
Kami membuat Coordinator
kelas bersarang yang menyimpan AnyCancellable
token dan memindahkan loadModel
fungsinya ke Coordinator
. Selain SwiftUI View
, Coordinator
is a class
yang hidup saat tampilan Anda terlihat (selalu ingat bahwa SwiftUI mungkin membuat dan menghancurkan View
sesuka Anda , siklus hidupnya tidak terkait dengan "tampilan" aktual yang ditampilkan di layar).
Di luar loadModel
kelas kami memeriksa ulang bahwa nilai kami Binding
benar - benar berubah sehingga kami tidak membatalkan permintaan yang sedang berlangsung untuk model yang sama ketika SwiftUI memperbarui kami View
, misalnya karena perubahan lingkungan.
Kemudian kami mengimplementasikan makeCoordinator
fungsi untuk membangun salah satu Coordinator
objek kami . Baik di dalam makeUIView
dan di dalam updateUIView
kami memanggil loadModel
fungsi di kami Coordinator
.
The dimantleUIView
metode adalah opsional. Ketika Coordinator
didekonstruksi, kami juga token
akan dirilis, yang akan memicu Gabungkan untuk membatalkan permintaan yang sedang berlangsung.