Day 4中咱们使用了ImmersiveSpace并在其间增加了一个立方体,但对这个立方体咱们只装备了长宽高,并没有做进一步的操作。

本文中咱们会经过纹路和原料对这个立方体的六个面别离进行不同的制作。首要咱们将ImmersiveView分拆出来,先新建一个ImmersiveView.swift文件,这是一个视图文件,所以请挑选User Interface下的Swift View完成创立,其间的内容待咱们编写完ViewModel中的代码后再进行修正。

咱们经过点击界面来翻开沉溺式视图,所以需求一个ContentView.swift文件来编写惯例的窗口页面,在其间增加一个Toggle开关,用于翻开和封闭沉溺式视图。

import SwiftUI
import RealityKit
struct ContentView: View {
    @State var showImmsersiveSpace = false
    @Environment(.openImmersiveSpace) var openImmersiveSpace
    @Environment(.dismissImmersiveSpace) var dismissImmersiveSpace
    var body: some View {
        NavigationStack {
            VStack {
                Toggle("Show ImmersiveSpace", isOn: $showImmsersiveSpace)
                    .toggleStyle(.button)
            }
            .padding()
        }
        .onChange(of: showImmsersiveSpace) { _, newValue in
            Task {
                if newValue {
                    await openImmersiveSpace(id: "ImmersiveSpace")
                } else {
                    await dismissImmersiveSpace()
                }
            }
        }
    }
}
#Preview {
    ContentView()
}

首要咱们界说了一个showImmsersiveSpace变量供Toggle按钮开关时使用。然后要翻开和封闭沉溺式空间,咱们能够别离使用@Environment中的openImmersiveSpacedismissImmersiveSpace,经过onChange修饰符来监控showImmsersiveSpace变量的变化,在切换到翻开时,就翻开沉溺式空间。咱们需求知道翻开哪一个视图,所以使用了id参数,这个参数应与使用进口文件中所设置的一致。

接下来就编写进口文件:

import SwiftUI
@main
struct visionOSDemoApp: App {
    var body: some Scene {
        WindowGroup() {
            ContentView()
        }
        ImmersiveSpace(id: "ImmersiveSpace") {
            ImmersiveView()
        }
    }
}

注意这儿ImmersiveSpace中所增加的id与之前ContentView中的要保持一致,咱们在后面会学到在同一个使用中也能够增加多个WindowGroup,相同经过装备id进行区别。

接下来是核心文件ViewModel.swift

import SwiftUI
import RealityKit
@MainActor class ViewModel: ObservableObject {
    private var contentEntity = Entity()
    func setupContentEntity() -> Entity {
        return contentEntity
    }
    func addCube() {
        guard
            let texture1 = try? TextureResource.load(named: "Number_1"),
            let texture2 = try? TextureResource.load(named: "Number_2"),
            let texture3 = try? TextureResource.load(named: "Number_3"),
            let texture4 = try? TextureResource.load(named: "Number_4"),
            let texture5 = try? TextureResource.load(named: "Number_5"),
            let texture6 = try? TextureResource.load(named: "Number_6")
        else {
            fatalError("Unable to load texture.")
        }
        let entity = Entity()
        var material1 = SimpleMaterial()
        var material2 = SimpleMaterial()
        var material3 = SimpleMaterial()
        var material4 = SimpleMaterial()
        var material5 = SimpleMaterial()
        var material6 = SimpleMaterial()
        material1.color = .init(texture: .init(texture1))
        material2.color = .init(texture: .init(texture2))
        material3.color = .init(texture: .init(texture3))
        material4.color = .init(texture: .init(texture4))
        material5.color = .init(texture: .init(texture5))
        material6.color = .init(texture: .init(texture6))
        entity.components.set(ModelComponent(
            mesh: .generateBox(width: 0.5, height: 0.5, depth: 0.5, splitFaces: true),
            materials: [material1, material2, material3, material4, material5, material6]
        ))
        entity.position = SIMD3(x: 0, y: 1, z: -2)
        contentEntity.addChild(entity)
    }
}

相同咱们创立了setupContentEntity()办法,但并没有在办法里增加任何模型,而是将增加的作业交给了addCube()办法,整个办法尽管很长,但有大量重复的代码,别离为六个面设置不同的图片。

  1. 经过TextureResource.load()办法设置了不同的纹路
  2. 接着使用SimpleMaterial()创立了六个原料
  3. 经过原料的color特点别离增加前面装备好的纹路

Number_1.jpg等图片请见咱们GitHub的演示代码,咱们先来说一下visionOS中的原料,常见的原料请见下图:

visionOS空间核算实战开发教程Day 5 纹路和原料

其间PhysicallyBasedMaterial也即PBR和SimpleMaterial是带光照信息的,而UnlitMaterialVideoMaterial都是不带光照信息的。

ModelComponent办法中,咱们使用了meshmaterials参数,mesh参数咱们相同使用了MeshResource.generateBox来创立一个立方体,不同的是这次咱们指定了splitFaces参数,该参数设为true表明顶点不进行合并,由于咱们要对六个面别离设置色彩或图画,不指定该参数六个面都会使用相同的原料,在本例中也便是都显现为1

最后咱们装备了position,这儿x, y, z坐标轴方向暗示如下:

visionOS空间核算实战开发教程Day 5 纹路和原料

接下来咱们修正ImmersiveView.swift的内容如下:

import SwiftUI
import RealityKit
struct ImmersiveView: View {
    @StateObject var model = ViewModel()
    private var contentEntity = Entity()
    var body: some View {
        RealityView { content in
            content.add(model.setupContentEntity())
            model.addCube()
        }
    }
}

这儿的代码相对简单,便是在RealityView中展现ViewModel中所增加的模型。

在运行使用前将Info.plist文件中的Preferred Default Scene Session Role切换回Window Application Session Role

点击Show ImmersiveSpace按钮,会得到如下界面:

visionOS空间核算实战开发教程Day 5 纹路和原料

再次点击按钮就会收起这个模型。

示例代码:GitHub仓库

其它相关内容请见虚拟实际(VR)/增强实际(AR)&visionOS开发学习笔记