VisionPro开发 - 如何让物体总是面向镜头?


首页:漫游Apple Vision Pro

Code Repo: github.com/xuchi16/vis...

Project Path: github.com/xuchi16/vis...


基本概念

在VisionOS中,可以通过ARKit获取多种感知能力

  1. 平面检测(Plane detection) :检测周围环境中的水平表面(如桌子和地板)以及垂直平面(如墙壁和门),并使用它们来锚定内容。

  2. 世界跟踪(World tracking) :确定设备相对于其周围环境的位置和方向,并添加世界锚点以放置内容。

  3. 手部跟踪(Hand tracking) :使用人的手和手指位置作为自定义手势和交互的输入。

  4. 场景重建(Scene reconstruction) :构建人周围物理环境的网格,并将其融入沉浸式空间以支持交互。

  5. 图像跟踪(Image tracking) :在人的周围环境中寻找已知图像,并使用它们作为自定义内容的锚点。

目前,在visionOS模拟器中,仅支持了World tracking,其他均暂未支持

通过这一感知能力,可以实现面向镜头、跟随镜头等功能,本文展示了让对象总是面向镜头的实现方式。

基本实现

  1. 定义ARKitSessionManager,主要负责初始化ARKitSessionWorldTrackingProvider以及获取设备实时姿态。
swift 复制代码
import SwiftUI
import ARKit

@MainActor
class ARKitSessionManager: ObservableObject {

    let session = ARKitSession()
    let worldTracking = WorldTrackingProvider()

    func startSession() async {
        if WorldTrackingProvider.isSupported {
            do {
                try await session.run([worldTracking])
            } catch {
                assertionFailure("Failed to run session: (error)")
            }
        }
    }

    func getOriginFromDeviceTransform() -> simd_float4x4 {
        guard let pose = worldTracking.queryDeviceAnchor(atTimestamp: CACurrentMediaTime()) else {
            return simd_float4x4()
        }
        return pose.originFromAnchorTransform
    }
}
  1. 为了让目标物体能够有始终面向摄像机的特性,根据6. 物体移动 一节介绍的ECS模式,需要定义对应的Component和System。
  • Component记录实体状态数据
  • System控制实体行为

这里FaceComponent没有过多状态,只是为了让System获取摄像机信息,记录了对应的ARKitSessionManager供System使用。

swift 复制代码
import RealityKit
public struct FaceComponent: Component {
    let manager: ARKitSessionManager?
}

FollowSystem中,

  • 通过followEntity.manager!.getOriginFromDeviceTransform()获取设备Transform,并且提取其中位置坐标
  • 通过entity.transform.translation获取实体位置坐标

Entity上提供了一个非常易用的函数look(at:from:upVector:relativeTo:),用于定位和调整实体的朝向,使其从给定位置看向一个目标。我们可以在任何实体上使用这个方法,但它特别适用于定位摄像头和灯光,使其瞄准空间中的特定点。

swift 复制代码
import RealityKit
public struct FaceSystem: System {
    static let faceQuery = EntityQuery(where: .has(FaceComponent.self))
    
    public init(scene: Scene) {
    }
    
    public func update(context: SceneUpdateContext) {
        let entities = context.scene.performQuery(Self.faceQuery)
        
        for entity in entities {
            guard let followEntity = entity.components[FaceComponent.self] else {
                continue
            }
            
            if followEntity.manager == nil {
                return
            }
            let cameraTransform = followEntity.manager!.getOriginFromDeviceTransform()
            
            let cameraPosition = SIMD3<Float>(cameraTransform.columns.3.x, cameraTransform.columns.3.y, cameraTransform.columns.3.z)
            let entityPosition = entity.transform.translation
            
            entity.look(at: cameraPosition, from: entityPosition, relativeTo: nil)
        }
    }
}
  1. 打开全沉浸空间并加载3D对象,为了后续能够使用ARKit中的信息,我们需要初始化ARKitSessionManager并启动ARKitSession。有了ARKitSessionManager后,将其传递给新建的FaceComponent,最终附属到实体上,这样FaceSystem就能够获得设备和实体的位置信息,并实现追踪效果了。
swift 复制代码
struct ImmersiveView: View {
    @State var entity = Entity()
    @ObservedObject var arkitSessionManager = ARKitSessionManager()

    var body: some View {
        RealityView { content in
            let tv = try! await Entity(named: "tv_retro")
            tv.transform.rotation = simd_quatf(angle: .pi, axis: [0, 1, 0])
            entity.addChild(tv)

            let followComponent = FaceComponent(manager: arkitSessionManager)
            entity.components[FaceComponent.self] = followComponent
            entity.position = SIMD3<Float>(x: 0, y: 1.2, z: 0)
            content.add(entity)
        }
        .task {
            await arkitSessionManager.startSession()
        }
    }
}

最终效果

相关推荐
汉秋1 天前
SwiftUI 中的 compositingGroup():真正含义与渲染原理
swiftui·swift
汉秋1 天前
SwiftUI 中的 @ViewBuilder 全面解析
swiftui·swift
胖虎12 天前
SwiftUI 页面作为一级页面数据被重置问题分析
ios·swiftui·swift·state·observedobject·stateobject·swiftui页面生命周期
guangzan2 天前
AI 结队编程:解决 SwiftUI 窗口点击关闭按钮崩溃问题
swiftui·tca
1024小神2 天前
xcode 配置了AppIcon 但是不显示icon图标
ios·swiftui·swift
东坡肘子4 天前
周日小插曲 -- 肘子的 Swift 周报 #115
人工智能·swiftui·swift
YungFan5 天前
iOS开发之MetricKit监控App性能
ios·swiftui·swift
1024小神8 天前
xcode 中配置AR Resource Group并设置图片宽度等
ios·swiftui·ar·xcode·swift
lancoff10 天前
#5 ScrollViewReader
ios·swiftui
lancoff10 天前
#6 GeometryReader
ios·swiftui