visionOS空间计算实战开发教程Day 10 照片墙

2023-11-30 09:28

本文主要是介绍visionOS空间计算实战开发教程Day 10 照片墙,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本例选择了《天空之城》的25张照片,组成5x5的照片墙)。首先我们在setupContentEntity方法中构建了一个纹理数组,将这25张照片添加到数组images中。其中封装了setup方法,借助于visionOS对沉浸式空间的支持,我们创建了三个平面,组成具有立体感的照片墙。

setup方法中调用了addChildEntities,对images随机打散,通过quotientAndRemainder方法对5求商取余来设置xy的值,从而生成5x5的照片,z轴上仅以平面为基准做了小小的调整。将准备好的位置和纹理,传入makePlane方法进行配置返回实体再分别添加到3个平面中。

为增加趣味性,这里还定义了toggleSorted()方法,在沉浸式空间内点击时会打散(randomSetChildPositions()方法),再次点击又会重置收起(resetChildPositions())。完整的ViewModel.swift文件内容如下:

import SwiftUI
import RealityKit@Observable
class ViewModel {private let planeSize = CGSize(width: 0.32, height: 0.18)private let maxPlaneSize = CGSize(width: 3.0, height: 2.0)private var  contentEntity = Entity()private var boardPlanes: [ModelEntity] = []private var images: [MaterialParameters.Texture] = []private var sorted = truefunc setupContentEntity() -> Entity {for i in 1..<26 {let name = "laputa\(String(format: "%03d", i))"if let texture = try? TextureResource.load(named: name) {images.append(MaterialParameters.Texture(texture))}}setup()return contentEntity}func toggleSorted() {if sorted {sorted.toggle()randomSetChildPositions()} else {sorted.toggle()resetChildPositions()}}// MARK: - Privateprivate func setup() {for i in 0..<3 {let boardPlane = ModelEntity(mesh: .generatePlane(width: 3, height: 2),materials: [SimpleMaterial(color: .clear, isMetallic: false)])boardPlane.position = SIMD3<Float>(x: 0, y : 2, z: -0.5 - 0.1 * Float(i + 1))contentEntity.addChild(boardPlane)boardPlanes.append(boardPlane)addChildEntities(boardPlane: boardPlane)}}private func addChildEntities(boardPlane: ModelEntity) {var i: Int = 0for image in images.shuffled().prefix(30) {let divisionResult = i.quotientAndRemainder(dividingBy: 5)let x: Float = Float(divisionResult.remainder) * 0.4 - 0.75let y: Float = Float(divisionResult.quotient) * 0.25 - 0.5let z: Float = boardPlane.position.z + Float(i) * 0.0001let entity = makePlane(name: "", position: SIMD3<Float>(x: x, y: y, z: z), texture: image)boardPlane.addChild(entity)i += 1}}private func makePlane(name: String, position: SIMD3<Float>, texture: MaterialParameters.Texture) -> ModelEntity {var material = SimpleMaterial()material.color = .init(texture: texture)let entity = ModelEntity(mesh: .generatePlane(width: 0.32, height: 0.18, cornerRadius: 0.0),materials: [material],collisionShape: .generateBox(width: 0.32, height: 0.18, depth: 0.1),mass: 0.0)entity.name = nameentity.position = positionentity.components.set(InputTargetComponent(allowedInputTypes: .indirect))return entity}private func move(entity: Entity, position: SIMD2<Float>) {let move = FromToByAnimation<Transform>(name: "move",from: .init(scale: .init(repeating: 1), translation: entity.position),to: .init(scale: .init(repeating: 1), translation: .init(x: position.x, y: position.y, z: entity.position.z)),duration: 2.0,timing: .linear,bindTarget: .transform)let animation = try! AnimationResource.generate(with: move)entity.playAnimation(animation, transitionDuration: 2.0)}private func randomSetChildPositions() {let size = CGSize(width: planeSize.width *  1.2, height: planeSize.height * 1.2)for boardPlane in boardPlanes {let newPoints = randomPoints(count: boardPlane.children.count, size: size)for i in 0..<boardPlane.children.count {let entity = boardPlane.children[i]move(entity: entity, position: newPoints[i])}}}private func resetChildPositions() {for boardPlane in boardPlanes {var i: Int = 0for entity in boardPlane.children {let divisionResult = i.quotientAndRemainder(dividingBy: 5)let x: Float = Float(divisionResult.remainder) * 0.4 - 0.75let y: Float = Float(divisionResult.quotient) * 0.25 - 0.5move(entity: entity, position: SIMD2<Float>(x, y))i += 1}}}private func randomPoints(count: Int, size: CGSize) -> [SIMD2<Float>] {var ret: [SIMD2<Float>] = []while ret.count < count {if let point = randomPoint(size: size, positions: ret) {ret.append(point)}}return ret}private func randomPoint(size: CGSize, positions: [SIMD2<Float>]) -> SIMD2<Float>? {for _ in 0..<5000 {let x = CGFloat.random(in: -maxPlaneSize.width...(maxPlaneSize.width / 2))let y = CGFloat.random(in: -maxPlaneSize.height...(maxPlaneSize.height / 2))let frame = CGRect(x: CGFloat(x), y: CGFloat(y), width: size.width, height: size.height)if positions.isEmpty {return SIMD2<Float>(Float(x), Float(y))} else {var intersects = falsefor position in positions {let f = CGRect(x: CGFloat(position.x), y: CGFloat(position.y), width: size.width, height: size.height)if f.intersects(frame) {intersects = true}}if !intersects {return SIMD2<Float>(Float(frame.minX), Float(frame.minY))}}}return nil}
}

ImmersiveView中发生了Tap事件后会调用其中的toggleSorted()方法,其它代码与此前的示例并没什么不同。

struct ImmersiveView: View {@State var model = ViewModel()var body: some View {RealityView { content incontent.add(model.setupContentEntity())}.onTapGesture {model.toggleSorted()}}
}

visionOS空间计算实战开发教程Day 10 照片墙

示例代码:GitHub仓库

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

这篇关于visionOS空间计算实战开发教程Day 10 照片墙的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/436497

相关文章

Python版本信息获取方法详解与实战

《Python版本信息获取方法详解与实战》在Python开发中,获取Python版本号是调试、兼容性检查和版本控制的重要基础操作,本文详细介绍了如何使用sys和platform模块获取Python的主... 目录1. python版本号获取基础2. 使用sys模块获取版本信息2.1 sys模块概述2.1.1

一文详解Python如何开发游戏

《一文详解Python如何开发游戏》Python是一种非常流行的编程语言,也可以用来开发游戏模组,:本文主要介绍Python如何开发游戏的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下... 目录一、python简介二、Python 开发 2D 游戏的优劣势优势缺点三、Python 开发 3D

基于Python开发Windows自动更新控制工具

《基于Python开发Windows自动更新控制工具》在当今数字化时代,操作系统更新已成为计算机维护的重要组成部分,本文介绍一款基于Python和PyQt5的Windows自动更新控制工具,有需要的可... 目录设计原理与技术实现系统架构概述数学建模工具界面完整代码实现技术深度分析多层级控制理论服务层控制注

全网最全Tomcat完全卸载重装教程小结

《全网最全Tomcat完全卸载重装教程小结》windows系统卸载Tomcat重新通过ZIP方式安装Tomcat,优点是灵活可控,适合开发者自定义配置,手动配置环境变量后,可通过命令行快速启动和管理... 目录一、完全卸载Tomcat1. 停止Tomcat服务2. 通过控制面板卸载3. 手动删除残留文件4.

Python爬虫HTTPS使用requests,httpx,aiohttp实战中的证书异步等问题

《Python爬虫HTTPS使用requests,httpx,aiohttp实战中的证书异步等问题》在爬虫工程里,“HTTPS”是绕不开的话题,HTTPS为传输加密提供保护,同时也给爬虫带来证书校验、... 目录一、核心问题与优先级检查(先问三件事)二、基础示例:requests 与证书处理三、高并发选型:

Python的pandas库基础知识超详细教程

《Python的pandas库基础知识超详细教程》Pandas是Python数据处理核心库,提供Series和DataFrame结构,支持CSV/Excel/SQL等数据源导入及清洗、合并、统计等功能... 目录一、配置环境二、序列和数据表2.1 初始化2.2  获取数值2.3 获取索引2.4 索引取内容2

python依赖管理工具UV的安装和使用教程

《python依赖管理工具UV的安装和使用教程》UV是一个用Rust编写的Python包安装和依赖管理工具,比传统工具(如pip)有着更快、更高效的体验,:本文主要介绍python依赖管理工具UV... 目录前言一、命令安装uv二、手动编译安装2.1在archlinux安装uv的依赖工具2.2从github

Java中的分布式系统开发基于 Zookeeper 与 Dubbo 的应用案例解析

《Java中的分布式系统开发基于Zookeeper与Dubbo的应用案例解析》本文将通过实际案例,带你走进基于Zookeeper与Dubbo的分布式系统开发,本文通过实例代码给大家介绍的非常详... 目录Java 中的分布式系统开发基于 Zookeeper 与 Dubbo 的应用案例一、分布式系统中的挑战二

C#实现SHP文件读取与地图显示的完整教程

《C#实现SHP文件读取与地图显示的完整教程》在地理信息系统(GIS)开发中,SHP文件是一种常见的矢量数据格式,本文将详细介绍如何使用C#读取SHP文件并实现地图显示功能,包括坐标转换、图形渲染、平... 目录概述功能特点核心代码解析1. 文件读取与初始化2. 坐标转换3. 图形绘制4. 地图交互功能缩放

Oracle Scheduler任务故障诊断方法实战指南

《OracleScheduler任务故障诊断方法实战指南》Oracle数据库作为企业级应用中最常用的关系型数据库管理系统之一,偶尔会遇到各种故障和问题,:本文主要介绍OracleSchedul... 目录前言一、故障场景:当定时任务突然“消失”二、基础环境诊断:搭建“全局视角”1. 数据库实例与PDB状态2