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.mzph.cn/news/157770.shtml

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

相关文章

【shell脚本】全自动完成pxe无人值守批量装机脚本,匹配centos系列

本脚本采用的是搭建ftp服务器、tftp服务器、dhcp服务器来完成文件的传输 ks应答文件为最小化安装,免去图形化,可以实现一键装机~~ #!/bin/bash yum -y install tftp-server dhcp vsftpd syslinux &> /dev/null ###脚本说明:需要输入…

UE5的TimeLine的理解

一直以来,我对动画的理解一直是这样的: 所谓动画,就是可导致可视化内容变化的参数和时间的对应关系。 我不能说这个观点现在过时了,只能说自己狭隘了。因为UE的TimeLine的设计理念真让人竖大拇指。 当我第一次看到TimeLine节点的…

FreeSQL 基本使用

FreeSQL连接MySQL 安装 FeeSql相关库 FreeSql 基本库 FreeSql.DbContext FreeSql.Extensions.Linq linq语法扩展库 FreeSql.Provider.Mysql MySQL连接库 新建DbConent.cs public class Base{static string connstr "Data Source127.0.0.1;Port3306;User IDroot;Pa…

Ubuntu apt-get换源

一、参考资料 ubuntu16.04更换镜像源为阿里云镜像源 二、相关介绍 1. apt常用命令 sudo apt-get clean sudo apt-get update2. APT加速工具 轻量小巧的零配置 APT 加速工具:APT Proxy GitHub项目地址:apt-proxy 三、换源关键步骤 1. 更新阿里源 …

猫咪不长肉怎么回事?搬空家底的增肥效果好的猫罐头分享

秋冬到了,北方有供暖还好,咱南方的小猫咪全靠一身正气,不囤点脂肪天生怕冷的小猫咪要怎么过冬啊?咋吃都吃不胖的猫可愁怀铲屎官了,想想我新手养猫那些年,为了给我家猫养胖点我是做了不少努力,当…

地奥集团大健康产业再添解酒黑科技:“酒必妥”!

地奥集团成都药业股份有限公司隶属于地奥集团旗下的子公司,至今已经超过百年历史,主要围绕化学药品在耕耘奉献。尽管公司历来都低调,但是地奥这块牌子在质量把控,安全生产把控等药品领域还是响当当。历年来,公司持续对…

Vue3中el-table表格数据不显示

可能的原因和解决方法如下: 检查数据格式是否正确:确认数据是否传入了正确的格式,如数据是否为数组,每条数据是否包含必要的属性等。 检查 column 属性是否正确:确认 column 属性中的属性名是否与数据中的属性名一致&…

vue3-响应式函数

​🌈个人主页:前端青山 🔥系列专栏:Vue篇 🔖人终将被年少不可得之物困其一生 依旧青山,本期给大家带来vue篇专栏内容:vue3-响应式函数 目录 ref 响应式函数 引言: ref 函数 reactive 函数 Reactive 与…

GNSS技术在交通运输领域的创新应用

全球导航卫星系统(GNSS)技术在交通运输领域发挥着越来越重要的作用,为汽车导航、航空、海运等交通模式提供了精准的定位和导航服务。本文将深入探讨GNSS技术在交通运输领域的应用,以及它对交通管理、安全性和效率的积极影响。 一、…

这些仪表板常用的数据分析模型,你都见过吗?

本文由葡萄城技术团队发布。转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具、解决方案和服务,赋能开发者。 ##前言 在数字化时代,数据已经成为了企业决策和管理的重要依据。而仪表板作为一种数据可视化工具&#x…

Linux inotify 文件监控

Linux 内核 2.6.13 以后,引入了 inotify 文件系统监控功能,通过 inotify 可以对敏感目录设置事件监听。这样的功能被也被包装成了一个文件监控神器 inotify-tools。 使用 inotify 进行文件监控的过程: 创建 inotify 实例,获取 i…

Java中实体与Map的相互转换

一、在Java中&#xff0c;可以通过以下方法将实体类转换为Map&#xff1a; 利用Java反射机制&#xff1a; public static Map<String, Object> objectToMap(Object obj) throws IllegalAccessException {Map<String, Object> map new HashMap<>();Class&l…

【代码随想录】算法训练计划28

回溯 1、491. 递增子序列 题目&#xff1a; 给你一个整数数组 nums &#xff0c;找出并返回所有该数组中不同的递增子序列&#xff0c;递增子序列中 至少有两个元素 。你可以按 任意顺序 返回答案。 数组中可能含有重复元素&#xff0c;如出现两个整数相等&#xff0c;也可以…

@RequestBody详解:用于获取请求体中的Json格式参数

获取请求体中的Json格式参数 &#xff08;RequestBody&#xff09; 当前端将一些比较复杂的参数转换成Json字符串通过请求体传递过来给后端&#xff0c;这种时候就可以使用RequestBody注解获取请求体中的数据。 而json字符串是包含在请求体中的&#xff0c;使用请求体传参通常…

【Azure 架构师学习笔记】-Azure Storage Account(7)- 权限控制

本文属于【Azure 架构师学习笔记】系列。 本文属于【Azure Storage Account】系列。 接上文 【Azure 架构师学习笔记】-Azure Storage Account&#xff08;6&#xff09;- File Layer 前言 存储帐户作为其中一个数据终端存储&#xff0c;对安全性的要求非常高&#xff0c;不管…

40、Flink 的Apache Kafka connector(kafka source的介绍及使用示例)-1

Flink 系列文章 1、Flink 部署、概念介绍、source、transformation、sink使用示例、四大基石介绍和示例等系列综合文章链接 13、Flink 的table api与sql的基本概念、通用api介绍及入门示例 14、Flink 的table api与sql之数据类型: 内置数据类型以及它们的属性 15、Flink 的ta…

Linux常用命令——bmodinfo命令

在线Linux命令查询工具 bmodinfo 显示给定模块的详细信息 补充说明 bmodinfo命令用于显示给定模块的详细信息。 语法 bmodinfo(选项)(参数)选项 -a&#xff1a;显示模块作者&#xff1b; -d&#xff1a;显示模块的描述信息&#xff1b; -l&#xff1a;显示模块的许可信息…

Linux环境下安装部署单机RabbitMQ(离线)

摘要 本文档适用于在Linux系统下部署单体RabbitMQ&#xff0c;是在无网的情况下部署的。涉及的任何操作都是通过手动下载安装包然后上传到服务器上进行安装&#xff0c;因此也遇到一些问题&#xff0c;并在此文档中记录。 实际操作环境&#xff1a;Kylin V10&#xff0c;实际…

C#中反射的使用总结

反射是.NET中的重要机制&#xff0c;通过反射&#xff0c;可以在运行时获得程序或程序集中每一个类型&#xff08;包括类、结构、委托、接口和枚举等&#xff09;的成员和成员的信息。可以直接通过反射方式创建对象&#xff0c;即使这个对象的类型在编译时没有加载。本文主要介…

基于哈夫曼树的数据压缩算法

基于哈夫曼树的数据压缩算法是一种有效的编码方法&#xff0c;可以对待压缩文件进行压缩&#xff08;即编码&#xff09;&#xff0c;同时可以对压缩后的二进制编码文件进行解压&#xff08;即译码&#xff09;。以下是其工作原理&#xff1a; 输入一串字符串&#xff0c;根据…