轻量封装WebGPU渲染系统示例<20>- 美化一下元胞自动机(源码)

news2025/1/18 3:28:52

当前示例源码github地址:

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

系统特性:

1. 用户态与系统态隔离。

2. 高频调用与低频调用隔离。

3. 面向用户的易用性封装。

4. 渲染数据(内外部相关资源)和渲染机制分离。

5. 用户操作和渲染系统调度并行机制。

6. 数据/语义驱动。

7. 异步并行的场景/模型载入。

8. computing与rendering用法机制一致性。

        1). 构造过程一致性。

        2). 启用过程一致性。

        3). 自动兼容到material多pass以及material graph机制中。

当前示例运行效果:

WGSL顶点与片段shader:

struct VertexInput {
	@location(0) pos: vec3f,
  	@location(1) uv : vec2f,
	@builtin(instance_index) instance: u32
};

struct VertexOutput {
	@builtin(position) pos: vec4f,
	@location(0) cell: vec2f,
	@location(1) uv: vec2f,
	@location(2) instance: f32,
};
@group(0) @binding(0) var<uniform> grid: vec2f;
@group(0) @binding(1) var<storage> cellState: array<u32>;
@group(0) @binding(2) var<storage> lifeState: array<f32>;
@vertex
fn vertMain(input: VertexInput) -> VertexOutput {
    let i = f32(input.instance);
    let cell = vec2f(i % grid.x, floor(i / grid.x));
    let cellOffset = cell / grid * 2.0;

    var state = f32(cellState[input.instance]);
    let gridPos = (input.pos.xy * state + 1.0) / grid - 1.0 + cellOffset;

    var output: VertexOutput;
    output.pos = vec4f(gridPos, 0.0, 1.0);
    output.cell = cell;
    output.uv = input.uv;
    output.instance = i;
    return output;
}

@fragment
fn fragMain(input: VertexOutput) -> @location(0) vec4f {
    let c = input.cell / grid;
	var dis = length(input.uv - vec2<f32>(0.5, 0.5));
	dis = min(dis/0.15, 1.0);
	let i = u32(input.instance);
	var f = clamp((lifeState[i])/100.0, 0.0005, 1.0);
	dis = (1.0 - pow(dis, 100.0)) * (1.0 - f) + f;
	var c3 = vec3f(c, (1.0 - c.x) * (1.0 - f) + f) * dis;
    return vec4f(c3, 1.0);
}

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

export class GameOfLifePretty {
	private mRscene = new RendererScene();

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

		const rc = this.mRscene;
		rc.initialize();
		this.initScene();
	}
	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] = i % 2;
		}

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

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

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

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

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

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

		return [
			{ ufvs0: [v0, va1, vc1], ufvs1: [v0, vb1, vc1] },
			{ ufvs0: [v0, compva1, compva2, compv3], ufvs1: [v0, compvb1, compvb2, compv3] }
		];
	}
	private mEntity: FixScreenPlaneEntity;
	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 = {
			shaderSrc: {
				code: shaderWGSL,
				uuid: "shader-gameOfLife",
				vertEntryPoint: "vertMain",
				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 FixScreenPlaneEntity({
			x: -0.8, y: -0.8, width: 1.6, height: 1.6,
			materials
		});
		rc.addEntity(entity);
		materials[0].visible = false;
		materials[2].visible = false;

		this.mEntity = entity;
	}

	private mFrameDelay = 3;
	run(): void {
		let rendering = this.mEntity.isRendering();
		if (rendering) {
			if (this.mFrameDelay > 0) {
				this.mFrameDelay--;
				return;
			}
			this.mFrameDelay = 3;

			const ms = this.mEntity.materials;
			for (let i = 0; i < ms.length; i++) {
				ms[i].visible = (this.mStep % 2 + i) % 2 == 0;
			}
			this.mStep++;
		}
		this.mRscene.run(rendering);
	}
}

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

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

相关文章

【新】致远OA从前台XXE到RCE漏洞分析

0x01 前言 致远OA是目前国内最流行的OA系统之一&#xff0c;前几年也曾爆出过多个安全漏洞。致远官方一直对修复漏洞的态度十分积极&#xff0c;目前能有效利用的致远漏洞已经很少了。 和我们之前分享过的通达OA的漏洞类似&#xff0c;这类主流OA系统现在想要直接一步达到RCE的…

UE5——源码阅读——10——引擎预初始化

运行延迟注册委托 初始化堆栈跟踪 检测是否需要覆盖打印时间 检测所必要的插件是否是可用的 获取目标信息 拿到编辑器目标名 检测当前运行的可执行文件是否是正确的 检测项目模块是否有过时和不兼容的 检测插件模块是否有过时和不兼容的 报错误信息 强制通讯 判断是…

选择合适的Python Web框架

Python 是一种功能强大的编程语言&#xff0c;广泛应用于 Web 开发领域。FastAPI 和 Flask 是 Python Web 开发中最受欢迎的两个框架。本文将对 FastAPI 和 Flask 进行综合对比&#xff0c;探讨它们在语法和表达能力、生态系统和社区支持、性能和扩展性、开发工具和调试支持、安…

找不到d3dcompiler_47.dll,无法继续执行代码,解决方法

首先&#xff0c;让我们来了解一下d3dcompiler_47.dll文件。d3dcompiler_47.dll是一个动态链接库文件&#xff0c;它是DirectX SDK中的一个重要组件&#xff0c;用于编译DirectX着色器。当我们在使用一些需要DirectX支持的软件或游戏时&#xff0c;如果缺少了这个文件&#xff…

Linux进程调度之完全公平调度(压箱底的干货分享)

目录 1.什么是完全公平调度&#xff1f; 2.调度周期&#xff0c;调度延迟&#xff0c;最小调度粒度 3.实际运行时间 4.nice值和权重 5.虚拟运行时间 6.查看进程运行时间 1.什么是完全公平调度&#xff1f; 完全公平调度&#xff0c;CFS (Completely Fair Scheduler) 是 …

python 去除图像中的框

最近在做图像标注&#xff0c;会出现以下的图片&#xff0c;需要去除其中的边框。 1.思路 人工标注画框的范围P&#xff0c;并使用标注工具在画框上画一个点A。获取点A的坐标和颜色。在范围P内&#xff0c;将与点A颜色相似的每一个点x的颜色&#xff0c;替换为点x上下&#…

电机应用-直流有刷电机

直流有刷电机 直流有刷电机具有结构简单、易于控制、成本低等特点。 基本的直流有刷电机在电源和电机间只需要两根电缆&#xff0c;可以节省配线和连接器所需的空间&#xff0c;并降低电缆和连接器的成本。 还可以使用MOSFET/IGBT开关对直流有刷电机进行控制&#xff0c;给电机…

第五章:Testing Modules

文章目录 State and ProgramsTestability of State-Based Programsintrusively test 侵入性测试Non-intrusive test 非侵入测试java和其他工具的实践有限状态机进行单元测试(Unit testing with FSA)构建状态机步骤step1:识别 FSA 状态step2:确定某个状态下的可用操作step3:…

【算法练习Day40】打家劫舍打家劫舍 II打家劫舍 III

​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;练题 &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 文章目录 打家劫舍打家劫舍 II打家劫…

java 之数据类型的转换

文章目录 package javastudy;public class arraytest{public void ad(int a,int b) {System.out.printf("ab is %f",ab);}public static void main(String[] args) {arraytest arr new arraytest();arr.ad(1.0, 2);//arr.ad(1 , 2);} }当我们的方法的数据类型是int …

【数据结构与算法】二叉树(基本操作和几种特殊二叉树介绍)

二叉树的基本介绍&#xff0c;只讲基本算法&#xff1b;对于特殊二叉树的相关算法&#xff0c;如AVL树的旋转&#xff0c;以后有时间再写。 文章目录 一、基本概念二、基本操作2.1 二叉树的存储方式2.2 常见操作2.3 二叉树的遍历2.31 前序遍历2.32 中序遍历2.33 后序遍历2.34 层…

JavaScript作用域实战

● 首先&#xff0c;我们先创建一个函数&#xff0c;和以前一样&#xff0c;计算一个年龄的 function calcAge(birthYear) {const age 2037 - birthYear;return age; }● 然后我们创建一个全局变量&#xff0c;并调用这个函数 const firstName "IT知识一享"; cal…

遇到python程序是通过sh文件启动的,如何调试

说明 下载的源码总会遇到这样启动的&#xff1a; 并且发现shell文件内容很多&#xff0c;比较复杂&#xff0c;比如&#xff1a; 解决方案 这时候想要调试&#xff0c;可以通过端口连接的方式调试&#xff0c;具体方法如下&#xff1a; 在vscode调试按钮中添加远程附加调试…

Antv/G2 自定义tooltip鼠标悬浮提示信息

Antv/G2 提示 - Tooltip 教程 Tooltip 提示信息文档 chart.line().position(label*value).color(type).tooltip(type*value, (type:string, value:number) > { return {name: type,value: value%}}) });demo&#xff1a; <!DOCTYPE html> <html lang&quo…

最受欢迎的程序员副业排行榜TOP6

程序员接单的情况并不少见&#xff0c;因为程序员职业工种的特殊性&#xff0c;能够比较快的衔接上新项目和新技术&#xff0c;所以接私活做副业成了许多程序员的不二之选。 程序员的副业是指程序员在业余时间里从事与编程相关的兼职工作&#xff0c;或者是与技术相关的创业项…

[算法训练营] 回溯算法专题(三)

&#x1f57a;作者&#xff1a; 主页 我的专栏C语言从0到1探秘C数据结构从0到1探秘Linux菜鸟刷题集 &#x1f618;欢迎关注&#xff1a;&#x1f44d;点赞&#x1f64c;收藏✍️留言 &#x1f3c7;码字不易&#xff0c;你的&#x1f44d;点赞&#x1f64c;收藏❤️关注对我真的…

致:CSGO游戏搬砖人的一封信

最近大家还在坚持操作CSGO游戏搬砖项目不&#xff1f; 这个项目虽是稳赚项目&#xff0c;但也有行情好和行情不好的时候&#xff0c;平台的大中小各种活动的举办&#xff0c;都会对我们的项目造成一定影响。行情的上下波动势必然会影响卡价的波动&#xff0c;影响选品的快慢&a…

【SqlSever】日期类型转换

特殊类型日期转换 原始数据 12 28 2021 5:18PM 12 28 2021 6:08PM 12 29 2021 7:47AM 12 26 2021 9:00PM 02 9 2022 10:44AM 转换为&#xff1a; 2021-12-28 17:18:00.000 2021-12-28 18:08:00.000 2021-12-29 07:47:00.000 2021-12-26 21:00:00.000 2022-02-09 10:44:00…

70 内网安全-域横向内网漫游Socks代理隧道技术

目录 必要基础知识点:1.内外网简单知识2.内网1和内网2通信问题3.正向反向协议通信连接问题4.内网穿透代理隧道技术说明 演示案例:内网穿透Ngrok测试演示-两个内网通讯上线内网穿透Frp自建跳板测试-两个内网通讯上线CFS三层内网漫游安全测试演练-某CTF线下2019 涉及资源: 主要说…