基于RealityKit的墙面表面积检测技术实现问询
结合RealityKit与SwiftUI实现墙面测量与选中功能方案
入门学习路径
- 优先啃Apple官方RealityKit文档,重点掌握
AnchorEntity、ModelEntity、ARView核心类,以及ARWorldTrackingConfiguration的平面检测配置逻辑。 - 观看WWDC相关Session:WWDC20的「RealityKit Essentials」、WWDC21的「Build apps with RealityKit 2」,这些是官方出品的实操指南,能快速建立AR开发的基础认知。
- 先从最小Demo练手:先实现「在AR场景中放置3D模型」,再逐步添加平面检测、手势交互,最后过渡到距离测量和选中效果的开发。
可修改的核心功能示例代码
以下代码实现了基础的AR视图集成、手动放置角落标记、距离计算、选中标记变色的功能,你可以根据需求扩展:
import SwiftUI import RealityKit import ARKit struct ARWallMeasuringView: View { @State private var arView = ARView(frame: .zero) @State private var placedMarkers: [AnchorEntity] = [] @State private var selectedMarker: AnchorEntity? var body: some View { ZStack { ARViewWrapper(arView: $arView, markers: $placedMarkers, selectedMarker: $selectedMarker) VStack { Spacer() HStack(spacing: 40) { Button(action: placeCornerMarker) { Image(systemName: "plus.circle.fill") .font(.system(size: 40)) .foregroundColor(.white) .shadow(radius: 5) } Button(action: calculateWallArea) { Image(systemName: "calculator.fill") .font(.system(size: 40)) .foregroundColor(.white) .shadow(radius: 5) } } .padding(.bottom, 30) } } } // 放置角落标记点 private func placeCornerMarker() { guard let raycastResult = arView.session.raycast( arView.makeRaycastQuery(from: arView.center, allowing: .estimatedPlane, alignment: .vertical) ).first else { return } let markerAnchor = AnchorEntity(raycastResult: raycastResult) let markerModel = ModelEntity( mesh: MeshResource.generateSphere(radius: 0.02), materials: [SimpleMaterial(color: .red, isMetallic: true)] ) markerAnchor.addChild(markerModel) arView.scene.addAnchor(markerAnchor) placedMarkers.append(markerAnchor) } // 计算墙面表面积(简化版:取前两个标记点的距离作为宽度,从平面锚点获取高度) private func calculateWallArea() { guard placedMarkers.count >= 2 else { print("至少需要放置2个标记点") return } let marker1 = placedMarkers[0] let marker2 = placedMarkers[1] let width = simd_distance(marker1.position, marker2.position) guard let planeAnchor = marker1.anchor as? ARPlaneAnchor else { print("未检测到平面锚点") return } let height = planeAnchor.extent.y let area = width * height print("墙面表面积:\(String(format: "%.2f", area)) 平方米") } } // SwiftUI与ARView的桥接容器 struct ARViewWrapper: UIViewRepresentable { @Binding var arView: ARView @Binding var markers: [AnchorEntity] @Binding var selectedMarker: AnchorEntity? func makeUIView(context: Context) -> ARView { let config = ARWorldTrackingConfiguration() config.planeDetection = [.vertical] // 重点检测垂直墙面 arView.session.run(config) // 添加点击选中手势 let tapGesture = UITapGestureRecognizer(target: context.coordinator, action: #selector(Coordinator.handleTap)) arView.addGestureRecognizer(tapGesture) return arView } func updateUIView(_ uiView: ARView, context: Context) {} func makeCoordinator() -> Coordinator { Coordinator(self) } class Coordinator: NSObject { var parent: ARViewWrapper init(_ parent: ARViewWrapper) { self.parent = parent } @objc func handleTap(_ gesture: UITapGestureRecognizer) { let location = gesture.location(in: parent.arView) guard let hitEntity = parent.arView.entity(at: location) else { return } // 找到标记点对应的锚实体 guard let markerAnchor = hitEntity.anchor as? AnchorEntity else { return } if parent.selectedMarker == markerAnchor { // 取消选中,恢复红色 if let model = markerAnchor.children.first as? ModelEntity { model.model?.materials = [SimpleMaterial(color: .red, isMetallic: true)] } parent.selectedMarker = nil } else { // 重置之前选中的标记点颜色 if let prevSelected = parent.selectedMarker, let prevModel = prevSelected.children.first as? ModelEntity { prevModel.model?.materials = [SimpleMaterial(color: .red, isMetallic: true)] } // 设置当前选中标记为蓝色 if let model = markerAnchor.children.first as? ModelEntity { model.model?.materials = [SimpleMaterial(color: .blue, isMetallic: true)] } parent.selectedMarker = markerAnchor } } } }
功能优化方向
- 自动识别墙面角落:替代手动放置标记,通过
ARPlaneAnchor的boundaryVertices属性获取墙面的四个角落坐标,自动生成标记点。 - 精准面积计算:扩展为支持四个标记点,计算矩形的长和宽,避免当前简化版的误差。
- 选中视觉增强:给选中的墙面添加蓝色轮廓(用
OutlineMaterial),而不仅仅是标记点变色,更贴近文本选中的视觉效果。 - 错误提示:添加弹窗或Toast提示用户操作错误(比如未检测到墙面、标记点数量不足等),提升用户体验。
内容的提问来源于stack exchange,提问作者Thea Young
相关产品推荐
相关产品推荐

