[VisionOS] 拆分HelloWorld的功能点 - 地球自转

背景

在体验HelloWorld时,很好奇每个功能是怎么实现的,但是这个demo复用了很多功能、数据模型,刚开始理解起来就比较困难。所以我就先从功能点来看,将复用的功能、数据模型都剔除掉,保证单一功能能解藕单独运行。

环境

Xcode:15.1 beta

VisionOS:1.0

梳理功能

graph LR; 功能点-->A(设置光照); style A fill:#bbf,color:#fff click A "https://juejin.cn/post/7298690615046651943" 功能点-->B(手势转动地球) style B fill:#bbf,color:#fff click B "https://juejin.cn/post/7298765809290706983" 功能点-->C(地球自转) 功能点-->D(地球跟随鼠标拖动) 功能点-->E(卫星围绕地球转动) 功能点-->F(月球围绕地球转动) 功能点-->G(沉浸式与窗口之间的切换)

地球自转

为了让模型更立体,后续的所有例子,都默认添加了光照

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.添加自转组件

这里用到的了RotationComponentRotationSystem,是一个完全自定义的组件。

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

Systemupdate方法触发的两个时机:

  • RealityView初始化时(只会触发Systemupdate一定时间,不会一直触发)
  • RealityViewupdate方法(每帧都会触发Systemupdate

注意: 由于用到了updatingSystemWhen: .rendering,一旦开始更新之后,Systemupdate方法每帧都会触发,相当于一直在触发entity.setOrientation,所以才可以一直旋转下去。那么update方法里面一定不能做耗时的操作,目前我只能想到两个方法来停止刷新,其他办法暂时还没找到。

1. 移除组件

其实移除组件后,并不能停止Systemupdate方法,只是查询不到RotationComponent

swift 复制代码
components.remove(RotationComponent.self)

2. 退出窗口

这个可以完全停止Systemupdate方法

3.注册Component、System

在我们使用的时候,一定要注册自定义的Component、System,不然就没有任何效果

Swift 复制代码
init() {
    RotationComponent.registerComponent()
    RotationSystem.registerSystem()
}
相关推荐
HarderCoder7 个月前
Apple Vision Pro 学习资料
visionos
苹果API搬运工7 个月前
试玩 RealityComposerPro 中的 Shader Graph:用圆环制作一个 Meta Logo
visionos·增强现实
苹果API搬运工7 个月前
我开源了个手势匹配框架,让你在模拟器调试 visionOS 手部追踪功能!
visionos·增强现实
苹果API搬运工7 个月前
只需三板斧!带你入门 visionOS 空间计算的数学与几何基础
visionos·增强现实
-九月新辰-8 个月前
Unity VisionOS开发流程
unity·游戏引擎·visionos
XR基地8 个月前
XR 世界导览021 | AVP App Store上线网页版、如何在AVP上快速匹配手势、AVP开发岗位
visionos
XR基地8 个月前
XR 世界导览#020-visionOS 1.1/Xcode 17.3/PICO 5.9.0 更新了!
unity3d·visionos
xChester8 个月前
visionOS 应用图标设计
前端·ios·visionos
XR基地9 个月前
XR 世界导览#019-Let's visionOS 大会/在 AVP 上玩手机或查看Spline的3D模型/用代码写ShaderGraph
unity3d·visionos
xChester9 个月前
VisionPro开发 - 轻松实现天空盒并添加光照
前端·ios·visionos