RealityKit AR 开发
swift import RealityKit import ARKit
---
## 创建第一个 AR 体验
### 使用 ARView
`ARView` 是 RealityKit 的核心视图容器,集成相机渲染与会话管理。
**SwiftUI 中的基本使用:**
```swift
import SwiftUI
import RealityKit
struct ContentView: View {
var body: some View {
ARViewContainer().edgesIgnoringSafeArea(.all)
}
}
struct ARViewContainer: UIViewRepresentable {
func makeUIView(context: Context) -> ARView {
let arView = ARView(frame: .zero)
return arView
}
func updateUIView(_ uiView: ARView, context: Context) {}
}
运行后,设备会自动启动 AR 会话,显示相机画面,并可寻找平面。
添加 3D 实体
RealityKit 使用 ModelEntity 表示可见的 3D 对象。最快的方法是创建一个简单立方体:
let box = ModelEntity(
mesh: .generateBox(size: 0.1),
materials: [SimpleMaterial(color: .blue, isMetallic: true)]
)
必须将实体添加到场景中。根实体是一个 AnchorEntity,用于将虚拟内容固定在真实世界某个位置。
理解锚点(AnchorEntity)
- AnchorEntity.world(transform:):固定在世界变换(相对于会话原点)。
- AnchorEntity.plane(…):自动放置在检测到的平面(如桌面、地板)上。
- AnchorEntity.image(…):绑定到被识别的图像。
- AnchorEntity.body(…):绑定到检测到的人体。
一个完整的“放置立方体在平面上”的例子:
func makeUIView(context: Context) -> ARView {
let arView = ARView(frame: .zero)
// 创建水平平面锚定
let anchor = AnchorEntity(plane: .horizontal)
let box = ModelEntity(
mesh: .generateBox(size: 0.2),
materials: [SimpleMaterial(color: .orange, roughness: 0.3, isMetallic: false)]
)
anchor.addChild(box)
arView.scene.addAnchor(anchor)
return arView
}
注意:仅当平面被检测到时,锚点内容才会显示。这是 RealityKit 自动化处理的优点。
Reality Composer 与 Reality Composer Pro
对于复杂场景,直接用代码创建所有实体非常低效。苹果提供可视化编辑工具:
- Reality Composer(支持 iOS/macOS):生成
.reality文件,可直接在项目中加载,支持交互、动画行为。 - Reality Composer Pro(Xcode 15+ 内置,面向 visionOS 与 iOS):更强的材质、粒子、空间音频编辑能力,输出
.usda或.usdz。
加载准备好的场景:
if let scene = try? Entity.load(named: "MyScene") {
anchor.addChild(scene)
}
你还可以在 Reality Composer 里设置触发行为(如点击播放动画),无需额外编写交互代码。
实体与组件系统
RealityKit 遵循 实体-组件(ECS) 设计模式。每个 Entity 是基本容器,它的功能(外观、物理、碰撞等)由附着的 Component 赋予。
实体层级
实体可包含子实体,形成树状结构。添加到锚点的实体称为根实体。
let parent = Entity()
let child = ModelEntity(mesh: ...)
parent.addChild(child)
常用组件
- ModelComponent – 控制网格和材质。
- CollisionComponent – 定义碰撞形状,允许射线检测和物理碰撞。
- PhysicsBodyComponent – 赋予实体物理属性(质量、受力模式)。
- PhysicsMotionComponent – 控制初速度与角速度。
- AnchoringComponent – 将实体绑定到 AR 锚点(用于直接添加实体的场景)。
- OpacityComponent – 调整透明度(需模型支持)。
- DirectionalLightComponent / SpotLightComponent / PointLightComponent – 灯光实体。
附加和修改组件:
var physics = PhysicsBodyComponent()
physics.mode = .dynamic // 受物理影响
physics.massProperties.mass = 2.0
box.components.set(physics)
// 一次性设置完整碰撞属性
let collision = CollisionComponent(shapes: [.generateBox(size: [0.2,0.2,0.2])])
box.components.set(collision)
自定义组件
你可以定义自己的组件,存储额外数据,并在系统循环中使用。
struct HealthComponent: Component {
var hitPoints: Int = 100
}
然后附加:
box.components.set(HealthComponent(hitPoints: 50))
访问:
if let health = box.components[HealthComponent.self] {
print(health.hitPoints)
}
交互与手势
RealityKit 提供了对实体进行手势操作的便捷方法,但需手动启用并处理碰撞。
点击检测与碰撞
实现点击实体并改变颜色,需要两个步骤:安装手势识别器,使用 arView.hitTest(_:) 进行射线检测。
SwiftUI 中结合 UIViewRepresentable 添加手势:
func makeUIView(context: Context) -> ARView {
let arView = ARView(frame: .zero)
let tapGesture = UITapGestureRecognizer(target: context.coordinator, action: #selector(Coordinator.handleTap(_:)))
arView.addGestureRecognizer(tapGesture)
context.coordinator.arView = arView
return arView
}
class Coordinator: NSObject {
weak var arView: ARView?
@objc func handleTap(_ gesture: UITapGestureRecognizer) {
guard let arView = arView else { return }
let location = gesture.location(in: arView)
if let entity = arView.entity(at: location) {
// 改变材质颜色
var material = SimpleMaterial(color: .random(), isMetallic: false)
if let model = entity as? ModelEntity {
model.model?.materials = [material]
}
}
}
}
注意:实体必须拥有 CollisionComponent 才能被射线命中。
拖拽与旋转
苹果提供内置的 EntityGestureRecognizer,只需将手势附加到 ARView 上即可实现平移(MoveTo)、缩放、旋转。通过 arView.installGestures(.all, for: entity) 一行代码即可激活所有交互手势。
示例:
// 对名为 box 的实体安装所有手势(拖拽、缩放、旋转)
arView.installGestures([.translation, .scale, .rotation], for: box)
这些手势会智能地保留在平面上的移动(Translation)模式,无需额外设置。
动画与视觉效果
RealityKit 的动画系统基于 Transform 的关键帧或直接操作组件。
基础变换动画
使用 move, scale, rotate 等方法:
let targetTransform = Transform(scale: [1.5, 1.5, 1.5],
rotation: simd_quatf(angle: .pi / 2, axis: [0,1,0]),
translation: [0, 0.1, 0])
entity.move(to: targetTransform, relativeTo: entity.parent, duration: 1.0, timingFunction: .easeInOut)
也可以使用 move(to:relativeTo:duration:timingFunction:) 实现相对运动。
使用 AnimationResource 播放 USDZ 动画
如果你的 USDZ 文件自带动画(如骨骼动画),可以获取动画资源并播放。
if let entity = try? Entity.load(named: "robot.usdz") {
anchor.addChild(entity)
if let animation = entity.availableAnimations.first {
entity.playAnimation(animation.repeat(duration: .infinity), transitionDuration: 0.5)
}
}
AnimationResource 支持循环、速度调节、混合等。
材质动画
直接修改材质属性(如颜色),配合 Timer 或 ARSession 更新循环实现动态效果。
物理模拟
RealityKit 的内置物理引擎非常强大,只需附加合适的组件即自动运行模拟。
- 静态(static):不移动,但可碰撞。
- 动态(dynamic):受力和碰撞影响。
- 运动学(kinematic):手动控制位置,但影响其他物体。
设置一个小球掉落的例子:
let sphere = ModelEntity(mesh: .generateSphere(radius: 0.05),
materials: [SimpleMaterial(color: .red, isMetallic: true)])
sphere.components.set(CollisionComponent(shapes: [.generateSphere(radius: 0.05)]))
var physics = PhysicsBodyComponent()
physics.mode = .dynamic
physics.massProperties.mass = 0.1
sphere.components.set(physics)
let anchor = AnchorEntity(plane: .horizontal)
anchor.addChild(sphere)
arView.scene.addAnchor(anchor)
再添加一个地面平面实体(静态):
let ground = ModelEntity(mesh: .generatePlane(width: 1, depth: 1),
materials: [OcclusionMaterial()]) // 透明但可碰撞
ground.components.set(CollisionComponent(shapes: [.generateBox(width: 1, height: 0.001, depth: 1)]))
ground.physicsBody = PhysicsBodyComponent(mode: .static)
anchor.addChild(ground)
也可以直接作用于检测到的真实平面网格(通过 SceneEvents.Update 获取实时网格),让虚拟物体与真实环境物理交互。
高级功能:图像/物体/身体跟踪
RealityKit 配合 ARKit 可轻松实现更高级的 AR 功能。
图像跟踪
- 在 Asset Catalog 中添加参考图像集,配置物理尺寸。
- 在 AR 配置中启用图像检测:
let config = ARWorldTrackingConfiguration()
if let images = ARReferenceImage.referenceImages(inGroupNamed: "AR Resources", bundle: nil) {
config.detectionImages = images
config.maximumNumberOfTrackedImages = 1
}
arView.session.run(config)
- 使用
AnchorEntity(.image(group:name:))自动放置内容,检测到图像后出现。
物体检测
类似图像,使用 ARReferenceObject 扫描真实物体,将其导入 Asset Catalog,用 detectionObjects 配置会话。
身体跟踪
iOS 13+ 支持 2D 人体检测,iOS 14+ 支持 3D 人体运动捕捉。RealityKit 提供 AnchorEntity(.body),可追踪手、头、脚等部位。
let config = ARBodyTrackingConfiguration()
arView.session.run(config)
let bodyAnchor = AnchorEntity(.body)
// 添加跟随手腕的球体
if let wrist = bodyAnchor.findEntity(named: "left_wrist") {
wrist.addChild(sphere)
}
需要导入 Apple 的官方身体骨骼模型,或者通过骨骼名称直接放置。
调试与常见问题
真实设备必须
模拟器仅能显示相机源而无法运行 AR 会话,始终用真机测试。
实体不可见检查清单
- 是否添加了锚点?锚点是否被 ARKit 检测到?
- 是否赋予了材质?简单网格可能默认黑色而看不清。
- 实体位置是否在相机后方或被遮挡?
- 是否开启了
showStatistics以查看帧率和实体数量?
性能优化
- 控制场景中的实体数量,使用 LOD(细节层次)或 USDZ 变体。
- 减少动态物理体数量,用静态或运动学代替。
- 尽量合并静态网格。
- 开启
Configuration中的isLightEstimationEnabled以获得自动光照。
视频录制与截图
// 截图
arView.snapshot(saveToHDR: false) { image in /* 使用 UIImage */ }
// 视频录制
arView.session.captureHighResolutionFrame { (frame, error) in ... }