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

如何获取ARKit生成的网格数据?

如何获取ARKit生成的网格数据?

嗨,我来帮你搞定这个问题!你想直接获取ARKit生成的网格数据来找到离相机最近的物体,这个思路完全可行,下面是具体的实现步骤和代码示例:

首先要明确:ARKit的场景重建功能默认是关闭的,所以第一步得先开启它,这样ARKit才会生成网格锚点(ARMeshAnchor),我们就能从这些锚点里拿到网格数据。

1. 开启场景重建配置

在创建ARView的时候,需要配置ARWorldTrackingConfiguration,开启sceneReconstruction选项,让ARKit开始生成网格:

let configuration = ARWorldTrackingConfiguration()
// 开启带物体分类的网格重建,也可以用.mesh来只生成不带分类的网格
configuration.sceneReconstruction = .meshWithClassification
arView.session.run(configuration)

2. 监听网格锚点的更新

ARKit会把生成的网格封装成ARMeshAnchor添加到AR场景中,我们可以通过订阅RealityKit的场景事件来捕获这些锚点:

// 订阅锚点状态变化事件,当锚点被添加或更新时触发
let anchorSubscription = arView.scene.subscribe(to: SceneEvents.AnchoredStateChanged.self) { event in
    // 过滤出网格锚点
    guard let meshAnchor = event.anchor as? ARMeshAnchor else { return }
    
    // 拿到网格锚点后,就可以处理里面的网格数据了
    self.processMesh(meshAnchor, camera: arView.camera)
}

记得要保存这个订阅对象,避免被提前释放,我们可以用一个协调器(Coordinator)来管理订阅。

3. 提取网格数据并计算最近点

ARMeshAnchor的geometry属性包含了所有网格数据:顶点、面、法线、物体分类等。我们可以遍历这些顶点,计算每个顶点到相机的距离,找到最近的那个点:

private func processMesh(_ anchor: ARMeshAnchor, camera: ARCamera?) {
    guard let cameraTransform = camera?.transform else { return }
    // 获取相机在世界坐标系中的位置
    let cameraPosition = simd_make_float3(cameraTransform.columns.3)
    
    var closestDistance: Float = .greatestFiniteMagnitude
    var closestVertex: SIMD3<Float>?
    
    // 遍历网格的所有顶点
    let vertices = anchor.geometry.vertices
    for index in 0..<vertices.count {
        // 获取顶点在锚点本地坐标系的位置
        let localVertex = simd_make_float3(vertices[index])
        // 转换到世界坐标系
        let worldVertex = anchor.transform * simd_make_float4(localVertex, 1.0)
        // 计算到相机的距离
        let distance = simd_distance(cameraPosition, simd_make_float3(worldVertex))
        
        // 更新最近点
        if distance < closestDistance {
            closestDistance = distance
            closestVertex = simd_make_float3(worldVertex)
        }
    }
    
    if let closestVertex = closestVertex {
        print("离相机最近的顶点位置:\(closestVertex),距离:\(String(format: "%.2f", closestDistance))米")
    }
}

完整的ARViewContainer代码

把上面的逻辑整合到你的ARViewContainer中,完整代码如下:

import SwiftUI
import RealityKit
import ARKit
import Combine

struct ARViewContainer: UIViewRepresentable {
    func makeUIView(context: Context) -> ARView {
        let arView = ARView(frame: .zero)
        
        // 配置AR会话,开启场景重建
        let configuration = ARWorldTrackingConfiguration()
        configuration.sceneReconstruction = .meshWithClassification
        arView.session.run(configuration)
        
        // 订阅锚点事件
        let subscription = arView.scene.subscribe(to: SceneEvents.AnchoredStateChanged.self) { event in
            guard let meshAnchor = event.anchor as? ARMeshAnchor else { return }
            self.processMesh(meshAnchor, camera: arView.camera)
        }
        context.coordinator.subscriptions.append(subscription)
        
        return arView
    }
    
    func updateUIView(_ uiView: ARView, context: Context) {}
    
    private func processMesh(_ anchor: ARMeshAnchor, camera: ARCamera?) {
        guard let cameraTransform = camera?.transform else { return }
        let cameraPosition = simd_make_float3(cameraTransform.columns.3)
        
        var closestDistance: Float = .greatestFiniteMagnitude
        var closestVertex: SIMD3<Float>?
        
        let vertices = anchor.geometry.vertices
        for index in 0..<vertices.count {
            let localVertex = simd_make_float3(vertices[index])
            let worldVertex = anchor.transform * simd_make_float4(localVertex, 1.0)
            let distance = simd_distance(cameraPosition, simd_make_float3(worldVertex))
            
            if distance < closestDistance {
                closestDistance = distance
                closestVertex = simd_make_float3(worldVertex)
            }
        }
        
        if let closestVertex = closestVertex {
            print("最近顶点位置:\(closestVertex),距离:\(String(format: "%.2f", closestDistance))米")
        }
    }
    
    // 协调器,用于管理订阅对象
    func makeCoordinator() -> Coordinator {
        Coordinator()
    }
    
    class Coordinator {
        var subscriptions: [AnyCancellable] = []
    }
}

一些注意事项

  • 场景重建功能需要硬件支持,目前iPhone 12及以上、iPad Pro(2020及以后)的机型才能使用。
  • 网格数据是实时更新的,每次锚点更新都会有新的顶点数据,如果计算逻辑比较重,建议放到后台线程处理,避免卡顿。
  • 如果你只关心某个区域的网格,可以过滤掉离相机较远的锚点,减少计算量。

备注:内容来源于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.04.22 08:49:49