关于 realitykit-ar
面向 iOS 开发者的 RealityKit 与 ARKit 技能,介绍使用 RealityView 构建 AR 场景、放置和交互 3D 实体,以及场景理解。
主要功能
- 01使用 RealityView 呈现 AR 内容
- 02加载或生成 3D 实体
- 03将实体锚定到平面或世界位置
- 04通过射线检测放置对象
- 05使用手势选择和拖动实体
- 06处理场景更新事件
适用场景
- 01在检测到的表面放置 3D 模型
- 02构建可点击和拖动的 AR 对象
- 03按场景更新处理连续逻辑
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ dpearson2699/ swift-ios-skills --skill realitykit-ar安装后在 Claude Code 中输入/realitykit-ar确认已加载。
附带文件references/realitykit-patterns.md
详细介绍
RealityKit + ARKit
使用 RealityKit 进行渲染、使用 ARKit 进行世界跟踪,在 iOS 上构建 AR 体验。
涵盖 RealityView、实体管理、射线投射、场景理解和基于手势的交互。面向 Swift 6.2 / iOS 26+。
目录
设置
项目配置
- 将
NSCameraUsageDescription添加到 Info.plist - 在 iOS 上,RealityKit 默认通过
RealityViewCameraContent使用设备摄像头(iOS 18+、macOS 15+) - 在 iOS 上实现基本 AR 无需额外功能
设备要求
AR 功能要求设备搭载 A9 芯片或更新型号。显示 AR 界面前,请务必确认设备支持。
import ARKit
guard ARWorldTrackingConfiguration.isSupported else {
showUnsupportedDeviceMessage()
return
}
关键类型
| 类型 | 平台 | 作用 |
|---|---|---|
RealityView | iOS 18+、visionOS 1+ | 承载 RealityKit 内容的 SwiftUI 视图 |
RealityViewCameraContent | iOS 18+、macOS 15+ | 通过设备摄像头显示的内容 |
Entity | 全部 | 所有场景对象的基类 |
ModelEntity | 全部 | 带有可见 3D 模型的实体 |
AnchorEntity | 全部 | 将实体固定到现实世界中的锚点 |
RealityView 基础知识
RealityView 是 RealityKit 在 SwiftUI 中的入口。在 iOS 上,它提供
RealityViewCameraContent,通过设备摄像头进行渲染,以实现 AR。
import SwiftUI
import RealityKit
struct ARExperienceView: View {
var body: some View {
RealityView { content in
// content is RealityViewCameraContent on iOS
let sphere = ModelEntity(
mesh: .generateSphere(radius: 0.05),
materials: [SimpleMaterial(
color: .blue,
isMetallic: true
)]
)
sphere.position = [0, 0, -0.5] // 50cm in front of camera
content.add(sphere)
}
}
}
创建和更新模式
使用 update 闭包响应 SwiftUI 状态变化:
struct PlacementView: View {
@State private var modelColor: UIColor = .red
var body: some View {
RealityView { content in
let box = ModelEntity(
mesh: .generateBox(size: 0.1),
materials: [SimpleMaterial(
color: .red,
isMetallic: false
)]
)
box.name = "colorBox"
box.position = [0, 0, -0.5]
content.add(box)
} update: { content in
if let box = content.entities.first(
where: { $0.name == "colorBox" }
) as? ModelEntity {
box.model?.materials = [SimpleMaterial(
color: modelColor,
isMetallic: false
)]
}
}
Button("Change Color") {
modelColor = modelColor == .red ? .green : .red
}
}
}
加载和创建实体
从 USDZ 文件加载
异步加载 3D 模型,避免阻塞主线程:
RealityView { content in
if let robot = try? await ModelEntity(named: "robot") {
robot.position = [0, -0.2, -0.8]
robot.scale = [0.01, 0.01, 0.01]
content.add(robot)
}
}
以编程方式生成网格
// Box
let box = ModelEntity(
mesh: .generateBox(size: [0.1, 0.2, 0.1], cornerRadius: 0.005),
materials: [SimpleMaterial(color: .gray, isMetallic: true)]
)
// Sphere
let sphere = ModelEntity(
mesh: .generateSphere(radius: 0.05),
materials: [SimpleMaterial(color: .blue, roughness: 0.2, isMetallic: true)]
)
// Plane
let plane = ModelEntity(
mesh: .generatePlane(width: 0.3, depth: 0.3),
materials: [SimpleMaterial(color: .green, isMetallic: false)]
)
添加组件
实体使用 ECS(实体组件系统)架构。为实体添加组件以赋予其行为:
let box = ModelEntity(
mesh: .generateBox(size: 0.1),
materials: [SimpleMaterial(color: .red, isMetallic: false)]
)
// Make it respond to physics
box.components.set(PhysicsBodyComponent(
massProperties: .default,
material: .default,
mode: .dynamic
))
// Add collision shape for interaction
box.components.set(CollisionComponent(
shapes: [.generateBox(size: [0.1, 0.1, 0.1])]
))
// Enable input targeting for gestures
box.components.set(InputTargetComponent())
锚定和放置
AnchorEntity
使用 AnchorEntity 将内容锚定到检测到的表面或世界坐标位置:
RealityView { content in
// Anchor to a horizontal surface
let floorAnchor = AnchorEntity(.plane(
.horizontal,
classification: .floor,
minimumBounds: [0.2, 0.2]
))
let model = ModelEntity(
mesh: .generateBox(size: 0.1),
materials: [SimpleMaterial(color: .orange, isMetallic: false)]
)
floorAnchor.addChild(model)
content.add(floorAnchor)
}
锚点目标
| 目标 | 说明 |
|---|---|
.plane(.horizontal, ...) | 水平表面(地板、桌面) |
.plane(.vertical, ...) | 垂直表面(墙壁) |
.plane(.any, ...) | 任意检测到的平面 |
.world(transform:) | 固定的世界空间位置 |
射线投射
使用 RealityViewCameraContent 在 SwiftUI 视图坐标和 RealityKit 世界空间之间进行转换。结合 SpatialTapGesture,即可在用户点击检测到的表面时放置对象。
手势和交互
对实体使用拖动手势
struct DraggableARView: View {
var body: some View {
RealityView { content in
let box = ModelEntity(
mesh: .generateBox(size: 0.1),
materials: [SimpleMaterial(color: .blue, isMetallic: true)]
)
box.position = [0, 0, -0.5]
box.components.set(CollisionComponent(
shapes: [.generateBox(size: [0.1, 0.1, 0.1])]
))
box.components.set(InputTargetComponent())
box.name = "draggable"
content.add(box)
}
.gesture(
DragGesture()
.targetedToAnyEntity()
.onChanged { value in
let entity = value.entity
guard let parent = entity.parent else { return }
entity.position = value.convert(
value.location3D,
from: .local,
to: parent
)
}
)
}
}
点击以选择
.gesture(
SpatialTapGesture()
.targetedToAnyEntity()
.onEnded { value in
let tappedEntity = value.entity
highlightEntity(tappedEntity)
}
)
场景理解
逐帧更新
订阅场景更新事件以持续处理:
RealityView { content in
let entity = ModelEntity(
mesh: .generateSphere(radius: 0.05),
materials: [SimpleMaterial(color: .yellow, isMetallic: false)]
)
entity.position = [0, 0, -0.5]
content.add(entity)
_ = content.subscribe(to: SceneEvents.Update.self) { event in
let time = Float(event.deltaTime)
entity.position.y += sin(Float(Date().timeIntervalSince1970)) * time * 0.1
}
}
visionOS 说明
在 visionOS 上,ARKit 提供了不同的 API,包括 ARKitSession、
WorldTrackingProvider 和 PlaneDetectionProvider。这些 visionOS 专用类型在 iOS 上不可用。在 iOS 上,RealityKit 会通过 RealityViewCameraContent 自动处理世界跟踪。
常见错误
不要:跳过 AR 功能检查
并非所有设备都支持 AR。显示黑色摄像头画面且不提供任何反馈会让用户感到困惑。
// WRONG -- no device check
struct MyARView: View {
var body: some View {
RealityView { content in
// Fails silently on unsupported devices
}
}
}
// CORRECT -- check support and show fallback
struct MyARView: View {
var body: some View {
if ARWorldTrackingConfiguration.isSupported {
RealityView { content in
// AR content
}
} else {
ContentUnavailableView(
"AR Not Supported",
systemImage: "arkit",
description: Text("This device does not support AR.")
)
}
}
}
不要:同步加载大型模型
在主线程上加载大型 USDZ 文件会导致帧率下降和卡顿。
RealityView 的 make 闭包是 async 的——请使用它。
// WRONG -- synchronous load blocks the main thread
RealityView { content in
let model = try! Entity.load(named: "large-scene")
content.add(model)
}
// CORRECT -- async load
RealityView { content in
if let model = try? await ModelEntity(named: "large-scene") {
content.add(model)
}
}
不要:忘记为可交互实体添加碰撞和输入目标组件
手势仅适用于同时具有 CollisionComponent 和
InputTargetComponent 的实体。没有这些组件,点击和拖动操作会穿透实体。
// WRONG -- entity ignores gestures
let box = ModelEntity(mesh: .generateBox(size: 0.1))
content.add(box)
// CORRECT -- add collision and input components
let box = ModelEntity(
mesh: .generateBox(size: 0.1),
materials: [SimpleMaterial(color: .red, isMetallic: false)]
)
box.components.set(CollisionComponent(
shapes: [.generateBox(size: [0.1, 0.1, 0.1])]
))
box.components.set(InputTargetComponent())
content.add(box)
不要:在 update 闭包中创建新实体
SwiftUI 每次状态变化时都会运行 update 闭包。在其中创建实体会在每次渲染过程中重复添加内容。
// WRONG -- duplicates entities on every state change
RealityView { content in
// empty
} update: { content in
let sphere = ModelEntity(mesh: .generateSphere(radius: 0.05))
content.add(sphere) // Added again on every update
}
// CORRECT -- create in make, modify in update
RealityView { content in
let sphere = ModelEntity(mesh: .generateSphere(radius: 0.05))
sphere.name = "mySphere"
content.add(sphere)
} update: { content in
if let sphere = content.entities.first(
where: { $0.name == "mySphere" }
) as? ModelEntity {
// Modify existing entity
sphere.position.y = newYPosition
}
}
不要:忽略相机权限
iOS 上的 RealityKit 需要访问相机。如果用户拒绝授权,视图会显示黑屏,且不提供任何说明。
// WRONG -- no permission handling
RealityView { content in
// Black screen if camera denied
}
// CORRECT -- check and request permission
struct ARContainerView: View {
@State private var cameraAuthorized = false
var body: some View {
Group {
if cameraAuthorized {
RealityView { content in
// AR content
}
} else {
ContentUnavailableView(
"Camera Access Required",
systemImage: "camera.fill",
description: Text("Enable camera in Settings to use AR.")
)
}
}
.task {
let status = AVCaptureDevice.authorizationStatus(for: .video)
if status == .authorized {
cameraAuthorized = true
} else if status == .notDetermined {
cameraAuthorized = await AVCaptureDevice
.requestAccess(for: .video)
}
}
}
}
审核清单
- 在 Info.plist 中设置
NSCameraUsageDescription - 在展示 AR 视图前检查 AR 设备能力
- 请求相机权限,并在用户拒绝时通过备用界面妥善处理
- 在
make闭包中异步加载 3D 模型 - 在
make中创建实体,在update中修改实体(不要在update中创建实体) - 交互式实体同时具有
CollisionComponent和InputTargetComponent - 碰撞形状与实体的视觉尺寸相符
- 使用
SceneEvents.Update订阅处理逐帧逻辑(不要使用 SwiftUI 计时器) - 大型场景使用
ModelEntity(named:)异步加载,而不是Entity.load(named:) - 锚点实体根据使用场景指定合适的表面类型
- 设置实体名称,以便在
update闭包中查找
参考资料
- 扩展模式(物理、动画、光照、ECS):
references/realitykit-patterns.md - RealityKit 框架
- RealityView
- RealityViewCameraContent
- Entity
- ModelEntity
- AnchorEntity
- ARKit 框架
- iOS 中的 ARKit
- ARWorldTrackingConfiguration
- 从文件加载实体