visionOS空间计算实战开发教程Day 5 纹理和材质

在​​Day 4​​​中我们使用了​​ImmersiveSpace​​并在其中添加了一个立方体,但对这个立方体我们只配置了长宽高,并没有做进一步的操作。

本文中我们会通过纹理和材质对这个立方体的六个面分别进行不同的绘制。首先我们将​​ImmersiveView​​分拆出来,先新建一个​​ImmersiveView.swift​​文件,这是一个视图文件,所以请选择User Interface下的Swift View完成创建,其中的内容待我们编写完​​ViewModel​​中的代码后再进行修改。

我们通过点击界面来打开沉浸式视图,所以需要一个​​ContentView.swift​​文件来编写常规的窗口页面,在其中添加一个Toggle开关,用于打开和关闭沉浸式视图。

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

首先我们定义了一个​​showImmsersiveSpace​​变量供Toggle按钮开关时使用。然后要打开和关闭沉浸式空间,我们可以分别使用​​@Environment​​中的​​openImmersiveSpace​​和​​dismissImmersiveSpace​​,通过​​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() {guardlet 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中的材质,常见的材质请见下图:

材质 Material

其中​​PhysicallyBasedMaterial​​也即PBR和​​SimpleMaterial​​是带光照信息的,而​​UnlitMaterial​​和​​VideoMaterial​​都是不带光照信息的。

在​​ModelComponent​​方法中,我们使用了​​mesh​​和​​materials​​参数,​​mesh​​参数我们同样使用了​​MeshResource.generateBox​​来创建一个立方体,不同的是这次我们指定了​​splitFaces​​参数,该参数设为​​true​​表示顶点不进行合并,因为我们要对六个面分别设置颜色或图像,不指定该参数六个面都会使用相同的材质,在本例中也就是都显示为​​1​​。

最后我们配置了​​position​​,这里x, y, z坐标轴方向示意如下:

visionOS坐标轴方向

接下来我们修改​​ImmersiveView.swift​​的内容如下:

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

这里的代码相对简单,就是在​​RealityView​​中展示​​ViewModel​​中所添加的模型。

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

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

Show ImmersiveSpace

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

示例代码:​​GitHub仓库​​

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/208839.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

宽压12-90V转5V3A降压IC,AH8691芯片

## 宽压12-90V转5V3A降压IC,多重保护功能全面升级 1. **宽压输入范围**:8V-100V,支持输出电压低至3.3V 2. **高效转换**:5A典型峰值开关电流,高达95%的转换效率 3. **多重保护**:包括过流、过热、输出短路…

联想拯救者Lenovo Legion R9000K 2021H(82N6)原装出厂Windows10/Win11系统ISO镜像

链接:https://pan.baidu.com/s/13NkeCXNdV0Ib5eeRnZUeAQ?pwdnlr7 提取码:nlr7 拯救者笔记本电脑原厂WIN系统自带所有驱动、出厂主题壁纸、系统属性专属LOGO标志、Office办公软件、联想电脑管家等预装程序 所需要工具:16G或以上的U盘 文…

如何准备软考-软件设计师(下)

前言: 下午的题目一般有6道题目,前4题是必答题,第5题和第6题二选一。每题15分,一共75分,45分即可通过。 接下来,我们以2022下半年软件设计师案例来当作教材来讲,下午的每种类型的题目该如何去…

80基于matlab的小波包熵与模糊C均值聚类的故障诊断,以凯斯西储大学轴承数据为例进行分析

基于matlab的小波包熵与模糊C均值聚类的故障诊断,以凯斯西储大学轴承数据为例进行分析。对数据进行小波包分解后重构,然后提取各频带能量分布,后计算小波包熵进行故障诊断。输出特征可视化结果。数据可更换自己的,程序已调通&…

Android设计模式--模板方法模式

一,定义 定义一个操作中的算法的框架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。 在面向对象的开发过程中,通常会遇到这样一个问题,我们知道一个算法所需的关键步…

c++学习之哈希

目录 1.关于unordered系列关联式容器 2.关于unordered_map 3.哈希(散列)表的实现 一,直接定址法 二,除留余数法 方法一:闭散列:开放定址法 方法二:闭散列:哈希桶/拉链法 4.哈希…

刚刚!OpenAI官宣!Sam Altman回归OpenAI 担任CEO

大家好我是二狗,就在刚刚! OpenAI宣布,Sam Altman将重新回到 OpenAI 担任CEO。 并组建由Bret Taylor(主席)、Larry Summers 和 Adam DAngelo 组成的新的初始董事会。 Sam Altman第一时间做了石锤回应: Sa…

6-使用nacos作为注册中心

本文讲解项目中集成nacos,并将nacos作为注册中心使用的过程。本文不涉及nacos的原理。 1、项目简介 以一个演示项目为例,项目包含三个服务,调用及依赖如下图: 由图中可以看出,coupon-customer-serv为服务的消费者&a…

Log4j

通过Log4j,我们可以控制日志信息输送到目的地是控制台、文件、GUI组件,甚至是套接口服务器、NT的事件记录器。我们可以控制每一条日志的输出格式。通过定义每一条日志信息的级别,能更加细致地控制日志的生成过程。 1 log4j、log4j2与SLF4J …

Java Spring

文章目录 SpringSpring 是什么?从Spring中获取Beanxml获取注解存储类注解⽅法注解bean命名规则类注解之间的关系 注解获取bean属性注⼊缺点 构造⽅法注⼊Setter 注⼊三种注⼊优缺点分析Resource:另⼀种注⼊关键字同⼀类型多个 Bean 报错处理 获取bean对象…

PDF转Word,1行Python代码就够了,免费用

大家好,这里是程序员晚枫。 今年十一假期没出去旅游,在家里更新一套原创课程,👉给小白的《50讲Python自动化办公》。 所有功能,都只需要1行代码,非常适合非程序员入门Python使用。 目前全网播放量直逼100…

封装一个基于ThreeJS渲染基础模型的类,非常简单,可拖动可缩放

工作需求要求threeJS渲染一个模型以供可视化大屏展示,抛出模型精度不谈,只说业务实现 1.Three.JS的引入 ThreeJS官网地址:Three.js – JavaScript 3D Library 查看文档 中文切换及安装创建步骤 如果是自己研究学习用的,在官网安装完后&…