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 } }
关键修改说明
- 移除无效的refreshToggle:删除了无意义的状态变量,因为
updateUIView没有任何更新逻辑。 - 添加ARView引用到协调器:让协调器能够直接操作AR场景,将
AnchorEntity加入到场景中。 - 修正最近顶点判断逻辑:计算顶点到摄像头的距离平方,同时将顶点坐标转换为世界空间,确保距离计算准确。
- 统一模型与锚点管理:用
currentAnchorEntity保存当前绑定的锚点实例,更新时先移除旧锚点,再创建新锚点并加入场景。 - 调整模型本地位置:将模型的位置设置为相对于网格锚点的本地坐标,确保模型准确附着在目标顶点上。
内容的提问来源于stack exchange,提问作者Reinhard Männer
相关产品推荐
相关产品推荐

