使用 Anchor Entity 在 visionOS 中锚定现实世界对象

使用 Anchor Entity 在 visionOS 中锚定现实世界对象

为何需要 Anchor Entity

在 RealityKit 中,可以使用 Entity 和 RealityView 来加载和渲染 3D 对象,并为他们添加动画,从而创建虚拟现实体验,你可以参考下面的文章了解如何实现。

visionOS 开发 / 使用 RealityKit 播放动画(一)
了解如何使用 RealityKit 在 3D 模型上播放动画。
快速上手 Reality Composer Pro 的 Timelines 功能,轻松添加动画
了解 Reality Composer Pro 中的 Timelines 功能

但是,如果你想将虚拟内容添加到周围的环境,来创建更加具有吸引力的增强现实(AR)体验,这种做法就会有一些限制。想象一下这些应用场景:

家具购物应用

假设你要开发一个家具购物的 AR 应用,该应用允许用户在自己的客厅里虚拟放置沙发来预览效果。如果沙发的虚拟图像不能准确锚定到地面,那么当你移动手机或头部时,沙发可能会看起来漂浮在空中或部分埋入地下,这会破坏真实感和购买决策过程。

历史遗迹增强导览

在历史遗迹的增强现实导览中,游客通过 AR 眼镜看到古代建筑的复原状态。如果这些复原图像不能准确地锚定在真实的遗迹位置上,可能导致虚拟内容与实际遗迹错位,影响教育效果和用户体验。

FSP 游戏场景

类似下面这样的 FPS 游戏场景,需要保持在观察者的前方

AnchorEntity 的引入是为了解决上述这些挑战,确保虚拟对象可以准确、稳定地固定在现实世界的具体位置上

Anchor Entity 基本概念

什么是 Anchor Entity

AnchorEntity 是 RealityKit 框架中的一个核心概念,用于在 AR 体验中将虚拟内容锚定到现实世界的特定物理位置。通过使用 AnchorEntity,开发者可以定义一个虚拟对象应该出现的精确位置和方向,确保当设备移动或环境变化时,虚拟内容仍然正确地放置和定向。这种锚定使得虚拟内容能够与现实世界的物理元素(如墙面、桌面等)无缝融合。

与 Entity 有什么异同

在 RealityKit 中,AnchorEntity 是 Entity 的一个子类,它专门用于在 AR 环境中创建稳定的参考点。普通的 Entity 可以表示场景中的任何对象,不一定与现实世界的位置关联。

相反,AnchorEntity 通过与现实世界的特定物理特征(如平面、图像标记等)相关联,为其他 Entity 提供了一个稳定的基准。这意味着 AnchorEntity 通常是场景中位置固定的实体,而其他非锚定的 Entity 可以更自由地在虚拟环境中移动或变化

与 ARAnchor 的异同

ARKit 中的 ARAnchor 和 RealityKit 中的 AnchorEntity ,都是为了将三维模型与现实世界中的对象绑定在一起。AnchorEntity 晚于 ARAnchor 推出,他们之间最重要的区别在于—— AnchorEntity 使用更加简单

使用 ARAnchor 需要手动配置 Session 会话,并通过代理方法处理更新,而创建 AnchorEntities 不需要手动管理会话,更为自动化,你可以基于特定标准(如平面或图像)定义一个AnchorEntity,RealityKit 会作为其场景管理的一部分处理放置和更新。

使用 AnchorEntity

基本用法

下面这个代码为垂直平面创建了锚点:

let wallAnchor = AnchorEntity(.plane(.vertical, classification: .wall, minimumBounds: SIMD2<Float>(0.6, 0.6)))
  • .plane 表示创建的锚点类型是平面。其他类型可在【锚点类型】中查看。
  • .vertical 表示锚点应该附着到垂直平面,通常是墙面。
  • .classification 这个参数进一步细化锚点的类型。.wall 表示这个锚点专门用于墙面。这是 RealityKit 用于提高锚点定位精度和相关性的分类。
  • .minimumBounds 这是一个 SIMD2<Float> 类型,定义了锚点有效依附的最小平面尺寸,这里设置为至少 0.6 米 x 0.6 米。这个参数确保 AR 系统只在检测到足够大的平面时才创建锚点,有助于提高应用的稳定性和实用性。

然后使用 Entity 加载一个 3D 模型,并将这个 Entity 作为 wallAnchor 的 Child:

var body: some View {
    RealityView { content in
        let wallAnchor = AnchorEntity(
            .plane(
                .vertical, classification: .wall,
                minimumBounds: SIMD2<Float>(0.6, 0.6)))
        if let entity = try? await Entity(
            named: "Shahed-131_special_edition_white")
        {
            wallAnchor.addChild(entity)
            content.add(wallAnchor)
        }

    }
}

这样我们就实现了将 3D 模型“贴”到墙上的效果:

💡
AnchorEntity 只能工作在 ImmersiveSpace 模式下,Windows 和 Volumes 模式下无法接收带有锚点的空间跟踪信息。

锚点类型

AnchorEntity 支持多种锚点,目前支持以下几种锚点类型:

注意:RealityKit 在不同的平台支持的锚点类型会有一些区别,以上列表仅表示在 visionOS 中支持的锚点类型,通常 iOS 平台会更多,而 macOS 平台则会更少。

由于支持的锚点类型是持续更新的,你可以查看这个官方文档,获取最完整的类型列表:

AnchoringComponent.Target | Apple Developer Documentation
Defines the kinds of real world objects to which an anchor entity can be tethered.

Classification 可选类型

classification 参数主要与 .plane 类型的 AnchorEntity 一起使用,用于指定锚点依附的具体平面类型。通过预先指定正确的平面类型,可以提升锚定精度。

目前支持的几种平面分类:

  • .wall:表示锚点应该依附到垂直的墙面上。
  • .floor:用于指定锚点依附到地面。
  • .ceiling:表示锚点依附到天花板。
  • .table:指定锚点依附到表面,如餐桌或办公桌。
  • .seat:适用于锚定到座位,比如椅子或沙发等。
  • .any:不具体指定平面类型,允许锚点依附到任何检测到的平面。
💡
这些分类选项只适用于 .plane 类型的锚点。

由于分类类型也在持续更新,你可以访问 Apple 官方文档获取最新平面类型列表:

AnchoringComponent.Target.Classification | Apple Developer Documentation
Defines types of real-world surfaces to seek as targets.

锚定到指定平面(示例)

在之前的示例中,我们已经学会如何将一个 3D 模型锚定到目标平面。这个部分我们来实现,将一张图片锚定到平面(例如墙上),例如下面这样: