关于 realitykit
这项 Swift 技能介绍如何用 RealityKit 和 ARKit 构建 iOS 增强现实体验,面向开发者。内容涵盖场景设置、实体放置与交互,并说明设备支持检查和性能注意事项。
主要功能
- 01RealityView 场景设置
- 02实体创建与放置
- 03锚点与表面射线检测
- 04基于手势的实体交互
- 05场景更新与平台说明
适用场景
- 01为 iOS 应用构建 AR 场景
- 02将模型放置在检测到的表面上
- 03为 3D 实体添加触控交互
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ dpearson2699/ swift-ios-skills --skill realitykit安装后在 Claude Code 中输入/realitykit确认已加载。
附带文件evals/evals.jsonreferences/realitykit-patterns.md
详细介绍
RealityKit
使用 RealityKit 进行渲染、使用 ARKit 进行世界追踪,在 iOS 上构建 AR 体验。
涵盖 RealityView、实体管理、射线投射、场景理解和基于手势的交互。目标平台为 Swift 6.3 / iOS 26+。
目录
设置
项目配置
- 在 Info.plist 中添加
NSCameraUsageDescription - 在 iOS 上,
RealityViewCameraContent默认显示 AR 相机视图(iOS 18+、macOS 15+);如需明确回退到非 AR 模式,请使用.virtual相机模式 - 基础 AR 不需要任何授权能力。如果 AR 是应用的核心功能,请添加
arkit必需设备能力;否则,请使用isSupported控制 AR 界面的显示。
设备要求
在显示 AR 界面之前,检查确切 AR 配置的 isSupported 值。
import ARKit
guard ARWorldTrackingConfiguration.isSupported else {
showUnsupportedDeviceMessage()
return
}
主要类型
| 类型 | 平台 | 作用 |
|---|---|---|
RealityView | iOS 18+、visionOS 1+ | 承载 RealityKit 内容的 SwiftUI 视图 |
RealityViewCameraContent | iOS 18+、macOS 15+ | 在 iOS 上通过 AR 相机视图显示、在 macOS 上以非 AR 方式显示的内容 |
Entity | 全部 | 所有场景对象的基类 |
ModelEntity | 全部 | 包含可见 3D 模型的实体 |
AnchorEntity | 全部 | 将实体固定到现实世界的锚点 |
RealityView 基础
RealityView 是使用 RealityKit 的 SwiftUI 入口。
RealityViewCameraContent 是 iOS/macOS 内容类型。在 iOS 上,它默认使用 AR
相机视图;在需要非 AR 模式或无法访问 AR/相机时,可以设置 content.camera = .virtual。
import ARKit
import SwiftUI
import RealityKit
struct ARExperienceView: View {
var body: some View {
RealityView { (content: RealityViewCameraContent) in
if !ARWorldTrackingConfiguration.isSupported {
content.camera = .virtual
}
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)
}
}
添加组件
实体采用 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:) | 固定的世界空间位置 |
射线投射
将 RealityKit 场景查询与 ARKit 现实世界射线投射分开处理:
RealityViewCameraContent.ray(through:in:to:)返回 RealityKit 坐标空间中的相机射线。它会将屏幕点投射到虚拟场景中,并不能证明检测到了物理表面。RealityViewCameraContent.hitTest(point:in:query:mask:)会命中通过CollisionComponent形状设为可命中的虚拟实体。使用这些形状来拾取实体和定向手势,而不是用于 ARKit 平面检测。- 使用
AnchorEntity(.plane(...))在检测到的平面上进行简单放置。 - 当任务需要与现实世界表面进行一次性交点计算时,使用 ARKit
ARRaycastQuery和ARSession.raycast(_:),然后使用AnchorEntity(raycastResult:)进行锚定。
let results = session.raycast(query)
if let result = results.first {
let anchor = AnchorEntity(raycastResult: result)
anchor.addChild(model)
content.add(anchor)
}
不要将实体命中测试视为 ARKit 表面射线投射的替代方案。
手势和交互
要通过手势与实体交互,请为可命中的形状添加 CollisionComponent,并为输入目标添加 InputTargetComponent。
实体拖动手势
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
)
}
)
}
}
场景理解
逐帧更新
订阅 SceneEvents.Update 来持续处理场景,而不是用 SwiftUI 计时器驱动
RealityKit。保持订阅处于活动状态,并使用
event.deltaTime;请参阅实体动画。
平台边界
在 visionOS 上,ARKit 提供了不同的 API,包括 ARKitSession、
WorldTrackingProvider 和 PlaneDetectionProvider。这些 visionOS 专用
类型在 iOS 上不可用。在 iOS 上,RealityKit 通过 RealityViewCameraContent
自动处理世界跟踪。
对于 iOS 架构或迁移说明,请使用
ARWorldTrackingConfiguration.isSupported 检查 AR 支持情况,使用
RealityViewCameraContent 承载内容,并通过放置在 AnchorEntity 中的
Entity/ModelEntity 构建场景。
交接: CollisionComponent + InputTargetComponent 负责 RealityKit
交互;AccessibilityComponent 负责实体辅助功能元数据;详细的 SwiftUI
手势和 VoiceOver/Switch Control 策略由相关章节处理。
将现有的 SCNView/SCNNode 工作视为独立的 SceneKit 路径,或明确迁移到
RealityKit,而不要混用场景图。
常见错误
不要:跳过 AR 功能检查
在展示 AR 前,使用“设置”中的配置专属支持检查。如果检查未通过,则显示非 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)
}
}
不要:忘记为可交互实体添加碰撞和输入目标组件
可交互实体需要手势和交互中所示的两个组件;缺少 这些组件时,点击和拖动事件会穿透。
不要:在更新闭包中创建新实体
每次 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
- 请求相机权限,并在用户拒绝时通过备用 UI 进行处理
- 当 AR 是应用的核心用途时,添加
arkit必需设备功能 - 在
make闭包中异步加载 3D 模型 - 在
make中创建实体,在update中修改实体(不要在update中创建) - 交互前提条件和相关章节的交接遵循“手势”部分的说明
- 实体命中测试、相机射线和 ARKit 表面射线投射遵循射线投射的区分说明
- 使用
SceneEvents.Update订阅处理逐帧逻辑(不要使用 SwiftUI 计时器) - 大型场景使用
ModelEntity(named:)异步加载,而不是Entity.load(named:) - 锚点实体根据使用场景选择合适的表面类型
- 设置实体名称,以便在
update闭包中查找实体