轻量封装WebGPU渲染系统示例<21>- 3D呈现元胞自动机之生命游戏(源码)

news2024/10/5 19:12:33

实现原理: 基本PBR光照与gpu compute计算

当前示例源码github地址:

https://github.com/vilyLei/voxwebgpu/blob/feature/rendering/src/voxgpu/sample/GameOfLifeSpherePBR.ts


当前示例运行效果:

其他效果截图:

此示例基于此渲染系统实现,当前示例TypeScript源码如下:


const gridSize = 256;
const shdWorkGroupSize = 8;

const compShdCode = `
@group(0) @binding(0) var<uniform> grid: vec2f;

@group(0) @binding(1) var<storage> cellStateIn: array<u32>;
@group(0) @binding(2) var<storage, read_write> cellStateOut: array<u32>;
@group(0) @binding(3) var<storage, read_write> lifeState: array<f32>;

fn cellIndex(cell: vec2u) -> u32 {
	return (cell.y % u32(grid.y)) * u32(grid.x) +
		   (cell.x % u32(grid.x));
}

fn cellActive(x: u32, y: u32) -> u32 {
	return cellStateIn[cellIndex(vec2(x, y))];
}

@compute @workgroup_size(${shdWorkGroupSize}, ${shdWorkGroupSize})
fn compMain(@builtin(global_invocation_id) cell: vec3u) {
	// Determine how many active neighbors this cell has.
	let activeNeighbors = cellActive(cell.x+1, 		cell.y+1) +
							cellActive(cell.x+1, 	cell.y) +
							cellActive(cell.x+1, 	cell.y-1) +
							cellActive(cell.x, 		cell.y-1) +
							cellActive(cell.x-1, 	cell.y-1) +
							cellActive(cell.x-1, 	cell.y) +
							cellActive(cell.x-1, 	cell.y+1) +
							cellActive(cell.x, 		cell.y+1);

	let i = cellIndex(cell.xy);

	// Conway's game of life rules:
	switch activeNeighbors {
		case 2: { // Active cells with 2 neighbors stay active.
			cellStateOut[i] = cellStateIn[i];
			if(cellStateOut[i] > 0) {
				lifeState[i] += 0.05;
			} else {
				lifeState[i] -= 0.05;
			}
		}
		case 3: { // Cells with 3 neighbors become or stay active.
			cellStateOut[i] = 1;
			lifeState[i] += 0.1;
		}
		default: { // Cells with < 2 or > 3 neighbors become inactive.
			cellStateOut[i] = 0;
			lifeState[i] -= 0.05;
		}
	}
	if(lifeState[i] < 0.01) { lifeState[i] = 0.01; }
}`;
export class GameOfLifeSpherePBR {
	private mRscene = new RendererScene();

	initialize(): void {
		console.log("GameOfLifeSpherePBR::initialize() ...");

		const rc = this.mRscene;
		rc.initialize();
		this.initEvent();
		this.initScene();
	}
	private initEvent(): void {
		const rc = this.mRscene;
		rc.addEventListener(MouseEvent.MOUSE_DOWN, this.mouseDown);
		new RenderStatusDisplay(this.mRscene, true);
		new MouseInteraction().initialize(rc, 0, false).setAutoRunning(true);
	}
	private mFlag = 6;
	private mouseDown = (evt: MouseEvent): void => { this.mFlag = 1; };

	private createUniformValues(): { ufvs0: WGRUniformValue[]; ufvs1: WGRUniformValue[] }[] {

		const gridsSizesArray = new Float32Array([gridSize, gridSize]);
		const cellStateArray0 = new Uint32Array(gridSize * gridSize);
		for (let i = 0; i < cellStateArray0.length; i++) {
			cellStateArray0[i] = Math.random() > 0.6 ? 1 : 0;
		}
		const cellStateArray1 = new Uint32Array(gridSize * gridSize);
		for (let i = 0; i < cellStateArray1.length; i++) {
			cellStateArray1[i] = i % 2;
		}
		const lifeStateArray3 = new Float32Array(gridSize * gridSize);
		for (let i = 0; i < lifeStateArray3.length; i++) {
			lifeStateArray3[i] = 0.01;
		}

		const posisitonArray4 = new Float32Array(gridSize * gridSize * 4);
		let sizeV = new Vector3(40, 1, 40);
		let posV = new Vector3().copyFrom(sizeV);
		posV.scaleBy(gridSize);
		posV.scaleBy(-0.5);

		let k = 0;
		for (let i = 0; i < gridSize; i++) {
			for (let j = 0; j < gridSize; j++) {
				let pv = new Vector3(j * sizeV.x, 0, i * sizeV.z).addBy(posV);
				posisitonArray4[k] = pv.x;
				posisitonArray4[k+1] = pv.y;
				posisitonArray4[k+2] = pv.z;
				k += 4;
			}
		}

		let shared = true;
		let sharedData0 = { data: cellStateArray0 };
		let sharedData1 = { data: cellStateArray1 };
		let sharedData3 = { data: lifeStateArray3 };
		let sharedData4 = { data: posisitonArray4 };

		const v0 = new WGRUniformValue({ data: gridsSizesArray, stride: 2, shared, shdVarName: 'v0' }).toVisibleAll();

		// build rendering uniforms
		const va1 = new WGRStorageValue({ sharedData: sharedData0, stride: 1, shared, shdVarName: 'va1' }).toVisibleVertComp();
		const vb1 = new WGRStorageValue({ sharedData: sharedData1, stride: 1, shared, shdVarName: 'vb1' }).toVisibleVertComp();
		const vc1 = new WGRStorageValue({ sharedData: sharedData3, stride: 1, shared, shdVarName: 'vc1' }).toVisibleAll();
		const v4 = new WGRStorageValue({ sharedData: sharedData4, stride: 3, shared, shdVarName: 'v4' }).toVisibleVertComp();

		// build computing uniforms
		const compva1 = new WGRStorageValue({ sharedData: sharedData0, stride: 1, shared, shdVarName: 'compva1' }).toVisibleVertComp();
		const compva2 = new WGRStorageValue({ sharedData: sharedData1, stride: 1, shared, shdVarName: 'compva2' }).toVisibleComp();
		compva2.toBufferForStorage();

		const compvb1 = new WGRStorageValue({ sharedData: sharedData1, stride: 1, shared, shdVarName: 'compvb1' }).toVisibleVertComp();
		const compvb2 = new WGRStorageValue({ sharedData: sharedData0, stride: 1, shared, shdVarName: 'compvb2' }).toVisibleComp();
		compvb2.toBufferForStorage();

		const compv3 = new WGRStorageValue({ sharedData: sharedData3, stride: 1, shared, shdVarName: 'compv3' }).toVisibleComp();
		compv3.toBufferForStorage();

		return [
			{ ufvs0: [v0, va1, vc1, v4], ufvs1: [v0, vb1, vc1, v4] },
			{ ufvs0: [v0, compva1, compva2, compv3], ufvs1: [v0, compvb1, compvb2, compv3] }
		];
	}
	private mEntity: Entity3D;
	private mStep = 0;

	private createMaterial(shaderCodeSrc: WGRShderSrcType, uniformValues: WGRUniformValue[], shadinguuid: string, instanceCount: number): WGMaterial {
		return new WGMaterial({
			shadinguuid,
			shaderCodeSrc,
			instanceCount,
			uniformValues
		});
	}
	private createCompMaterial(shaderCodeSrc: WGRShderSrcType, uniformValues: WGRUniformValue[], shadinguuid: string, workgroupCount = 2): WGCompMaterial {
		return new WGCompMaterial({
			shadinguuid,
			shaderCodeSrc,
			uniformValues
		}).setWorkcounts(workgroupCount, workgroupCount);
	}
	private initScene(): void {
		const rc = this.mRscene;

		const ufvsObjs = this.createUniformValues();

		const instanceCount = gridSize * gridSize;
		const workgroupCount = Math.ceil(gridSize / shdWorkGroupSize);

		let shaderSrc = {
			vertShaderSrc: {
				code: vertWGSL,
				uuid: "vert-gameOfLife",
				vertEntryPoint: "vertMain",
				fragEntryPoint: "fragMain"
			},
			fragShaderSrc: {
				code: fragWGSL,
				uuid: "frag-gameOfLife",
				fragEntryPoint: "fragMain"
			}
		} as WGRShderSrcType;
		let compShaderSrc = {
			compShaderSrc: {
				code: compShdCode,
				uuid: "shader-computing",
				compEntryPoint: "compMain"
			}
		};
		const materials: WGMaterial[] = [
			// build ping-pong rendering process
			this.createMaterial(shaderSrc, ufvsObjs[0].ufvs0, "rshd0", instanceCount),
			this.createMaterial(shaderSrc, ufvsObjs[0].ufvs1, "rshd1", instanceCount),
			// // // build ping-pong computing process
			this.createCompMaterial(compShaderSrc, ufvsObjs[1].ufvs1, "compshd0", workgroupCount),
			this.createCompMaterial(compShaderSrc, ufvsObjs[1].ufvs0, "compshd1", workgroupCount),
		];
		let entity = new CylinderEntity({
			radius: 20, height: 38,
			longitudeNumSegments: 10, latitudeNumSegments: 10,
			alignYRatio : 0.0, materials
		});
		rc.addEntity(entity);
		materials[0].visible = false;
		materials[2].visible = false;

		this.mEntity = entity;
	}

	private mFrameDelay = 3;

	run(): void {
		let flag = this.mEntity.isRendering();
		const ms = this.mEntity.materials;
		if (flag) {

			for (let i = 0; i < ms.length; i++) {
				ms[i].visible = (this.mStep % 2 + i) % 2 == 0;
			}
			if (this.mFrameDelay > 0) {
				this.mFrameDelay--;
				flag = false;
			}else {
				this.mFrameDelay = 3;
				this.mStep++;
			}

		}
		if(!flag) {
			ms[2].visible = false;
			ms[3].visible = false;
		}
		this.mRscene.run();
	}
}


 

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

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

相关文章

使用Ruby编写通用爬虫程序

目录 一、引言 二、环境准备 三、爬虫程序设计 1. 抓取网页内容 2. 解析HTML内容 3. 提取特定信息 4. 数据存储 四、优化和扩展 五、结语 一、引言 网络爬虫是一种自动抓取互联网信息的程序。它们按照一定的规则和算法&#xff0c;遍历网页并提取所需的信息。使用Rub…

Leetcode刷题详解——子集

1. 题目链接&#xff1a;78. 子集 2. 题目描述&#xff1a; 给你一个整数数组 nums &#xff0c;数组中的元素 互不相同 。返回该数组所有可能的子集&#xff08;幂集&#xff09;。 解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。 示例 1&#xff1a; 输入&#xf…

Mactracker for mac(硬件信息查询工具)免费下载

想知道你电脑的信息吗&#xff1f;Mactracker Mac版是Macos上一款硬件信息查询工具&#xff0c;可以查询电脑中的硬件信息&#xff0c;还可以查看您使用软件的具体情况&#xff0c;苹果电脑产品和周边产品的信息&#xff0c;售价等等&#xff0c;让您对电脑有更多深刻的了解。 …

【C++】开源:rapidjson数据解析库配置与使用

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 这篇文章主要介绍rapidjson数据解析库配置与使用。 无专精则不能成&#xff0c;无涉猎则不能通。——梁启超 欢迎来到我的博客&#xff0c;一起学习&#xff0c;共同进步。 喜欢的朋友可以关注一下&…

求职招聘小程序源码系统+社交招聘+多城市招聘 带完整搭建教程

大家好&#xff0c;今天罗峰来给大家分享一款求职招聘小程序源码系统。目前&#xff0c;求职招聘市场在不断变革。传统的招聘网站已经无法满足人们对于高效、便捷、多元化的招聘需求。该系统集求职招聘、社交招聘、多城市招聘等功能于一体&#xff0c;旨在为用户提供更加便捷、…

京东商品详情API,页面信息采集,优惠券信息获取

京东开放平台提供了API接口来访问京东商品详情。通过这个接口&#xff0c;您可以获取到商品的详细信息&#xff0c;如商品名称、价格、库存量、描述等。额外还附加一个优惠券信息接口。代码如下: 京东获得JD商品详情 API 优惠券接口 公共参数 名称类型必须描述keyString是调…

【I/O流之旅】File类-零基础入门指南

&#x1f38a;专栏【Java】 &#x1f33a;每日一句:看不清楚未来时,就比别人坚持久一点 ⭐欢迎并且感谢大家指出我的问题 目录 1.File概述 2.File构造方法 (1).根据文件路径创建文件对象 (2).根据父路径名字符串和子路径名字符串创建对象 (3).根据父路径对应文件对象和子路…

Python基础入门(3)----Python基础语法:解释器、标识符、关键字、缩进

文章目录 Python解释器标识符关键字缩进代码示例与运行结果Python是一种高级编程语言,以其简洁明了的语法和强大的功能而受到广泛欢迎。本文将介绍Python的一些基础语法元素,包括解释器、标识符、关键字和缩进,并提供相应的代码示例和运行结果。 Python解释器 Python是一种…

登陆认证权限控制(2)—— 基于Spring security 安全框架的权限管理 注解式权限控制 RABC模型

前言 登陆认证&#xff0c;权限控制是一个系统必不可少的部分&#xff0c;一个开放访问的系统能否在上线后稳定持续运行其实很大程度上取决于登陆认证和权限控制措施是否到位&#xff0c;不然可能系统刚刚上线就会夭折。 Spring Security 是一个能够为基于 Spring 的企业应用…

vue2 集成 - 超图 - SuperMap iClient3D for WebGL 及常用方法

1:下载SuperMap iClient3D for WebGL SuperMap iClient3D for WebGL产品包 打开资源目录如下 2:格式化项目中所用的依赖包 开发指南 从超图官网下载SuperMap iClient3D 11i (2023) SP1 for WebGL_CN.zip解压后,将Build目录下的SuperMap3D复制到项目中 \public\static…

iOS Crash 治理:淘宝VisionKitCore 问题修复

本文通过逆向系统&#xff0c;阅读汇编指令&#xff0c;逐步找到源码&#xff0c;定位到了 iOS 16.0.<iOS 16.2 WKWebView 的系统bug 。同时苹果已经在新版本修复了 Bug&#xff0c;对于巨大的存量用户&#xff0c;仍旧会造成日均 Crash pv 1200 uv 1000&#xff0c; 最终通…

SpringCloud——三个服务注册中心的异同点

首先我们说一下什么是CAP&#xff1a; C&#xff1a;Consistency(强一致性) A&#xff1a;Availability(高可用性) P&#xff1a;Partition tolerance(分区容错性) CAP关注的粒度是数据&#xff01; AP(Eureka) CP(Zookeeper/Consul)

【Database System Concept 7th】Chapter 24 Advanced Indexing Techniques 读书笔记

Chapter 24 Advanced Indexing Techniques 24.5 Hash Indices24.5.1 Static Hashing24.5.2 Dynamic Hashing24.5.2.1 Data Structure24.5.2.2 Queries and Updates 24.5 Hash Indices 24.5.1 Static Hashing 这一部分就不介绍了&#xff0c;在14.5中已经介绍过了。 24.5.2 D…

攻击者滥用日历服务作为 C2 基础设施

谷歌警告多个威胁参与者正在利用其日历服务作为命令和控制&#xff08;C2&#xff09;基础设施。 谷歌警告 称&#xff0c;多个威胁参与者共享一个名为“Google Calendar RAT”的公共概念验证&#xff08;PoC&#xff09;漏洞&#xff0c;该漏洞依赖日历服务来托管命令和控制&…

SpringCloud——消息驱动——Stream

1.什么是消息驱动 消息驱动就是屏蔽底层消息中间件的差异&#xff0c;降低切换成本&#xff0c;统一消息的编程模型。目前仅支持RabbitMQ、Kafka。 2.消息中间件有什么问题&#xff0c;stream靠什么实现&#xff1f; 如果我们项目用到了RabbitMQ和Kafka&#xff0c;由于这两个…

大数据毕业设计选题推荐-超级英雄运营数据监控平台-Hadoop-Spark-Hive

✨作者主页&#xff1a;IT研究室✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Python…

torch.cuda.is_available()=false的原因

1、检查是否为nvidia显卡&#xff1b; 2、检查GPU是否支持cuda; 3、命令行cmd输入nvidia-smi&#xff08;中间没有空格&#xff09;&#xff0c;查看显卡信息&#xff0c;cuda9.2版本只支持Driver Version>396.26&#xff1b;如果小于这个值&#xff0c;那么你就需要更新显…

NCV7721D2R2G一款完全保护的双半桥驱动器 专为汽车工业运动控制解决方案

NCV7721D2R2G是一款完全保护的双半桥驱动器&#xff0c;专为汽车和工业运动控制应用而设计。两个半桥驱动器具有独立控制。这允许高侧、低侧和H桥控制。H桥控制提供正向、反向、制动和高阻抗状态。驱动器通过逻辑电平输入进行控制。 特性&#xff1a; 1.睡眠模式下的超低静态电…

多测师肖sir___ddt讲解(辅助框架)

ddt数据驱动 1、ddt定义&#xff1a;全称data-driver tests &#xff0c;数据驱动测试&#xff0c;可以实现不同数据运行同一个测试用例。 ddt本质是一个装饰器&#xff0c;一组数据一个场景 主要核心&#xff1a;把业务逻辑装成关键字&#xff0c;在调用关键字 2、为什么要使…

EasyExcel 导出冻结指定行

导出的实体类 package org.jeecg.modules.eis.test;import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.annotation.write.style.*; import lombok.Getter; import lombok.Setter; import org.apache.poi.ss.usermodel.HorizontalAlignment;import…