AR 开发入门:与苹果的 AR 工具一起玩转增强现实

XR 基地是一个专注于凝聚 XR 的创作者社区,我们的目标是 让 XR 开发变得更简单!

本文 首发于 XR 基地官网XR 基地公众号

作者:东坡肘子,XR 基地成员,iOS 开发者,技术博主

AR,一种让科技与现实世界融为一体的奇妙魔法,正在悄然改变我们与世界互动的方式。它让虚拟世界跃入真实生活,让数字信息与物理世界无缝衔接。

AR 带来全新的体验,激发人们的想象力,重塑人与环境信息交互模式,开拓人类与世界新的维度。作为拓展人类现实体验极限的产物,AR 随着科技发展正在与人们日常生活深度融合,人们得以在 AR 的加持下探索现实与虚拟之间的新的可能。

本文将带领读者探索苹果的 AR 生态与工具,初步了解如何运用苹果 AR 工具构建 AR 体验。我们将一睹 AR 在苹果生态中的强大表现。

在最近举行的 WWDC 2023 大会上,苹果发布了全新头显产品 Apple Vision Pro,并大大提高了开发者在该设备上开发增强现实应用的体验。尽管我们目前还无法基于 Apple Vision Pro 的真实设备进行开发,但关于 AR 技术和基本开发流程的核心概念并没有发生变化。阅读本文,可以让你在 iOS 平台上率先领略苹果的 AR 生态,这有益于你日后转入 Apple Vision Pro 的开发。

AR 的演变之路

增强现实(Augmented Reality,简称 AR),是指透过摄影机影像的位置及角度精算并加上图像分析技术,让屏幕上的虚拟世界能够与现实世界场景进行结合与交互的技术 - 维基百科

同许多新兴技术一样,AR 的灵感也源自科幻小说。1901 年,美国作家莱曼·弗兰克·鲍姆在小说《The Master Key》中描绘了这样一个场景:一个叫罗伯特的小男孩偶然触碰到了"电之万能钥匙", 并得到三件礼物,其中一件是一副神奇的眼镜。戴上眼镜后,他看到人们额头上出现了用于表示性格的标记。这个场景与今天 AR 的定义如出一辙:识别影像中的物体, 并在现实中叠加信息。

在 1992 年,美国波音研究员 T.P Caudell 和同事首次提出了"Augmented Reality"这个术语。在他们的论文《Augmented Reality: An Application of Heads-Up Display Technology to Manual Manufacturing Processes》中,使用了"增强现实"一词来描述将计算机生成的元素投射在真实世界之上的技术。这也是人类历史上第一次有人提出 AR 的概念。

该论文阐述了如何利用头戴显示设备将增强现实技术应用于制造业中的手工流程。这使得操作员可以得到计算机生成的附加信息,从而提高工作效率与质量。

1997 年,美国北卡罗莱纳大学的 Ronald Azuma 教授发表了篇论文《A Survey of Augmented Reality,第一次给出了人们公认的 AR 技术定义。这个定义提出了 AR 的三大特征:虚拟世界和现实世界的结合、实时互动、基于三维定位。这个定义不仅清晰地描绘出 AR 技术的发展蓝图,也为 AR 技术长期稳定发展奠定了基础。

不过,因为种种限制,AR 技术当时还远远称不上主流,普通人不仅碰都没碰过,名字都可能没听说过。1999 年,奈良先端科学技术大学院大学的加藤博一开发的 AR Toolkit 项目让 AR 技术终于出了实验室的囚笼,给普通人第一次亲身体验 AR 应用的机会。

AR Toolkit 项目利用二维标记实现虚拟物体与现实物体的实时跟踪和叠加。AR Toolkit 项目的出现为 AR 技术打开了大门,让 AR 理论变成现实。它让 AR 技术得以快速提速,极大推广了 AR 理念,为 AR 技术最终进入人们生活,打下基础。

然而,真正让大多数人了解和认识 AR 技术的,是由任天堂公司授权、Niantic Labs 公司开发和运营的 AR 手游《Pokémon GO》,于 2016 年面世。该游戏让全球用户领略了 AR 技术所带来的独特魅力。

《Pokémon GO》是一款让玩家在现实世界中探索、捕捉、战斗和交换宝可梦的游戏。玩家可以通过智能手机在现实世界中发现精灵,进行抓捕和战斗。玩家抓到的精灵越多,就会变得越强大,更有机会抓到更强大、更稀有的精灵。该游戏一经发布,就成为了风光无限的现象级 AR 手游。市场研究公司 App Annie 发布的数据显示,《Pokémon GO》仅在 63 天内就通过 iOS 和 Google Play 应用商店在全球赚取了 5 亿美元,成为史上赚钱速度最快的手游之一。或许是受了《Pokémon GO》成功的影响,次年,苹果正式迈入了 AR 领域。

2017 年可以说是 Apple AR 的"元年"。在这一年的 WWDC 上,Apple 发布了 ARKit 框架,以帮助开发者在 Apple 生态下进行 AR 应用的开发。发布之初,ARKit 提供了可以识别平面以及跟踪设备移动情况的能力。这两项能力是基于计算机视觉框架 Vision 对摄像头数据和 iOS 设备的陀螺仪传感器实现的。尽管基础,但这两个功能已经为 AR 应用的开发打了坚实的基础。

此外,iPhone X 搭载的原深感摄像头为人脸识别技术提供了硬件支持。基于此,ARKit 可以精确识别面部表情,不仅可以识别用户的面容,还可以将用户的表情精细地对应到面部三维模型上。

2018 年,Apple 在原有 QuickLook 的基础上推出了 AR QuickLook。用户现在可以通过系统内置的文件应用程序以 AR 的方式预览三维模型。此外,ARKit 也得到了进一步地增强,增加了追踪识别现实世界中的图片和三维物体的功能。用户甚至可以在扫描现实世界时对其进行"截图",然后在具有反射效果的三维物体上反映出来。

2019 年,Apple 发布了专门用于 AR 场景的渲染引擎 RealityKit,以及与之配套的创作工具 Reality Composer。通过使用 Reality Composer,即便你不懂开发,也能轻松地构建一个比较完整的 AR 场景。无论你使用 Mac、iPad 还是 iPhone,都可以使用 Reality Composer 来完成场景的构建工作。

在 2020 年之前,开发者如果想将三维模型转换成 RealityKit 或者 SceneKit 支持的 USDZ 格式,只能使用一个命令行工具------USDZ Converter。然而,在某些需要对模型进行精细调整的场景下,这种方式并不太方便。因此,Apple 在 2020 年推出了 Reality Converter,填补了在创作者工具方面的一个空白。

2021 年,Apple 在 RealityKit 中提供了 Object Capture 的 API,使开发者能够通过拍摄物体直接生成高质量的三维模型。

2022 年,Apple 推出了 RoomPlan 框架。该框架允许开发者使用配备了 LiDAR 的设备对房屋进行建模。

经过不断的努力和投入,加之拥有大量的硬件设备数量优势,苹果已经成为了当今 AR 领域的领导者。

到底是以什么样的技术原理作为支撑,才能实现 AR 的神奇效果呢?

AR 是如何工作的呢?

从工作原理来讲,AR 大致分为两类。

第一类是通过计算机视觉技术扫描和理解周围环境的 AR,这种专业点叫 Vision Based AR。它通过摄像头和传感器来扫描你周围的环境。

Vision Based AR 分为基于标记的 AR(Marker-based AR) 和无标记的 AR(Marker-less AR) 两种。Marker-based AR 实现简单,现实感稍微差点,显示内容也受那些小标记的限制。譬如之前展示的那个初音未来的视频,它就是基于 Marker-based AR 的原理实现的。另一种 Marker-less AR 需要计算机视觉和机器学习技术的支持,它会建立一个超级详细的三维环境模型,然后基于这个模型进行定位、跟踪和显示内容。相比而言,Marker-less AR 可以达到更高的现实感,显示内容也更加精细。

第二类 AR 是基于位置服务的 AR(Location Based Service Based AR),简称 LBS Based AR。它通过 GPS 和指南针获取你的位置和方向,得以实现定位、跟踪和显示内容。LBS Based AR 不需要环境模型或标记,直接根据设备位置显示内容,开发难度最小,但现实感也最差,显示的内容不能与真实环境高度匹配。像现象级手游《Pokémon GO》就是 LBS Based AR 的代表。

近年来,随着一些大公司不断丰富街景数据,现在在某些地区仅依赖位置信息便可以准确地将虚拟物体与周围环境相匹配,这种技术被称作 VPS(Virtual Position System),例如 Google Maps Platform 中的 Geospatial 相关技术。

相比而言,Vision Based AR 实现更精细,可以达到更高的现实感,但开发难度也更大。而 LBS Based AR 更简单,现实感略差,但开发难度更小。这两种 AR 形式各有优势,也可相互融合,发挥各自的长处。比如用 LBS Based AR 确定大致位置和方向,再用 Vision Based AR 精确扫描环境并显示内容,如此可取长补短,实现高性能的 AR 系统。

无论采用哪种原理的 AR 形式,苹果都为开发者提供了简单而成熟的解决方案。开发者只需要专注于 AR 的应用创意,选择适当的 AR 形式及工具,便可轻松将 AR 体验带给最终用户,而无需担心复杂的底层技术实现。苹果让 AR 开发变得如此简单,使得开发者能够自如地创造 AR 应用。

5 分钟快速体验 AR 的魅力

在之前的内容中,我们通过文字、图片和影像向你介绍了 AR。但只有当你亲身体验 AR 的魔力后,才会真正感受到 AR 的魅力,其震撼远超过任何语言所能描述。让我们一起来看看 AR QuickLook 这个技术框架,如何为我们带来 AR 的震撼体验。

QuickLook 是一个框架,可用于 iOS、macOS 和 iPadOS。任何集成了这个框架的应用程序都可以快速查看许多常见的文件类型,比如 PDF、TXT、Pages 等。许多 Apple 的第一方应用程序,例如邮件、备忘录、文件和信息,都内置了 QuickLook。这意味着如果某个文件格式得到 QuickLook 的支持,便可以在众多的苹果设备上被快速预览。

2018 年,苹果为 QuickLook 添加了对 USDZ、Reality 等 AR 文件类型的支持。只要有一台 iOS 12+ 的苹果设备,就可以马上体验 AR 的魅力。

如今,QuickLook 不再仅仅是一个浏览文档或图片的工具。它已经经历了一次蜕变。支持 AR 内容的 QuickLook 迈进了一个全新的维度,因此我们将其称为"AR QuickLook"。通过 AR QuickLook,我们可以在现实环境中自然地查看和体验各种 AR 场景和效果,这是体验 AR 的最佳途径。

在身边找一台符合要求的设备( iPhone、iPad ),用 Safari 访问这个网址 :developer.apple.com/augmented-r...

你会看到有许多在右上角有一个小立方体标识的 3D 模型,选择其中的一个( 完整的演示效果可看下方视频 )。

如果在 macOS 上访问该网址,3D 模型的右上方不会有小立方体的标识( 表示无法启用 AR QuikckLook ),点击后只能获得该模型的 3D 文件( USDZ 格式 )。

点击任何 3D 模型,Safari 浏览器会启动 AR QuickLook 并加载该模型。一旦系统检测到适合的平面,AR QuickLook 会自动将 3D 模型放置在对应平面上。这种无缝体验令人满意,3D 模型在真实环境中也显得非常自然,简直太神奇了!

现在,我们将注意力转移到 AR QuickLook 的交互界面。在界面中央有一个切换按钮,上面分别写着"AR"和"对象", 它们分别代表什么呢?

实际上,AR QuickLook 提供了两种方式来展示 3D 模型。 "AR 模式" 将虚拟物品放置在真实环境中,让用户直观地感受虚拟物品在真实世界中的效果。 "对象模式" 更侧重于 3D 模型本身,方便用户查看模型细节。这种切换机制允许用户灵活地在两种模式间转换,以满足不同的浏览与体验需求,同时也增强了 AR QuickLook 的易用性和趣味性。

无论是哪种模式,使用者都可以轻松地进行一些基本操作。下面是一些常见的操作:

  • 定位:通过点击(tap)、按住(hold)和拖动(drag)的手势,我们可以轻松定位 3D 模型的位置,从而将模型放在我们想要展示的地方。而且 AR QuickLook 能够识别出水平面和垂直面,这也让模型的摆放更加自然。

  • 缩放:用捏合(pinch-in)或拉伸(pinch-out)手势将 3D 模型放大或缩小。另外一个与缩放相关的操作是双击,通过双击 3D 模型会将其比例重置为 100%。

  • 旋转:通过将两根手指放在屏幕上,并以圆周运动的方式移动它们来旋转 3D 模型。同样,双击手势将重置旋转。

  • 悬浮:用两根手指向上拖动 3D 模型,你会惊奇地发现,它似乎摆脱了地心引力的束缚!

  • 拍照/录像:快速点击屏幕上的快门按钮可以进行拍照,而长按快门按钮会触发录像功能(一旦松手,录像将会中止)。

现在你已经掌握了 AR QuickLook 的基本操作,那就多花点时间仔细地把玩一下网页里的不同模型吧!

不要沉迷于其中,记得过会儿回来继续阅读哦!

不知道你在刚才的把玩中是否注意到如下细节:

  • 3D 模型在起居室这样的日常环境中摆放,与周围的寻常家具别无二致,能够自然融入。

  • 3D 模型能够呈现出自然的阴影,如同真实物体一般。

  • 若有人从模型的前方或后方经过,会生成准确的遮挡效果,让人感觉与 3D 模型真的共处于同一个空间。

所有这些,都需要依赖精巧的算法以及软硬件之间完美的配合才能实现,好在苹果已帮我们做好了一切。AR QuickLook 让我们得以亲眼目睹虚拟世界与现实世界的完美融合,这正是 AR 的魅力所在。如果刚才没有注意到上述细节,可以再体验一次,相信一定会有全新的领悟。

如果你有自己的 3D 模型需要通过 AR QuickLook 查看,可以使用苹果提供的 Reality Converter 工具将 3D 模型转换成 USDZ 格式。这样,AR QuickLook 就可以直接识别和显示你的模型了。

AR QuickLook 让我们体验到 AR 的无限可能。但如果想构建属于自己的 AR 场景或效果,又该从何处着手呢?别担心,苹果也在此方面也为我们提供了解决方案。通过 Reality Composer,你可以轻松创建自定义的 AR 场景与效果,而无需编写任何代码。

无需编程,你也能创建 AR 场景

直到几年前,创造沉浸式的 AR 体验仍是一项相当困难的任务。AR 开发人员需要大量的技能,以及对各种技术的广泛了解,才能使一个小立方体出现在 AR 中。当苹果公司发布 Reality Composer 时,一切都改变了。

Reality Composer 是 Apple 在 2019 年 WWDC 上发布的一款可视化编辑工具,可以帮助人们在 Mac、iPhone 和 iPad 上创建、测试和优化 AR 体验。无需任何编程知识或 3D 开发相关的背景,就可以完成自己的 AR 创作。

你可以在 App Store 中直接下载 Reality Composer,包括 iPhone 和 iPad 版本。下图展示了 Reality Composer 在 iPad 上的运行状态。

在 macOS 上,Reality Composer 是集成在 Xcode 中的。只要你安装好 Xcode,就可以在 Spotlight 中搜索并直接打开它。

由于缺乏后置摄像头,Mac 版本的 Reality Composer 缺少一个 AR 模式,无法直接进入 AR 状态预览,需要将项目通过分享或转存的方式传递给 iPhone 或 iPad 才能看到最终的效果。你可以根据个人情况选择使用哪个版本的 Reality Composer 进行学习。下图显示了 Reality Composer 在 Mac 上的运行状态。

在新建 Reality Composer 项目时,应用会要求我们为第一个场景选择锚定类型(Anchor)。

不同的锚定类型分别对应着不同的 AR 算法以及设备上的不同镜头,一个场景只能选择一种锚定类型。

  • 水平

水平锚定是创建新文档或场景的默认选项。通常用于要将 3D 对象放置在桌子、地板或其他平面上的场景。当你为场景选择水平锚定时,Reality Composer 会显示一个指南网格,以代表这就是将放置你的场景的真实世界表面。

  • 垂直

用于需要将物体放置在墙壁、柱子或其他竖直表面上的场景。选择此锚定类型后,Reality Composer 会显示一个垂直网格。

我们使用 AR QuickLook 预览 苹果 AR 网站 上的 3D 模型时,大多采用水平或垂直锚定类型。

  • 图像

图像锚定可以让你把 AR 场景放置在现实世界中的二维图像上(或附近),比如海报、绘画或者照片。当你选择这种锚定类型时,Reality Composer 会显示一个白色的方形指南,用以表示检测到的现实世界中的图像,以便你把要放置的内容放在其附近。

你还记得之前展示的通过 AR ToolKit 生成的跳舞初音吗?那就是采用了这种锚定类型。

  • 面孔

面孔类型允许你将内容放置在检测到的人脸上或附近。选择此锚定类型时,Reality Composer 将显示一个 3D 人脸来替代 ARKit 检测到的真实世界中的人脸。

在 ARKit 中,使用面孔锚定类型需要具备 TrueDepth 前置摄像头的设备。只要你的设备支持 Face ID,就可以使用该锚定类型。

  • 对象

使用这种锚定类型,你可以将场景放置在一个物体的扫描版本上或附近。当 ARKit 在现实世界中检测到对应的真实物体后,场景中的内容将根据它们相对于替代物的位置而放置。比如,你可以使用苹果提供的 3D 扫描应用 获取某个型号车辆的扫描数据。当 AR 应用在现实世界中检测到该型号车辆时,便可以在它的周围添加各种信息。

Reality Composer 提供的几种锚定方式涵盖了大部分主流的 Vision Based AR 类型,可以满足大多数 AR 场景的开发需求。

相信许多读者都曾经看过或使用过抖音(或其他类似产品)提供的为面部添加特效的功能。接下来,我们将使用 Reality Composer 来实现此功能,并在此过程中进一步了解 Reality Composer。

首先,在新项目中选择"面孔"锚定类型创建一个场景,然后将项目命名为 GoldenEye。

点击上方的"场景"按钮,为场景命名为"Eyes"。

虽然从外观上看,Reality Composer 与许多三维编辑软件相似,但实际上它更像是一个用于编辑 AR 场景的 PowerPoint。而且在两者之间可以找到许多类似的概念。

此时,你可以将场景视为 PowerPoint 中的一页,场景使用的锚定类型即为页面中对应的模板。接下来,我们将为此场景添加一些想要显示的内容。

点击上方的添加( + )按钮,在列表中选择球体。

你可以通过鼠标或手势对球体进行缩放并放置到右眼附近,或者在右侧的属性栏中为球体设置具体的位置和尺寸信息。别忘了给球体命名为 "Eye_R"。

在选中球体(Eye_R)时,切换到材质栏并选择黄金材质。

用相同的方式创建左眼对应的球体,并命名为"Eye_L"。

恭喜你!你已经使用 Reality Composer 成功创建了第一个 AR 场景。

如果你是在具备 Face ID 功能的 iPhone 或 iPad Pro 上创建的该场景,只需点击上方的 "AR" 按钮,即可立刻查看效果。如果是在 Mac 上创建的,则需要点击上方工具栏中的"发送到"按钮,将其发送至符合条件的设备上(已安装 Reality Composer),即可进行预览。

当从 Mac 发送到 iPhone 或 iPad 时,需要首先在设备上运行 Reality Composer。

出乎意料的容易!是吧。

现在我们可以为 AR 场景增加一些互动能力,让体验更加有趣。

与 PowerPoint 中使用者可以为页面中的物体(文字、图片)添加 Action 一样,我们也可以用类似的操作,为场景中的物体添加"行为"。

点击工具栏中的"行为"按钮,在下方的行为面板中,添加"轻点与播放声音"。

请将新增的行为命名为"Play Sound"。在"触发"栏中,点击"选择"按钮,选中两个金色的球体。在"播放声音"栏中,点击"选择"按钮,同样将两个球体设置为受影响的对象。最后选择你喜欢的音频片段。

点击上方工具栏中的"播放"按钮后,选择任意金色球体,系统立刻会播放选定的音频片段。

切换到 AR 模式( 在 iPhone、iPad 上点击 AR 按钮 )并点击"播放"按钮,你可以在设备屏幕上重复此操作,让 AR 场景具备交互性。这样,使用者就可以在实际影像中与添加的虚拟物体进行互动。

如果在 iPhone 或 iPad 上无法听到声音,很可能是因为选择了当前尚未下载的音频素材。你可以在设备上的声音列表中点击"☁️"下载素材,或者替换成设备上已经下载的音频。

当然,Reality Composer 的功能远不止于此。我们可以给物体添加物理行为,让不同的物体之间进行联动交互,创建多个采用不同锚定类型的场景,导入其他的 3D 模型(USDZ)。在大多数情况下,Reality Composer 都能很好地将创意转换成 AR 场景。

现在,你可以将制作好的项目文件(rcproject 文件)分享给其他拥有 iPhone 或 iPad 的小伙伴,与他们共同体验 AR 的乐趣,并展现你的创意。

用代码与 AR 场景交互,创建独立的应用

随着你对 Reality Composer 的了解加深,可能会发现它提供的功能无法完全满足你不断涌现的创意灵感。此外,你可能还希望通过 App Store 将你精心打造的 AR 场景分享给更多人,或将 AR 功能添加到其他应用程序中。那么我们该如何实现这些目标呢?

我们使用 Reality Composer 创建的项目文件,不仅可以在不同的设备上通过 Reality Composer 进行预览,还可以将其集成到应用程序项目中并作为一种资源使用。

这种做法在苹果生态的开发中非常普遍,比如使用 Scene Editor 创建 3D 场景、Sprite Editor 创建 2D 游戏关卡,或者使用 Data Model Editor 定义 Core Data 数据模型等等。最终,这些文件都会被集成到应用的开发项目中。Xcode 会根据文件的内容自动生成对应的代码,这样我们就可以在项目的其他代码中直接访问这些资源和对象了。

在接下来的两个章节中,需要安装 Xcode 并且拥有开发者账户才能完整地体验到最终的开发效果。但是即使你目前尚未具备这些条件,我也鼓励你继续阅读。我将用非常简单的例子和语言,让你对开发流程有个了解。

首先,在 Xcode 中创建一个名为 AR_Demo 的增强现实应用程序项目。这样,Xcode 会为我们生成相应的模板,以简化开发难度。

使用默认的项目配置,Interface 选择 SwiftUI,Content Technology 选择 RealityKit。

项目结构如下:

其中,ContentView 包含视图定义、AR 场景加载等代码,是我们之后重点关注的部分。

Experience 则是模版自动为我们生成的一个 rcproject 文件(Reality Composer 项目文件)。里面定义了一个使用平面锚定类型的场景,并放置了一个立方体。

点击右上角的 "Open in Reality Composer",可以在 Reality Composer 中编辑该场景。请注意,此时的场景名称为 "Box",立方体的名称也是 "Box"。

让我们看看此时 ContentView 中的代码中都有些什么内容。

Swift 复制代码
// SwiftUI 视图
struct ContentView : View {
    var body: some View {
        ARViewContainer().edgesIgnoringSafeArea(.all)
    }
}

// 通过 UIViewRepresentable ,创建一个可以 SwiftUI 中使用的 AR 视图( 因为 AR 视图当前是基于 UIKit 的)
struct ARViewContainer: UIViewRepresentable {
    
    func makeUIView(context: Context) -> ARView {
        // 创建 AR 视图
        let arView = ARView(frame: .zero)
        
        // 从 "Experience" Reality 文件中加载 "Box" 场景
        let boxAnchor = try! Experience.loadBox()
        
        // 将 Box 的锚定添加到场景中
        arView.scene.anchors.append(boxAnchor)
        
        return arView
        
    }
    
    func updateUIView(_ uiView: ARView, context: Context) {}
    
}

注意到了吗,Experience 和 Box 分别对应 Reality 文件的项目名称和场景名称。这意味着,我们对项目、场景和物体的命名将会被 Xcode 自动生成为相同名称的对象代码。通过 Xcode 的定义跳转操作,我们可以查看这些自动生成的代码内容。

接下来,我们将为之前创建的"黄金眼"项目添加一个新的功能:让两个黄金眼球随着嘴巴的张大而变大。 删除当前项目中的 Experience 文件,并将前一章在 Reality Composer 中创建的 GoldenEye 文件拖到当前的 Xcode 项目中( 注意选择 Copy items if needed )。

将 makeUIView 调整成下面的代码。

Swift 复制代码
import ARKit // 导入 ARKit 框架

func makeUIView(context: Context) -> ARView {
    // 创建 ARView
    let arView = ARView(frame: .zero)
    
    // 创建 ARConfiguration,可以理解为设置场景的锚定类型
    let arConfiguration = ARFaceTrackingConfiguration()

    // 使用 Configuration,创建并启动 AR 会话
    arView.session.run(arConfiguration, options: [.resetTracking, .removeExistingAnchors])
    
    // 加载眼球场景
    let arAnchor = try! GoldenEye.loadEyes()
    
    // 将 Eyes 的锚定添加到场景中
    arView.scene.anchors.append(arAnchor)
    return arView
}

在这段代码中,我们使用 ARFaceTrackingConfiguration 创建了一个与面孔锚定类型对应的 AR 配置对象,并据此创建的 AR 会话(ARSession)。在 ARKit 中,可以使用代码创建以下锚定类型:

  • AROrientationTrackingConfiguration:基本的三自由度(3DOF)跟踪。

  • ARWorldTrackingConfiguration:六自由度(6DOF)跟踪。它也可以跟踪人、已知的图像和物体。涵盖了 Reality Composer 的水平、垂直、图像、物体等多种锚定方式。

  • ARBodyTrackingConfiguration:跟踪人体。

  • ARImageTrackingConfiguration:跟踪已知的图像。对应 Reality Composer 的图片锚定。

  • ARObjectScanningConfiguration:扫描物体并创建该物体的高保真三维数据。所生成的物体数据可用于 ARWorldTrackingConfiguration 中,作为跟踪的目标对象。

  • ARFaceTrackingConfiguration:使用前置摄像头跟踪面部和面部表情。对应 Reality Composer 的面孔锚定。

  • ARPositionalTrackingConfiguration:提供六自由度(6DOF)跟踪,但和 ARWorldTrackingConfiguration 不同,这种场景下设备不会收集和分析来自相机的画面,仅追踪设备的移动,适合于一些类似 VR 的场景。

  • ARGeoTrackingConfiguration:利用 GPS 与地图数据实现地理定位跟踪。

相较于 Reality Composer ,使用代码,我们可以创建更多的锚定类型,以应对更加复杂的 AR 场景需求。

我们需要根据口张开的程度来控制眼球的大小,那么如何获取需要的信息呢?

每个 AR 会话(ARSession)在启动后,会根据其设置的 ARConfiguration 种类返回不同的数据信息。例如:ARGeoAnchor 将返回经纬度和高度信息,而 ARBodyAnchor 将返回躯干和各个关节的位置信息。对于我们当前的场景,则需要通过 ARFaceAnchor 获取面部各个器官的运动信息。

这些信息将通过 ARSession 配置的 Delegate 返回给开发者。我们只需要根据这些信息,对场景中的物体进行调整,便可以实现我们的需求。

进一步调整我们的代码,在 ARViewContainer 中添加如下的代码:

Swift 复制代码
func makeCoordinator() -> Coordiantor {
    Coordiantor(arViewContainer: self)
}

class Coordiantor: NSObject, ARSessionDelegate {
    var arViewContainer: ARViewContainer
    var face: GoldenEye.Eyes!
    init(arViewContainer: ARViewContainer) {
        self.arViewContainer = arViewContainer
        super.init()
    }

    // 锚点信息发生变化时会调用
    func session(_: ARSession,
                 didUpdate anchors: [ARAnchor])
    {
        guard let face else { return }
        var faceAnchor: ARFaceAnchor?
        for anchor in anchors {
            if let a = anchor as? ARFaceAnchor {
                faceAnchor = a
            }
        }
        // 特定面部特征的标识符,用于描述这些特征相对运动的系数
        let blendShapes = faceAnchor?.blendShapes
        
        // 下颌开口的系数,用来判断嘴的开合大小
        if let jawOpen = blendShapes?[.jawOpen]?.floatValue {

            // 通过下颚的开合系数来调整眼球的尺寸
            face.eyeL?.scale = SIMD3<Float>(1, 1, 1) * (0.3 + jawOpen / 2)
            face.eyeR?.scale = SIMD3<Float>(1, 1, 1) * (0.3 + jawOpen / 2)
        }
    }

    // 移除锚点时会调用
    func session(_: ARSession, didRemove _: [ARAnchor]) {
        print("didRemove")
    }

    // 添加锚点时会调用
    func session(_: ARSession, didAdd _: [ARAnchor]) {
        print("didAdd")
    }
}

在上面这段代码中,我们创建了一个符合 ARSessionDelegate 协议的 Coordiantor 类。在 session(_: ARSession, didUpdate anchors: [ARAnchor]) 方法中,我们将根据 ARFaceAnchor 提供的 BlendShapeLocation 信息中有关下颚运动的数据来调整眼球的大小。

BlendShapeLocation 提供了非常丰富的面部运动细节,包括眼睛、嘴巴、下巴、眉毛、脸颊、鼻子等。更多详情请参阅 官方文档

最后,在 makeUIView 方法中为 ARSession 配置 delegate。

Swift 复制代码
...

// 设置 delegate
arView.session.delegate = context.coordinator
context.coordinator.face = arAnchor

return arView

至此,我们已经完成了所有的代码,创建了一个具备根据张嘴大小改变眼球尺寸的独立 AR 应用。

我们保留并使用了在 Reality Composer 项目中的绝大多数信息,包括名称、球体尺寸、预设位置、材质以及行为,这就使得代码非常简单。即使没有在代码中添加处理手势的代码,球体已然具备在 AR 场景中点击后播放声音的能力。

通过 Reality Composer 和代码的结合,我们进一步开启了 AR 创意之门。原有的 Reality Composer 项目资产被最大限度地保留并发挥作用,从而大幅降低了代码的开发难度和工作量。我们可以在此基础上发散思维,拓展 AR 的潜在应用,并探索更广阔的创造空间。

不依赖 Reality Composer ,实现 AR 应用

读到此处,你或许会产生一个疑问:在 Apple 的 AR 开发过程中,我们必须使用 Reality Composer 吗?是否可以采用其他熟悉的引擎(如 Unity、Unreal)或完全通过代码来构建场景与交互逻辑?

放心,答案是显而易见的,这些选择同样开放且可行。Reality Composer 只是苹果提供的一种可选方案,用于简化 AR 开发流程,降低相关技术门槛。如果你已经熟练掌握其他引擎工具或对代码开发十分熟悉,采用 Reality Composer 绝非必需。

在 Apple 的 AR 开发过程中,只有 ARKit 框架是不可或缺的。

ARKit 为 AR 开发打开了大门,它是构建 AR 体验的基础与核心。开发者通过它获得场景数据与交互能力,得到将 AR 概念变为现实的工具与素材。此后,开发者可以根据兴趣与经验,选择合适的框架或直接编写代码,创作出色的 AR 效果。

以 Unity 为例,下图是在 Unity 里面进行移动端 AR 应用开发的技术框架图,这里其实可以看出 ARKit 的重要性,因为无论怎样,到底层都需要 ARKit 提供基础的 AR 能力,例如 SLAM 等等。

而这里,我们也提供一段在 Unity 中使用控制 GameObject 位置与旋转的演示代码,是不是一股弄弄的 ARKit 的感觉:

C# 复制代码
// 创建 ARSession 与配置
ARSession session = ARSession.instance; 
ARWorldTrackingConfiguration config = new ARWorldTrackingConfiguration();
session.runWithConfig(config);

// 获取相机图像并渲染到屏幕上
ARCameraBackground arCamera = FindObjectOfType<ARCameraBackground>();
if (arCamera != null)
    arCamera.enabled = true;

// 在场景中添加 ARAnchor 对像
ARRaycastManager raycastManager = GetComponent<ARRaycastManager>();
List<ARRaycastHit> hits = new List<ARRaycastHit>();
if (raycastManager.Raycast(touches[0].position, hits, UnityARVideoFormat.kARFBCameraPosition))
{
    //添加 Anchor 与 GameObject
    GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
    cube.transform.position = hits[0].pose.position;
    cube.transform.rotation = hits[0].pose.rotation;
}   

// 更新 Anchor 位置与姿态
for (int i = 0; i < anchors.Count; i++) 
{
    anchors[i].transform.position = anchors[i].anchor.transform.position;
    anchors[i].transform.rotation = anchors[i].anchor.transform.rotation;
}

接下来,我们将以上一节的需求为例,演示如何仅依赖代码创建同样功能的应用,而不需要使用 Reality Composer。

考虑到篇幅,本文仅介绍其中比较重要的部分,不对所有的代码进行解释。你可以在 此处 获取完整代码。

RealityKit 是苹果在 iOS 13 中推出的新一代 AR 开发框架。它基于 ARKit 打造,并在其基础上进行了进一步的封装与优化,提供更高层级的 AR 开发体验。

相比 ARKit,RealityKit 更加简单易用。它采用了 Entity-Component 的方式组织 AR 体验的构成元素,开发者无需过度关注底层实现细节,就可以轻松构建互动的 AR 效果。同时,RealityKit 也在视觉与交互体验上作出提高,增加了环境光、反射等效果,支持丰富的手势交互等,使 AR 内容与真实场景更加协调,交互也更加自然。

SceneKit 为 RealityKit 提供了 3D 渲染能力,Metal 则保证了 Rendering 的高性能实现。RealityKit 通过这些底层框架,在 ARKit 的数据基础上,实现了高质量的 3D 与 2D 混合渲染,为 AR 体验带来更高的真实感与体验度。

相较于采用其他框架的纯代码开发选项,RealityKit 往往是 AR 开发的最佳选择。它提供了更加简单和直接的开发体验,技术门槛也更低。

在 Xcode 中新建一个对增强现实应用程序项目,然后删除模板中的 Experience 文件。

请将 makeUIView 方法修改为以下代码:

Swift 复制代码
func makeUIView(context: Context) -> ARView {
    let arView = ARView(frame: .zero)
    let arConfiguration = ARFaceTrackingConfiguration()
    arView.session.run(arConfiguration, options: [.resetTracking, .removeExistingAnchors])
    return arView
}

同上文中介绍的一样,我们创建并启用了一个基于 ARFaceTrackingConfiguration 的 AR 会话。

在 ARViewContainer 中添加如下代码:

Swift 复制代码
func makeEyesAnchor() throws -> AnchorEntity {
    let eyesAnchor = AnchorEntity()
    let eyeBallSize: Float = 0.015 // 小球的尺寸
    let collisionBoxSize: Float = 0.03 // 碰撞盒的尺寸,用于判断点击

    // 创建左眼小球并设置位置
    let leftEyeBall = createEyeBall(scale: eyeBallSize)
    let leftEyeOffset = SIMD3<Float>(0.03, 0.02, 0.05) // 左眼位置
    leftEyeBall.name = "leftEye" // 左眼名称
    leftEyeBall.position = leftEyeOffset

    // 为左眼小球添加碰撞盒
    let leftEyeCollision = CollisionComponent(shapes: [ShapeResource.generateBox(size: [collisionBoxSize, collisionBoxSize, collisionBoxSize])])
    leftEyeBall.components.set(leftEyeCollision)

    eyesAnchor.addChild(leftEyeBall)

    // 创建右眼小球并设置位置
    let rightEyeBall = createEyeBall(scale: eyeBallSize)
    let rightEyeOffset = SIMD3<Float>(-0.03, 0.02, 0.05) // 右眼位置
    rightEyeBall.name = "rightEye" // 右眼名称
    rightEyeBall.position = rightEyeOffset

    // 为右眼小球添加碰撞盒
    let rightEyeCollision = CollisionComponent(shapes: [ShapeResource.generateBox(size: [collisionBoxSize, collisionBoxSize, collisionBoxSize])])
    rightEyeBall.components.set(rightEyeCollision)

    eyesAnchor.addChild(rightEyeBall)

    return eyesAnchor
}

func createEyeBall(scale: Float) -> ModelEntity {
    let eyeBall = ModelEntity(
        mesh: .generateSphere(radius: scale),
        materials: [SimpleMaterial(color: .yellow, isMetallic: true)]
    )
    return eyeBall
}

在这部分中,我们通过代码完成了之前在 Reality Composer 中创建球体、摆放球体、设置材质等操作。

return arView 代码的上方,添加:

Swift 复制代码
let arAnchor = try! makeEyesAnchor()
arView.scene.anchors.append(arAnchor)

此时,如果我们运行 App,球体并不会出现。这是因为我们还没有将它们的位置与面部的锚点绑定在一起。

在 ARViewContainer 中添加如下代码:

Swift 复制代码
func makeCoordinator() -> Coordinator {
    Coordinator(arViewContainer: self)
}

class Coordinator: NSObject, ARSessionDelegate {
    var arViewContainer: ARViewContainer
    var face: AnchorEntity?
    var player: AVAudioPlayer?
    init(arViewContainer: ARViewContainer) {
        self.arViewContainer = arViewContainer
        super.init()
    }

    func session(_: ARSession, didUpdate anchors: [ARAnchor]) {
        guard let faceAnchor = anchors.first as? ARFaceAnchor,
              let face = face
        else {
            return
        }

        // 更新头部实体的位置和方向
        let facePosition = simd_make_float3(faceAnchor.transform.columns.3)
        let faceOrientation = simd_quatf(faceAnchor.transform)
        face.position = facePosition
        face.orientation = faceOrientation

        // 获取头部节点的旋转值
        let faceRotation = face.orientation

        // 更新左眼小球的旋转
        if let leftEye = face.children.first(where: { $0.name == "leftEye" }) as? ModelEntity {
            let parentRotation = faceOrientation
            let eyeLocalRotation = simd_mul(parentRotation.inverse, faceRotation)
            leftEye.orientation = eyeLocalRotation
        }

        // 更新右眼小球的旋转
        if let rightEye = face.children.first(where: { $0.name == "rightEye" }) as? ModelEntity {
            let parentRotation = faceOrientation
            let eyeLocalRotation = simd_mul(parentRotation.inverse, faceRotation)
            rightEye.orientation = eyeLocalRotation
        }

        let maxScale: Float = 1.6 // 小球的最大缩放倍数

        // 获取张嘴程度
        let blendShapes = faceAnchor.blendShapes

        if let jawOpen = blendShapes[.jawOpen]?.floatValue {
            // 调整小球的缩放倍数
            let scale = 1 + (jawOpen * maxScale)

            face.children.compactMap { $0 as? ModelEntity }.forEach { eyeBall in
                eyeBall.scale = SIMD3<Float>(repeating: scale)
            }
        }
    }
}

同上节中的代码类似,在 session(_: ARSession, didUpdate anchors: [ARAnchor]) 回调方法中,我们根据面部的位置,不断的调整两个小球的位置,并根据张嘴的程度来调整小球的尺寸。

makeUIView 中的 arView.scene.anchors.append(arAnchor) 下方添加代码,设置 delegate:

Swift 复制代码
arView.session.delegate = context.coordinator
context.coordinator.face = arAnchor

此时运行应用,两个金色的小球已经绑定在两眼的位置,而且可以随着嘴巴的开合程度而变化大小。

最后我们将添加点击小球播放声音的功能。首先在 makeUIView 方法中为 AR 视图添加一个点击手势。

Swift 复制代码
let tapGesture = UITapGestureRecognizer(target: context.coordinator, action: #selector(context.coordinator.handleTap(_:)))
arView.addGestureRecognizer(tapGesture)
return arView

在 Coordinator 中添加响应手势和播放音频的代码:

Swift 复制代码
@objc func handleTap(_ gesture: UITapGestureRecognizer) {
    guard let arView = gesture.view as? ARView else { return }
    let touchLocation = gesture.location(in: arView)

    if let _ = arView.entity(at: touchLocation) {
        playSound()
    }
}

func playSound() {
    if player == nil {
        // 在项目中添加任意音频文件,并替换此处的文件名
        let fileName = "mixkit-classic-click.wav" 
        guard let url = Bundle.main.url(forResource: fileName, withExtension: nil) else {
            print("Sound file '\(fileName)' not found.")
            return
        }
        player = try! AVAudioPlayer(contentsOf: url)
        player?.prepareToPlay()
    }

    player?.play()
}

至此,我们没有依赖于任何 Reality Composer 资源便创建了具备同样功能的 AR 应用。当然,对于当前的需求,结合 Reality Composer 要比使用纯代码更加高效。不过只要按照上述逻辑,你就可以使用 ARKit 与你习惯的任何工具相结合,创造出想要的效果。

总结

通过阅读这篇文章,相信你已经对 AR 技术、苹果提供的 AR 工具有了初步的了解,并体验到了 AR 带来的新奇与创意。

文章中介绍的只是 AR 工具与技术中的小部分,在这里,我只想表达一个观点:AR 不再是什么遥不可及的未来技术,它已经悄然融入我们的生活,并持续改变着世界的样貌。

如果你想进一步了解 ARKit 或者开发 AR 应用,我强烈推荐你阅读 WWDC 中关于 AR 的 Session、官方提供的开发者文档以及专业书籍。此外,XR 基地也会在不久的将来推出有关苹果 AR 的教程,敬请期待。

AR 技术不仅局限于游戏与娱乐。在教育、医疗、工程与生产等领域,都有着巨大的应用潜力。如果你将来有机会从事这些行业,拥有 AR 技能无疑会为你带来更大的优势。

未来,将会有越来越多强大、智能、便捷的 AR 工具和技术涌现出来以帮助每一个人在现实与虚幻中尽情遨游。

最后,让我们一起期待 AR 带来的更多惊喜!玩得开心,用地畅快!

相关推荐
网安墨雨1 小时前
iOS应用网络安全之HTTPS
web安全·ios·https
福大大架构师每日一题3 小时前
37.1 prometheus管理接口源码讲解
ios·iphone·prometheus
BangRaJun1 天前
LNCollectionView-替换幂率流体
算法·ios·设计
刘小哈哈哈1 天前
iOS 多个输入框弹出键盘处理
macos·ios·cocoa
靴子学长1 天前
iOS + watchOS Tourism App(含源码可简单复现)
mysql·ios·swiftui
一如初夏丿1 天前
xcode15 报错 does not contain ‘libarclite‘
ios·xcode
杨武博2 天前
ios 混合开发应用白屏问题
ios
BangRaJun2 天前
LNCollectionView
android·ios·objective-c
二流小码农2 天前
鸿蒙元服务项目实战:终结篇之备忘录搜索功能实现
android·ios·harmonyos
TMGM202410282 天前
苹果将推出超薄和折叠款iPhone,2024年带来哪些变化?
ios·iphone