You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI中ARViewRepresentable绑定虚拟物体后无法显示求助

ARKit虚拟物体不显示的问题修复

核心问题分析

你的代码存在几个关键逻辑错误,导致虚拟物体无法显示:

  • AnchorEntity未加入AR场景:创建AnchorEntity后从未将其添加到ARView的场景中,模型自然不会被渲染。
  • 最近顶点判断逻辑错误:用顶点y坐标判断是否靠近摄像头完全不合理,应该计算顶点到摄像头的欧氏距离(用距离平方优化性能)。
  • 模型管理逻辑混乱:重复创建新的AnchorEntity绑定模型,且移除模型时操作的是新创建的空Anchor,而非已加入场景的实例。
  • refreshToggle无效:updateUIView方法为空,切换状态变量不会触发任何ARView更新操作,完全没必要保留。

修正后的完整代码

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

struct ARViewContainer: UIViewRepresentable {
    func makeUIView(context: Context) -> ARView {
        let arView = ARView(frame: .zero)
        // 开启场景重建相关选项
        arView.environment.sceneUnderstanding.options = [.occlusion, .physics]
        arView.debugOptions.insert(.showSceneUnderstanding)
        arView.renderOptions = [.disablePersonOcclusion, .disableDepthOfField, .disableMotionBlur]
        arView.session.delegate = context.coordinator
        // 将协调器的ARView引用初始化
        context.coordinator.arView = arView
        return arView
    }
    
    func updateUIView(_ uiView: ARView, context: Context) {}
    
    func makeCoordinator() -> Coordinator {
        Coordinator()
    }
    
    class Coordinator: NSObject, ARSessionDelegate {
        weak var arView: ARView?
        private var currentAnchorEntity: AnchorEntity?
        private let model: ModelEntity
        
        init() {
            // 创建立方体模型
            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])
            super.init()
        }
        
        func session(_ session: ARSession, didUpdate anchors: [ARAnchor]) {
            guard let arView = arView else { return }
            
            var closestVertex: SIMD3<Float>?
            var closestMeshAnchor: ARMeshAnchor?
            let cameraTransform = arView.cameraTransform
            
            // 遍历所有网格锚点,寻找离摄像头最近的顶点
            for anchor in anchors {
                guard let meshAnchor = anchor as? ARMeshAnchor else { continue }
                let meshGeometry = meshAnchor.geometry
                
                for i in 0..<meshGeometry.vertices.count {
                    let vertex = meshGeometry.vertex(at: UInt32(i))
                    // 将顶点坐标转换为世界空间
                    let worldVertex = meshAnchor.transform * SIMD4(vertex, 1.0).xyz
                    // 计算顶点到摄像头的距离平方(避免开根号,优化性能)
                    let distanceSquared = distance_squared(worldVertex, cameraTransform.translation)
                    
                    if closestVertex == nil || distanceSquared < distance_squared(closestVertex!, cameraTransform.translation) {
                        closestVertex = worldVertex
                        closestMeshAnchor = meshAnchor
                    }
                }
            }
            
            // 更新虚拟物体位置
            guard let closestVertex = closestVertex, let closestMeshAnchor = closestMeshAnchor else { return }
            
            // 移除旧的锚点和模型
            currentAnchorEntity?.removeFromParent()
            
            // 创建新的锚点,将模型定位到最近顶点
            let anchorEntity = AnchorEntity(anchor: closestMeshAnchor)
            // 调整模型位置到顶点坐标(相对于锚点的本地空间)
            model.position = closestVertex - closestMeshAnchor.transform.translation
            anchorEntity.addChild(model)
            // 将锚点加入AR场景
            arView.scene.addAnchor(anchorEntity)
            currentAnchorEntity = anchorEntity
        }
    }
}

extension ARMeshGeometry {
    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
    }
}

关键修改说明

  1. 移除无效的refreshToggle:删除了无意义的状态变量,因为updateUIView没有任何更新逻辑。
  2. 添加ARView引用到协调器:让协调器能够直接操作AR场景,将AnchorEntity加入到场景中。
  3. 修正最近顶点判断逻辑:计算顶点到摄像头的距离平方,同时将顶点坐标转换为世界空间,确保距离计算准确。
  4. 统一模型与锚点管理:用currentAnchorEntity保存当前绑定的锚点实例,更新时先移除旧锚点,再创建新锚点并加入场景。
  5. 调整模型本地位置:将模型的位置设置为相对于网格锚点的本地坐标,确保模型准确附着在目标顶点上。

内容的提问来源于stack exchange,提问作者Reinhard Männer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 15:36:35