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

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

当前示例源码github地址:

https://github.com/vilyLei/voxwebgpu/blob/feature/rendering/src/voxgpu/sample/GameOfLife3DPBR.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;
		}
	}
	lifeState[i] = max(lifeState[i], 0.01);
}`;
export class GameOfLife3DPBR {
	private mRscene = new RendererScene();

	initialize(): void {
		console.log("GameOfLife3DPBR::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 mouseDown = (evt: MouseEvent): void => {};

	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, shared };
		let sharedData1 = { data: cellStateArray1, shared };
		let sharedData3 = { data: lifeStateArray3, shared };
		let sharedData4 = { data: posisitonArray4, shared };

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

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

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

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

		const compv3 = new WGRStorageValue({ bufData: 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(uniformValues: WGRUniformValue[]): WGMaterial {
		
		const instanceCount = gridSize * gridSize;
		let shaderCodeSrc = {
			vertShaderSrc: {
				code: vertWGSL,
				uuid: "vert-gameOfLife",
				vertEntryPoint: "vertMain",
			},
			fragShaderSrc: {
				code: fragWGSL,
				uuid: "frag-gameOfLife",
				fragEntryPoint: "fragMain"
			}
		} as WGRShderSrcType;
		return new WGMaterial({
			shadinguuid: 'rendering',
			shaderCodeSrc,
			instanceCount,
			uniformValues,
			uniformAppend: false
		});
	}
	private createCompMaterial(uniformValues: WGRUniformValue[]): WGCompMaterial {
		
		const workgroupCount = Math.ceil(gridSize / shdWorkGroupSize);
		let shaderCodeSrc = {
			compShaderSrc: {
				code: compShdCode,
				uuid: "shader-computing",
				compEntryPoint: "compMain"
			}
		};
		return new WGCompMaterial({
			shadinguuid: 'computing',
			shaderCodeSrc,
			uniformValues,
			uniformAppend: false
		}).setWorkcounts(workgroupCount, workgroupCount);
	}
	private initScene(): void {
		const rc = this.mRscene;

		const ufvsObjs = this.createUniformValues();

		// build ping-pong material rendering/computing process
		const materials: WGMaterial[] = [

			this.createMaterial(ufvsObjs[0].ufvs0),
			this.createMaterial(ufvsObjs[0].ufvs1),

			this.createCompMaterial(ufvsObjs[1].ufvs1),
			this.createCompMaterial(ufvsObjs[1].ufvs0),
		];
		let entity = new CylinderEntity({
			radius: 20, height: 38,
			longitudeNumSegments: 10, latitudeNumSegments: 10,
			alignYRatio : 0.0, materials
		});
		rc.addEntity(entity);

		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();
	}
}


 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Unity游戏开发基础组件

Unity2D 相机调整&#xff1a;Projection设置为Orthographic。也就是正交模式&#xff0c;忽视距离。 资源&#xff1a; Sprite&#xff1a;一种游戏资源&#xff0c;在2D游戏中表示角色场景的图片资源 SpriteSheet&#xff1a;切割一张图片为多个Sprite 在Sprite Editor中可以…

【单片机基础小知识-如何通过指针来读写寄存器】

寄存器的本质就是内存&#xff0c;RAM&#xff0c;而指针是可以对内存进行操作的&#xff0c;因此可以通过指针来读写寄存器。 如何读取以下一片地址&#xff1a; 步骤1、首地址 结构体&#xff0c;它所占用的内存空间大小与它内部成员有关。 构造一个28字节的类型 type…

Pycharm-community-2021版安装和配置

一、下载Pycharm-community-2021 1.从官网下载pycharm-community Pycharm 版本官网 二、安装PyCharm 1.打开下载完成的安装包&#xff0c;点击Next 2.安装PyCharm到其他位置,点击Next 3.一定把更新PATH变量勾上,可以创建桌面快捷方式&#xff0c;创建关联&#xff0c;最后…

如何在Android平板上远程连接Ubuntu服务器code-server进行代码开发?

文章目录 1.ubuntu本地安装code-server2. 安装cpolar内网穿透3. 创建隧道映射本地端口4. 安卓平板测试访问5.固定域名公网地址6.结语 1.ubuntu本地安装code-server 准备一台虚拟机&#xff0c;Ubuntu或者centos都可以&#xff0c;这里以VMwhere ubuntu系统为例 下载code serve…

【高等数学】一些零碎知识点

一、yarcsin(sinx) 二、伽马函数

互联网企业该如何进行风险管理

谈到风险管理&#xff0c;首先我们应该了解如何评估威胁。 威胁可以根据攻击的类型和目标来分类。STRIDE是微软开发出来对计算机安全威胁进行分类的威胁建模系统。 STRIDE代表&#xff1a; 假冒篡改抵赖信息披露拒绝服务提升权限 假冒 即试图通过使用错误的ID访问某个系…

基于redis实现分布式锁

文章目录 基于redis实现分布式锁基本实现防死锁防误删高并发场景下无法保证原子性使用lua保证删除原子性 把redis锁封装成方法 基于redis实现分布式锁 基本实现 借助于redis中的命令setnx(key, value)&#xff0c;key不存在就新增&#xff0c;存在就什么都不做。同时有多个客…

合并文档的 7 个免费 PDF 合并平台

如果没有合适的软件&#xff0c;将文档合并成 PDF 可能会很棘手。因此&#xff0c;这里有六个最好的 PDF 合并平台可以帮助您。 如果您每天处理多组 PDF 文件或其他文档&#xff0c;将它们组合成一个更大的文档可以轻松处理。PDF 合并应用程序可以帮助您使用工具加快此过程&am…

深入理解强化学习——多臂赌博机:梯度赌博机算法的基础知识

分类目录&#xff1a;《深入理解强化学习》总目录 到目前为止&#xff0c;我们已经探讨了评估动作价值的方法&#xff0c;并使用这些估计值来选择动作。这通常是一个好方法&#xff0c;但并不是唯一可使用的方法。我们针对每个动作 a a a考虑学习一个数值化的偏好函数 H t ( a …

《014.SpringBoot+vue之学生选课管理系统03》【前后端分离】

《014.SpringBootvue之学生选课管理系统03》【前后端分离】 项目简介 [1]本系统涉及到的技术主要如下&#xff1a; 推荐环境配置&#xff1a;DEA jdk1.8 Maven MySQL 前后端分离; 后台&#xff1a;SpringBootMybatisMySQL; 前台&#xff1a;vue; [2]功能模块展示&#xff1a…

文件改名:一次性解决文件名混乱,批量重命名技巧

在日常生活和工作中&#xff0c;我们经常会遇到文件名混乱的问题&#xff0c;例如文件名重复、格式不统一或者文件名错误等。这些问题不仅会给我们带来查找和使用上的困扰&#xff0c;还会影响我们的工作效率。为了解决这些问题&#xff0c;我们可以使用批量重命名技巧&#xf…

chatgpt==对接API

来到首页 https://platform.openai.com/docs/overview quickstart turorial 生成API KEY https://platform.openai.com/api-keys 来体验下 setx OPENAI_API_KEY "your-api-key-here" echo %OPENAI_API_KEY% 编写PYTHON代码 pip install --upgrade openai from …

【23真题】C9无歧视,专业课均分130!

今天分享的是23年哈尔滨工业大学803的信号与系统部分的试题及解析。 本套试卷难度分析&#xff1a;22年哈今天分享的是23年哈尔滨工业大学803的信号与系统部分的试题及解析。 哈尔滨工业大学803考研真题&#xff0c;我也发布过&#xff0c;若有需要&#xff0c;戳这里自取&…

uni-app:js实现数组中的相关处理-数组复制

一、slice方法-浅拷贝 使用分析 创建一个原数组的浅拷贝&#xff0c;对新数组的修改不会影响到原数组slice() 方法创建了一个原数组的浅拷贝&#xff0c;这意味着新数组和原数组中的对象引用是相同的。因此&#xff0c;当你修改新数组中的对象时&#xff0c;原数组中相应位置的…

LeetCode-94. 二叉树的中序遍历(C++)

目录捏 一、题目描述二、示例与提示三、思路四、代码 一、题目描述 给定一个二叉树的根节点 root &#xff0c;返回 它的 中序 遍历 。 二、示例与提示 示例 1&#xff1a; 输入&#xff1a; root [1,null,2,3] 输出&#xff1a; [1,3,2] 示例 2&#xff1a; 输入&#xf…

亚马逊云科技产品测评』活动征文|通过使用Amazon Neptune来预测电影类型初体验

文章目录 福利来袭Amazon Neptune什么是图数据库为什么要使用图数据库什么是Amazon NeptuneNeptune 的特点 快速入门环境搭建notebook 图神经网络快速构建加载数据配置端点Gremlin 查询清理 删除环境S3 存储桶删除 授权声明&#xff1a;本篇文章授权活动官方亚马逊云科技文章转…

Stable Diffusion webui 源码调试(三)

Stable Diffusion webui 源码调试&#xff08;三&#xff09; 个人模型主页&#xff1a;LibLibai stable-diffusion-webui 版本&#xff1a;v1.4.1 内容更新随机&#xff0c;看心情调试代码~ shared 变量 shared变量&#xff0c;简直是一锅大杂烩&#xff0c;shared变量存放…

Kubernetes 中 RBAC、ServiceAccount 的区别和联系

Author&#xff1a;rab 目录 前言一、区别二、联系三、案例思考&#xff1f; 前言 首先&#xff0c;Kubernetes (K8s) RBAC (Role-Based Access Control) 和 ServiceAccount 都是 Kubernetes 中用于控制访问权限的两个重要概念&#xff0c;但是它们之间有一些区别和联系。 一…

【ES专题】Logstash与FileBeat详解以及ELK整合详解

目录 前言阅读对象阅读导航前置知识笔记正文一、ELK架构1.1 经典的ELK1.2 整合消息队列Nginx架构 二、LogStash介绍2.1 Logstash核心概念2.1.1 Pipeline2.1.2 Event2.1.3 Codec (Code / Decode)2.1.4 Queue 2.2 Logstash数据传输原理2.3 Logstash的安装&#xff08;以windows为…

微信总提示空间不足怎么办?三个方法随心选!

微信显示空间不足会给用户带来很多困扰&#xff0c;比如影响手机的正常使用&#xff0c;占用大量存储空间&#xff0c;导致手机运行缓慢&#xff0c;没法分享图片和视频&#xff0c;影响我们的社交交流。下面提供了一些简单实用的方法。 方法一&#xff1a;清理微信缓存 1、打…