背景
在体验HelloWorld时,很好奇每个功能是怎么实现的,但是这个demo复用了很多功能、数据模型,刚开始理解起来就比较困难。所以我就先从功能点来看,将复用的功能、数据模型都剔除掉,保证单一功能能解藕单独运行。
环境
Xcode:15.1 beta
VisionOS:1.0
梳理功能
地球自转
为了让模型更立体,后续的所有例子,都默认添加了光照
swift
import SwiftUI
import RealityKit
import RealityKitContent
struct EarthRotation: View {
@State var isRotation = false
@State var curEarth:Entity = Entity()
var body: some View {
ZStack{
RealityView { content in
guard let earth = await RealityKitContent.entity(named: "Globe") else {
return
}
earth.setSunlight(intensity: 14)
earth.scale = SIMD3(repeating: 0.3)
earth.orientation = .init(angle: 0, axis: [0, 1, 0])
curEarth = earth
content.add(earth)
} update: { content in
curEarth.components.set(RotationComponent(speed: isRotation ? 0.5 : 0))
}
Toggle("Rotation", isOn: $isRotation)
.toggleStyle(.button)
.padding(.top, 240)
}
}
init() {
RotationComponent.registerComponent()
RotationSystem.registerSystem()
}
}
#Preview {
EarthRotation()
}
1. 加载3D资源
这里和手势转动地球不一样,可以不用给Entity添加InputComponent
,因为这个时候我们并不需要一个手势去触发旋转。只要加载一个普通的3D资源就可以了。
2.添加自转组件
这里用到的了RotationComponent
、RotationSystem
,是一个完全自定义的组件。
swift
import SwiftUI
import RealityKit
/// Rotation information for an entity.
struct RotationComponent: Component {
var speed: Float
var axis: SIMD3<Float>
init(speed: Float = 1.0, axis: SIMD3<Float> = [0, 1, 0]) {
self.speed = speed
self.axis = axis
}
}
/// A system that rotates entities with a rotation component.
struct RotationSystem: System {
static let query = EntityQuery(where: .has(RotationComponent.self))
init(scene: RealityKit.Scene) {}
func update(context: SceneUpdateContext) {
for entity in context.entities(matching: Self.query, updatingSystemWhen: .rendering) {
guard let component: RotationComponent = entity.components[RotationComponent.self] else { continue }
entity.setOrientation(.init(angle: component.speed * Float(context.deltaTime), axis: component.axis), relativeTo: entity)
}
}
}
这里面会涉及到一个ECS
架构: Entity、Component、System。
Entity
负责加载资源,系统提供了旋转、位置、缩放等功能,可以添加多个Component
。
Component
就是一些功能组件,有输入、光照等系统准备好的组件,也可以自定义组件,自定义组件如果需要更新就需要用到System
,理论上Component
也可以添加多个System
System
中update
方法触发的两个时机:
RealityView
初始化时(只会触发System
中update
一定时间,不会一直触发)RealityView
的update
方法(每帧都会触发System
中update
)
注意: 由于用到了updatingSystemWhen: .rendering
,一旦开始更新之后,System
中update
方法每帧都会触发,相当于一直在触发entity.setOrientation
,所以才可以一直旋转下去。那么update
方法里面一定不能做耗时的操作,目前我只能想到两个方法来停止刷新,其他办法暂时还没找到。
1. 移除组件
其实移除组件后,并不能停止System
中update
方法,只是查询不到RotationComponent
swift
components.remove(RotationComponent.self)
2. 退出窗口
这个可以完全停止System
中update
方法
3.注册Component、System
在我们使用的时候,一定要注册自定义的Component、System,不然就没有任何效果
Swift
init() {
RotationComponent.registerComponent()
RotationSystem.registerSystem()
}