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

基于初始相机位置为原点,在SwiftUI+RealityKit中指定坐标放置AR锚点

在SwiftUI + RealityKit中以初始相机位置为原点放置AnchorEntities

核心思路

AR会话启动时,捕获初始相机的世界变换矩阵作为全局原点,后续所有目标坐标都基于这个原点做转换,最终创建对应位置的AnchorEntity。

实现步骤

1. 捕获初始相机的变换矩阵

在AR会话初始化完成后,获取第一帧有效相机的变换作为原点基准,可通过ARSessionDelegate回调或直接监听ARView的session.currentFrame实现:

import SwiftUI
import RealityKit

struct ARViewContainer: UIViewRepresentable {
    @State private var initialCameraTransform: simd_float4x4?
    
    func makeUIView(context: Context) -> ARView {
        let arView = ARView(frame: .zero)
        arView.session.delegate = context.coordinator
        return arView
    }
    
    func updateUIView(_ uiView: ARView, context: Context) {
        guard initialCameraTransform == nil, let currentFrame = uiView.session.currentFrame else {
            return
        }
        initialCameraTransform = currentFrame.camera.transform
        // 记录原点后放置目标实体,示例坐标为x+1、y0、z-2(相对于初始相机前方2米、右侧1米)
        placeTargetEntity(at: simd_float3(1, 0, -2), in: uiView)
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(parent: self)
    }
    
    class Coordinator: NSObject, ARSessionDelegate {
        var parent: ARViewContainer
        
        init(parent: ARViewContainer) {
            self.parent = parent
        }
        
        // 可选:通过会话回调确认AR环境初始化完成后记录原点
        func session(_ session: ARSession, didAdd anchors: [ARAnchor]) {
            guard parent.initialCameraTransform == nil, let currentFrame = session.currentFrame else {
                return
            }
            parent.initialCameraTransform = currentFrame.camera.transform
        }
    }
    
    // 放置目标实体的核心方法
    private func placeTargetEntity(at targetWorldPosition: simd_float3, in arView: ARView) {
        guard let initialTransform = initialCameraTransform else { return }
        
        // 计算初始相机的逆变换,将世界坐标转为相对初始相机原点的坐标
        let inverseInitialTransform = initialTransform.inverse
        let relativePosition = simd_mul(inverseInitialTransform, simd_float4(targetWorldPosition, 1)).xyz
        
        // 创建锚点并添加可视化模型
        let anchorEntity = AnchorEntity(world: simd_float4x4(translation: relativePosition))
        let modelEntity = ModelEntity(mesh: .generateBox(size: 0.2))
        anchorEntity.addChild(modelEntity)
        
        arView.scene.addAnchor(anchorEntity)
    }
}

// SwiftUI主视图
struct ContentView: View {
    var body: some View {
        ARViewContainer()
            .edgesIgnoringSafeArea(.all)
    }
}

2. 关键细节说明

  • 坐标转换逻辑:initialCameraTransform.inverse能将世界空间坐标转换为以初始相机为原点的局部空间,确保目标位置始终相对启动时的相机位置。
  • 锚点选择:使用AnchorEntity(world:)可直接将实体放置在计算后的相对位置,无需依赖平面检测或地理定位。
  • 会话稳定性:建议通过session(didAdd:)回调记录原点,避免初始帧抖动导致的位置偏差。

3. 简洁替代方案

如果仅需要简单的位置偏移,可直接记录初始相机位置向量,后续目标位置基于该向量偏移:

// 记录初始相机位置
let initialCameraPosition = currentFrame.camera.transform.translation
// 目标位置 = 初始位置 + 偏移量
let targetPosition = initialCameraPosition + simd_float3(1, 0, -2)
let anchorEntity = AnchorEntity(world: simd_float4x4(translation: targetPosition))

内容的提问来源于stack exchange,提问作者Sparsh gupta

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 02:35:17