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类,其中包含AnyCancellable令牌,并将loadModel函数移到Coordinator中。 除了SwiftUI View之外,Coordinator是一个class,它在您的视图可见时仍然存在(始终记住,SwiftUI可能会随意创建和销毁您的View,生命周期与屏幕上显示的实际“视图”无关。

loadModel类的内部,我们再次检查Binding的值是否实际更改,以便在SwiftUI更新View时我们不会取消对同一模型的正在进行的请求,例如因为环境的变化。

然后,我们实现makeCoordinator函数来构造我们的Coordinator对象之一。 在makeUIViewupdateUIView中,我们都在loadModel上调用Coordinator函数。

dimantleUIView方法是可选的。当Coordinator被解构时,我们的token也将被释放,这将触发Combine取消正在进行的请求。

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...