I'm implementin ARKit and RealityKit, from ARKit I need the estimated light and that value has to goes back to the swiftui view. But as I'm doing each time the swiftui view is redrawn also in the UIViewRepresentable the delegate call updateUIView method. I'm wondering if there's a way to make it not calling the updateUIView method also because the value is written by ARKit and the SwiftUI view doesn't has to modify it.
Here the actual code
struct ARViewContainer : UIViewRepresentable {
@Binding var light: Float
@Binding var objectToPlace: ObjectModel?
@Binding var visualizationMode: VisualizationMode
func makeUIView(context: Context) -> ARView {
print("makeUIView")
let arView = CustomArView(frame: .zero)
context.coordinator.view = arView
arView.session.delegate = context.coordinator
return arView
}
//SwiftUI to UIKit
func updateUIView(_ uiView: ARView, context: Context) {
print("updateUIView")
if visualizationMode == .model {
print("updateUIView")
uiView.session.pause()
uiView.session.delegate = nil
uiView.scene.anchors.removeAll()
uiView.removeFromSuperview()
uiView.window?.resignKey()
}
if let model = self.objectToPlace {
if let anchor = uiView.scene.anchors.first(where: { $0.name == "default" }) {
print("removing all")
anchor.children.removeAll(preservingWorldTransforms: false)
}
if let modelEntity = model.entity {
modelEntity.transform.rotation = simd_quatf(real: 1.0, imag: SIMD3<Float>(0.0, 0.0, 0.0))
modelEntity.transform.translation = SIMD3<Float>(0.0, 0.0, 0.0)
modelEntity.transform.scale = SIMD3<Float>(0.01, 0.01, 0.01)
let anchorEntity = AnchorEntity(plane: .horizontal)
anchorEntity.name = "default"
anchorEntity.addChild(modelEntity)
modelEntity.generateCollisionShapes(recursive: true)
uiView.installGestures([.scale, .rotation], for: modelEntity)
uiView.scene.addAnchor(anchorEntity)
} else {
print("not to position")
}
}
}
func makeCoordinator() -> Coordinator {
return Coordinator(light: $light, objectToPlace: $objectToPlace)
}
//UIKit to SwiftUI
class Coordinator: NSObject, ARSessionDelegate {
var view: ARView?
@Binding var light: Float
@Binding var objectToPlace: ObjectModel?
init(light: Binding<Float>, objectToPlace: Binding<ObjectModel?>) {
self._light = light
self._objectToPlace = objectToPlace
}
func session(_ session: ARSession, didUpdate frame: ARFrame) {
light = Float(frame.lightEstimate?.ambientIntensity ?? 0.0)
if let view {
for anchor in view.scene.anchors {
if anchor.name == "default" {
print("trovato")
if !anchor.children.isEmpty {
objectToPlace = nil
}
}
}
}
}
func session(_ session: ARSession, didUpdate anchors: [ARAnchor]) {
}
func sessionShouldAttemptRelocalization(_ session: ARSession) -> Bool {
return false
}
}
}
class CustomArView: ARView {
var focusSquare: FocusEntity?
required init(frame frameRect: CGRect) {
super.init(frame: frameRect)
focusSquare = FocusEntity(on: self, style: .classic(color: .yellow))
focusSquare?.delegate = self
focusSquare?.setAutoUpdate(to: true)
self.setupARView()
}
@MainActor required dynamic init?(coder decoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setupARView() {
let config = ARWorldTrackingConfiguration()
config.planeDetection = .horizontal
config.environmentTexturing = .automatic
config.isLightEstimationEnabled = true
if ARWorldTrackingConfiguration.supportsSceneReconstruction(.mesh) {
config.sceneReconstruction = .mesh
}
self.session.run(config)
}
}
and in swiftui
ARViewContainer(light: $vm.light, objectToPlace: $objectToPlace, visualizationMode: $visualizationMode)
the vm.light come from the view model that contains the Published variable
thanks