背景
在体会HelloWorld时,很猎奇每个功用是怎么实现的,但是这个demo复用了很多功用、数据模型,刚开始理解起来就比较困难。所以我就先从功用点来看,将复用的功用、数据模型都剔除去,确保单一功用能解藕独自运行。
环境
Xcode:15.1 beta
VisionOS:1.0
整理功用
graph LR;
功用点-->A(设置光照);
style A fill:#bbf,color:#fff
click A "https://www.6hu.cc/post/7298690615046651943"
功用点-->B(手势滚动地球)
style B fill:#bbf,color:#fff
click B "https://www.6hu.cc/post/7298765809290706983"
功用点-->C(地球自转)
功用点-->D(地球跟从鼠标拖动)
功用点-->E(卫星环绕地球滚动)
功用点-->F(月球环绕地球滚动)
功用点-->G(沉浸式与窗口之间的切换)
地球自转
为了让模型更立体,后续的一切例子,都默许增加了光照
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
,是一个彻底自定义的组件。
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
components.remove(RotationComponent.self)
2. 退出窗口
这个能够彻底中止System
中update
办法
3.注册Component、System
在咱们使用的时候,必定要注册自定义的Component、System,否则就没有任何效果
init() {
RotationComponent.registerComponent()
RotationSystem.registerSystem()
}