I am experimenting with an AR app. I am trying to do the following:
The iOS device displays the real scene by an ARView, and the ARView creates a mesh.
Whenever the mesh is updated, I want to find the vertex closest to the camera, and attach a virtual object to it (after deleting a possibly previously attached object).

我不确定我当前的代码是否正确,但它似乎做了我上面描述的事情.如果我移动设备,显示的网格将更新.当找到新的最近顶点时,它会切换MainView中的状态变量refreshToggle,我希望更新后的网格与虚拟对象一起显示.但虚拟物体没有显示,我不明白为什么.

这是我的代码.我很抱歉它这么长,但我不确定要省略什么. 欢迎任何帮助!

struct MainView : View {
    @State private var refreshToggle = false // Toggled, when a new closest anchor is found
    var body: some View {
        ARViewContainer(refreshToggle: $refreshToggle).edgesIgnoringSafeArea(.all)
    }
}

struct ARViewContainer: UIViewRepresentable {
    @Binding var refreshToggle: Bool
    
    func makeUIView(context: Context) -> ARView {
        let arView = ARView(frame: .zero)
        arView.environment.sceneUnderstanding.options = []
        arView.environment.sceneUnderstanding.options.insert(.occlusion) // Turn on occlusion from the scene reconstruction's mesh.
        arView.environment.sceneUnderstanding.options.insert(.physics) // Turn on physics for the scene reconstruction's mesh.
        arView.debugOptions.insert(.showSceneUnderstanding) // Display a debug visualization of the mesh.
        arView.renderOptions = [.disablePersonOcclusion, .disableDepthOfField, .disableMotionBlur] // Disable not required render options
        arView.session.delegate = context.coordinator
        return arView
    }
    
    func updateUIView(_ uiView: ARView, context: Context) {}
    
    func makeCoordinator() -> Coordinator {
        Coordinator($refreshToggle)
    }
    
    class Coordinator: NSObject, ARSessionDelegate {
        @Binding var refreshToggle: Bool
        var model: ModelEntity
        
        init(_ refreshToggle: Binding<Bool>) {
            self._refreshToggle = refreshToggle
            
            // Create a cube model
            let mesh = MeshResource.generateBox(size: 0.1, cornerRadius: 0.005)
            let material = SimpleMaterial(color: .gray, roughness: 0.15, isMetallic: true)
            model = ModelEntity(mesh: mesh, materials: [material])
        }
        
        func session(_ session: ARSession, didUpdate anchors: [ARAnchor]) {
            var closestAnchor: ARAnchor? = nil
            for anchor in anchors {
                if let meshAnchor = anchor as? ARMeshAnchor {
                    let meshGeometry = meshAnchor.geometry
                    let vertices = meshGeometry.vertices

                    // Search for the vertex closest to the camera and place there a virtual marker object
                    let nrVertices = vertices.count
                    var closestVertex = SIMD3<Float>(x: 0, y: .infinity, z: 0) 
                    for i in 0 ..< nrVertices {
                        let nextVertex = meshGeometry.vertex(at: UInt32(i))
                        if nextVertex.y < closestVertex.y {
                            closestVertex = nextVertex
                            if closestAnchor?.identifier != meshAnchor.identifier {
                                // A new closest anchor has been found. Remove a virtual marker object
                                if let closestAnchor = closestAnchor {
                                    let anchor = AnchorEntity(anchor: closestAnchor)
                                    anchor.children.remove(model)
                                }
                            }           
                            closestAnchor = meshAnchor
                        }
                    }           
                    
                    // If a closest vertex was found, attach a virtual object to it
                    if let closestAnchor = closestAnchor {
                        let anchor = AnchorEntity(anchor: closestAnchor)
                        anchor.children.append(model)
                        refreshToggle = !refreshToggle // Let ARViewContainer redisplay the real scene with the mesh and a virtual object attached to the closest anchor
                    }
                } // if an ARMeshAnchor was found
            } // for all anchors
        } // session didUpdate anchors
    } // coordinator
    
}

extension ARMeshGeometry { // See https://developer.apple.com/documentation/arkit/armeshgeometry/3516924-vertices
    func vertex(at index: UInt32) -> SIMD3<Float> {
        assert(vertices.format == MTLVertexFormat.float3, "Expected three floats (twelve bytes) per vertex.")
        let vertexPointer = vertices.buffer.contents().advanced(by: vertices.offset + (vertices.stride * Int(index)))
        let vertex = vertexPointer.assumingMemoryBound(to: SIMD3<Float>.self).pointee
        return vertex
    }
}

推荐答案

Problem solved, although I don't understand it (no experience in Computer Graphics).
After the closest mesh anchor has been found, one has to create an AnchorEntity.
In this entity, one has to set the anchoring property with an AnchoringComponent initialized with an appropriate AnchoringComponent.Target. Only then is the virtual object rendered in the scene.

以下代码适用于我,并且基于一些有价值的信息,即KFDoom(+1)、blog of Ethan Saadiatutorial of Ralf Ebert的答案.

Here is the updated code in case somebody wants to play with it.
The transform in .world(transform: transform) has been taken from a different version and turned out to be useful.

import ARKit
import RealityKit
import SwiftUI

struct MainView: View {
    var body: some View {
        ARViewContainer()
            .edgesIgnoringSafeArea(.all)
    }
}

struct ARViewContainer: UIViewRepresentable {
    
    func makeUIView(context: Context) -> ARView {
        let arView = ARView()
        
        // Configure the ARView to generate a mesh
        arView.environment.sceneUnderstanding.options = []
        
        // Turn on occlusion from the scene reconstruction's mesh.
        arView.environment.sceneUnderstanding.options.insert(.occlusion)
        
        // Turn on physics for the scene reconstruction's mesh.
        arView.environment.sceneUnderstanding.options.insert(.physics)
        
        // Display a debug visualization of the mesh.
        arView.debugOptions.insert(.showSceneUnderstanding)
        
        // For performance, disable render options that are not required for this app.
        arView.renderOptions = [.disablePersonOcclusion, .disableDepthOfField, .disableMotionBlur]
        arView.session.delegate = context.coordinator
        
        // Handle ARSession events via delegate
        context.coordinator.arView = arView
        arView.session.delegate = context.coordinator
        
        return arView
    }
    
    func updateUIView(_ uiView: ARView, context: Context) {}
    
    func makeCoordinator() -> Coordinator {
        Coordinator()
    }
    
    class Coordinator: NSObject, ARSessionDelegate {
        var model: ModelEntity
        weak var arView: ARView?
        
        override init() {
            // Create a cube model
            let boxMesh = MeshResource.generateBox(size: 0.1, cornerRadius: 0.005)
            let material = SimpleMaterial(color: .gray, roughness: 0.15, isMetallic: true)
            model = ModelEntity(mesh: boxMesh, materials: [material])

            super.init()
        }

        func session(_ session: ARSession, didUpdate anchors: [ARAnchor]) {
            var closestAnchor: ARAnchor? = nil
            guard let arView = arView else { return }
            
            // Create a single AnchorEntity instance
            var anchorEntity: AnchorEntity?
            
            for anchor in anchors {
                if let meshAnchor = anchor as? ARMeshAnchor {
                    let meshGeometry = meshAnchor.geometry
                    let vertices = meshGeometry.vertices
                    
                    // For debugging, we search for the vertex closest to the camera and place there a virtual marker object

                    let nrVertices = vertices.count
                    var closestVertex = SIMD3<Float>(x: 0, y: .infinity, z: 0) 
                    for i in 0 ..< nrVertices {
                        let nextVertex = meshGeometry.vertex(at: UInt32(i))
                        // The frontmost vertex has the largest z value, see https://developer.apple.com/documentation/scenekit/organizing_a_scene_with_nodes
                        if nextVertex.z > closestVertex.z {
                            closestVertex = nextVertex
                            if closestAnchor?.identifier != meshAnchor.identifier {
                                // A new closest anchor has been found. Remove the virtual marker object if it exists.
                                // If an anchorEntity already exists, remove it from the ARView's scene
                                if let existingAnchor = anchorEntity {
                                    existingAnchor.removeFromParent()
                                }
                            }           
                            closestAnchor = meshAnchor
                        }
                    }           
                    
                } // if an ARMeshAnchor found
            } // for all anchors
            
            // If a closest vertex was found, attach a virtual object to it
            if let closestAnchor = closestAnchor {
                // Create a new AnchorEntity and attach the model to it
                anchorEntity = AnchorEntity(anchor: closestAnchor)
                let transform = simd_float4x4([[0.96475136, 0.0, 0.26316252, 0.0], [0.0, 1.0, 0.0, 0.0], [-0.26316252, 0.0, 0.9647514, 0.0], [0.16189954, -0.25364277, -0.22894737, 1.0]])
                let anchoring = AnchoringComponent(.world(transform: transform))
                anchorEntity!.anchoring = anchoring
                anchorEntity!.addChild(model)
                arView.scene.anchors.append(anchorEntity!)
            }
        } // session didUpdate anchors
    } // coordinator
}

extension ARMeshGeometry { // See https://developer.apple.com/documentation/arkit/armeshgeometry/3516924-vertices
    func vertex(at index: UInt32) -> SIMD3<Float> {
        assert(vertices.format == MTLVertexFormat.float3, "Expected three floats (twelve bytes) per vertex.")
        let vertexPointer = vertices.buffer.contents().advanced(by: vertices.offset + (vertices.stride * Int(index)))
        let vertex = vertexPointer.assumingMemoryBound(to: SIMD3<Float>.self).pointee
        return vertex
    }
}

#Preview {
    MainView()
}

Ios相关问答推荐

由于代码签名时出错,无法在iOS设备上发布iOS Maui Build

SwiftUI绑定到特定的一个或多个枚举 case

如何在KMM项目中处理PHPickerViewController的回调?

将 Riverpod 从 StateNotifier 修复为 NotifierProvider 以及应用程序生命周期监控

NumberFormatter 无法使用 Xcode 15.0 beta 正确识别 iOS 17 beta 中的 Locale 货币设置

无法在 CollectionView 中禁用部分弹跳 - 组合布局

使用 AVCaptureDeviceTypeBuiltInTripleCamera 时 Select 合适的相机进行条码扫描

Flutter firebase_auth 中的无效应用程序凭据/令牌不匹配

发生异常:需要 issuerId

SwiftUI:如何为 ScrollView 制作可拉伸(灵活)的粘性标题?

撤销 Apple 登录令牌以进行帐户删除过程

iOS SwiftUI - 从以前的 struct 调用函数

从父母到子元素的 Swift Pass 事件

如何阻止图像在 UIImageView 中拉伸?

检测 iPhone/iPad/iPod touch 的 colored颜色 ?

如何以编程方式调用视图控制器?

~= Swift 中的运算符

如何使用 swift 添加速率按钮的链接?

在 iOS 上编写文件

在 iOS 上没有显示数字键盘