RealityKit AR 开发

FreeGuideOnline 15阅读 2026-07-11

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 支持循环、速度调节、混合等。

材质动画

直接修改材质属性(如颜色),配合 TimerARSession 更新循环实现动态效果。


物理模拟

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 功能。

图像跟踪

  1. 在 Asset Catalog 中添加参考图像集,配置物理尺寸。
  2. 在 AR 配置中启用图像检测:
let config = ARWorldTrackingConfiguration()
if let images = ARReferenceImage.referenceImages(inGroupNamed: "AR Resources", bundle: nil) {
    config.detectionImages = images
    config.maximumNumberOfTrackedImages = 1
}
arView.session.run(config)
  1. 使用 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 ... }