布景
在体会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(地球自转)
style C fill:#bbf,color:#fff
click C "https://www.6hu.cc/post/7298775642261569575"
功用点-->D(地球跟随鼠标拖动)
style D fill:#bbf,color:#fff
click D "https://www.6hu.cc/post/7299037876637351975"
功用点-->E(卫星环绕地球滚动)
style E fill:#bbf,color:#fff
click E "https://www.6hu.cc/post/7300431522255241250"
功用点-->G(沉浸式与窗口之间的切换)
style G fill:#bbf,color:#fff
click G "https://www.6hu.cc/spost/7300816733525901352"
卫星环绕地球滚动
这儿尽管只展现了卫星运动,其实月球和它相同,仅仅去掉了轨道。
import SwiftUI
import RealityKit
struct SatelliteAroundEarth: View {
@State private var earthEntity: EarthEntity?
var body: some View {
RealityView { content in
let earth = await EarthEntity(name: "")
earth.setSunlight(intensity: 14)
content.add(earth)
self.earthEntity = earth
earth.update()
}
}
init() {
TraceComponent.registerComponent()
TraceSystem.registerSystem()
}
}
#Preview {
SatelliteAroundEarth()
}
这个是HelloWorld里边最有意思的一个场景,地球在自转,一颗卫星环绕地球运转,后边拖着长长的白色轨道。
1. 资源
和地球自转相同,一个一般的资源就可以了,不用在Reality Composer Pro
里边增加任何组件。
2. 滚动
2.1 原理
假如要了解卫星怎样环绕地球滚动,首先要了解Entity
。
Entity
我了解,便是一个3D的容器,它既可以加载一个本地的资源,也可以addChild
增加其他Entity
,相似UIView
。
旋转很好了解,在地球自转里边,我们现已自定义了一个RotationComponent
绕Y轴旋转的组件,Entity.components
增加组件就可以轻松完成旋转。
举个例子,如下图,Entity1
增加了一个Y轴旋转的组件,那么Entity1
就会环绕Y轴开端旋转。
Entity1
增加一个Entity2
,假如不改动Entity2
的方位,默认两个原点都是[0,0,0],也便是Entity1
和Entity2
一起往相同方向旋转,视觉上看起来是重叠的。
假如想要让Entity2
环绕Entity1
旋转呢?只需要给Entity2
设置一个Z轴上的偏移量(默认单位m),[0,0.1,0]。还是把Entity1
、Entity2
当作一个全体,这个全体是环绕Entity1
的原点做Y轴旋转,那么视觉上看起来便是Entity2
环绕Entity1
旋转。
2.2 完成一个简略的环绕旋转
import SwiftUI
import RealityKit
import RealityKitContent
struct EarthAround: View {
var body: some View {
RealityView { content in
guard let earth = await RealityKitContent.entity(named: "Earth") else {
return
}
let orbit = Entity()
// 增加一个Y轴旋转
orbit.components.set(RotationComponent(speed: 0.5))
content.add(orbit)
// 为了让地球更立体,增加光线
earth.setSunlight(intensity: 14)
// 地球模型太大,适当的缩放,防止超出窗口
earth.scale = SIMD3(repeating: 0.1)
// 设置Z轴偏移
earth.position = [0,0,0.1]
orbit.addChild(earth)
}
}
init() {
RotationComponent.registerComponent()
RotationSystem.registerSystem()
}
}
#Preview {
EarthAround()
}
用刚才的图了解一下,便是这样的。
2.3 自定义卫星组件
import SwiftUI
import RealityKit
import RealityKitContent
class SatelliteEntity: Entity {
private var satellite = Entity()
private let box = Entity()
private let orbit = Entity()
init(_ configuration: Configuration) async {
super.init()
guard let satellite = await RealityKitContent.entity(named: configuration.name) else { return }
self.satellite = satellite
orbit.components.set(RotationComponent(speed: 0))
// 在Y轴上的旋转视点
orbit.orientation = .init(angle: Float(configuration.initialRotation.radians), axis: [0,1,0])
self.addChild(orbit)
orbit.addChild(box)
box.addChild(satellite)
}
@MainActor required init() {
super.init()
}
func update(anchor: Entity, configuration: Configuration, speed: Float){
// 在Z轴上的旋转视点,可以调整卫星与赤道的夹角
let newOrientation = simd_quatf(angle: Float(configuration.inclination.radians), axis: [0, 0, 1])
orientation = newOrientation
// Y轴自旋转
if var rotation: RotationComponent = orbit.components[RotationComponent.self]{
rotation.speed = configuration.speedRatio * speed
orbit.components[RotationComponent.self] = rotation
}
// 卫星所在box,缩放、方位
box.scale = SIMD3(repeating: configuration.scale)
box.position = [0,0,configuration.altitude]
// 卫星更新轨道
satellite.updateTrace(anchor: anchor,
width: configuration.traceWidth,
isVisible: configuration.isTraceVisible,
isPaused: false)
}
}
那这儿就略微复杂一点了,里边涉及到的Entity
、Component
比较多。
白色轨道组件TraceComponent
就没有深究了,里边涉及到MeshResource
、TextureResource
,现在还不是很懂。
2.4 卫星环绕地球滚动
import SwiftUI
import RealityKit
import RealityKitContent
class EarthEntity: Entity {
/// The model that draws the Earth's surface features.
private var earth: Entity = Entity()
/// A container for artificial satellites.
private var satellites = Entity()
init(name: String) async {
super.init()
guard let earth = await RealityKitContent.entity(named: name) else {return}
self.earth = earth
await satellites = SatelliteEntity(.orbitSatelliteDefault)
self.addChild(earth)
self.addChild(satellites)
update()
}
@MainActor required init() {
super.init()
}
func update(){
// 增加地球自转
if var rotation: RotationComponent = earth.components[RotationComponent.self] {
rotation.speed = 0.1
earth.components[RotationComponent.self] = rotation
} else {
earth.components.set(RotationComponent(speed: 0.1))
}
// 更新卫星的数据
(satellites as? SatelliteEntity)?.update(anchor: earth, configuration: .orbitSatelliteDefault, speed: 0.1)
// 现在只用到了缩放
move(
to: Transform(
scale: SIMD3(repeating: 0.3),
rotation: orientation,
translation: .zero),
relativeTo: parent)
}
}
现在是把所有逻辑都封装在EarthEntity
,在外面运用就比较简略。
代码
都可以独自运转
2.2 完成一个简略的环绕旋转运转EarthAround.swift
2.4 卫星环绕地球滚动
运转SatelliteAroundEarth.swift
,里边也包含了月球。
注意:只要了解了卫星环绕地球的原理,其实就可以复用到月球,所以卫星、月球的代码放在一起展现。当然也一个独自的月球环绕的Demo,逻辑是相同的。