RealityKit – SwiftUI로 Reality Composer 장면로드
SwiftUI, RealityKit 및 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]
})
}
}
이것이 내가 그들을로드하는 방법이지만 카메라 뷰가 열리고 하나의 모델을로드하면 다른 모델은로드되지 않습니다. 누군가 나를 도울 수 있습니까?
답변
당신의 가치가 Binding
변경되면 SwiftUI는 당신의 updateUIView(_:,context:)
구현을 호출합니다 .
또한 AnyCancellable
. 에서 반환 된 토큰 sink
이 할당 해제되면 요청이 취소됩니다. 이로 인해 더 큰 모델을로드하려고 할 때 예기치 않은 오류가 발생할 수 있습니다.
이 두 가지 문제를 모두 해결하려면 Coordinator
. 수입 UIKit 수입 RealityKit 수입 SwiftUI 수입 결합 수입 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)
}
}
토큰 Coordinator
을 보유 하는 중첩 클래스를 만들고 함수를 . SwiftUI 이외 의는 A는 보기가 표시되는 생활 동안 (항상 SwiftUI 작성하고이 파괴 수 있음을 기억한다는 뜻에서, 수명주기가 화면에 표시되는 실제 "보기"와 관련이 없습니다).AnyCancellable
loadModel
Coordinator
View
Coordinator
class
View
loadModel
클래스 밖에서 Binding
우리는 SwiftUI가를 업데이트 할 때 View
, 예를 들어 환경의 변화로 인해 동일한 모델에 대한 지속적인 요청을 취소하지 않도록 우리의 값이 실제로 변경 되었는지 다시 확인 합니다.
그런 다음 객체 makeCoordinator
중 하나를 생성 하는 함수를 구현 Coordinator
합니다. 모두 makeUIView
와에 updateUIView
우리는 전화를 loadModel
우리에 기능을 Coordinator
.
이 dimantleUIView
방법은 선택 사항입니다. 때 Coordinator
해체됩니다 우리의 token
지속적인 요청을 취소하기로 결합 트리거되는 잘으로 출시됩니다.