Google codelab WebGPU入门教程源码<6> - 使用计算着色器实现计算元胞自动机之生命游戏模拟过程(源码)

本文主要是介绍Google codelab WebGPU入门教程源码<6> - 使用计算着色器实现计算元胞自动机之生命游戏模拟过程(源码),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

对应的教程文章: 

https://codelabs.developers.google.com/your-first-webgpu-app?hl=zh-cn#7

对应的源码执行效果:

对应的教程源码: 

此处源码和教程本身提供的部分代码可能存在一点差异。点击画面,切换效果。

class Color4 {r: number;g: number;b: number;a: number;constructor(pr = 1.0, pg = 1.0, pb = 1.0, pa = 1.0) {this.r = pr;this.g = pg;this.b = pb;this.a = pa;}
}export class WGPUSimulation {private mRVertices: Float32Array = null;private mRPipeline: any | null = null;private mRSimulationPipeline: any | null = null;private mVtxBuffer: any | null = null;private mCanvasFormat: any | null = null;private mWGPUDevice: any | null = null;private mWGPUContext: any | null = null;private mUniformBindGroups: any | null = null;private mGridSize = 32;private mShdWorkGroupSize = 8;constructor() {}initialize(): void {const canvas = document.createElement("canvas");canvas.width = 512;canvas.height = 512;document.body.appendChild(canvas);console.log("ready init webgpu ...");this.initWebGPU(canvas).then(() => {console.log("webgpu initialization finish ...");this.updateWGPUCanvas();});document.onmousedown = (evt):void => {this.updateWGPUCanvas( new Color4(0.05, 0.05, 0.1) );}}private mUniformObj: any = {uniformArray: null, uniformBuffer: null};private createStorage(device: any): any {// Create an array representing the active state of each cell.const cellStateArray = new Uint32Array(this.mGridSize * this.mGridSize);// Create two storage buffers to hold the cell state.const cellStateStorage = [device.createBuffer({label: "Cell State A",size: cellStateArray.byteLength,usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,}),device.createBuffer({label: "Cell State B",size: cellStateArray.byteLength,usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,})];// Mark every third cell of the first grid as active.for (let i = 0; i < cellStateArray.length; i+=3) {cellStateArray[i] = 1;}device.queue.writeBuffer(cellStateStorage[0], 0, cellStateArray);// Mark every other cell of the second grid as active.for (let i = 0; i < cellStateArray.length; i++) {cellStateArray[i] = i % 2;}device.queue.writeBuffer(cellStateStorage[1], 0, cellStateArray);return cellStateStorage;}private createUniform(device: any): any {// Create a uniform buffer that describes the grid.const uniformArray = new Float32Array([this.mGridSize, this.mGridSize]);const uniformBuffer = device.createBuffer({label: "Grid Uniforms",size: uniformArray.byteLength,usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,});device.queue.writeBuffer(uniformBuffer, 0, uniformArray);const cellStateStorage = this.createStorage(device);// Create the bind group layout and pipeline layout.const bindGroupLayout = device.createBindGroupLayout({label: "Cell Bind Group Layout",entries: [{binding: 0,visibility: GPUShaderStage.FRAGMENT | GPUShaderStage.VERTEX | GPUShaderStage.COMPUTE,buffer: {} // Grid uniform buffer}, {binding: 1,visibility: GPUShaderStage.VERTEX | GPUShaderStage.COMPUTE,buffer: { type: "read-only-storage"} // Cell state input buffer}, {binding: 2,visibility: GPUShaderStage.COMPUTE,buffer: { type: "storage"} // Cell state output buffer}]});const bindGroups = [device.createBindGroup({label: "Cell renderer bind group A",layout: bindGroupLayout,entries: [{binding: 0,resource: { buffer: uniformBuffer }}, {binding: 1,resource: { buffer: cellStateStorage[0] }}, {binding: 2,resource: { buffer: cellStateStorage[1] }}],}),device.createBindGroup({label: "Cell renderer bind group B",layout: bindGroupLayout,entries: [{binding: 0,resource: { buffer: uniformBuffer }}, {binding: 1,resource: { buffer: cellStateStorage[1] }}, {binding: 2,resource: { buffer: cellStateStorage[0] }}],})];this.mUniformBindGroups = bindGroups;const obj = this.mUniformObj;obj.uniformArray = uniformArray;obj.uniformBuffer = uniformBuffer;return bindGroupLayout;}private mStep = 0;private createComputeShader(device: any): any {let sgs = this.mShdWorkGroupSize;// Create the compute shader that will process the simulation.const simulationShaderModule = device.createShaderModule({label: "Game of Life simulation shader",code: `@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>;fn cellIndex(cell: vec2u) -> u32 {return cell.y * u32(grid.x) + cell.x;}@compute @workgroup_size(${sgs}, ${sgs})fn computeMain(@builtin(global_invocation_id) cell: vec3u) {if (cellStateIn[cellIndex(cell.xy)] == 1) {cellStateOut[cellIndex(cell.xy)] = 0;} else {cellStateOut[cellIndex(cell.xy)] = 1;}}`});return simulationShaderModule;}private createRectGeometryData(device: any, pass: any, computePass: any): void {let vertices = this.mRVertices;let vertexBuffer = this.mVtxBuffer;let cellPipeline = this.mRPipeline;let simulationPipeline = this.mRSimulationPipeline;if(!cellPipeline) {let hsize = 0.8;vertices = new Float32Array([//   X,    Y,-hsize, -hsize, // Triangle 1 (Blue)hsize, -hsize,hsize,  hsize,-hsize, -hsize, // Triangle 2 (Red)hsize,  hsize,-hsize,  hsize,]);vertexBuffer = device.createBuffer({label: "Cell vertices",size: vertices.byteLength,usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,});device.queue.writeBuffer(vertexBuffer, /*bufferOffset=*/0, vertices);const vertexBufferLayout = {arrayStride: 8,attributes: [{format: "float32x2",offset: 0,shaderLocation: 0, // Position, see vertex shader}],};const shaderCodes = `struct VertexInput {@location(0) pos: vec2f,@builtin(instance_index) instance: u32,};struct VertexOutput {@builtin(position) pos: vec4f,@location(0) cell: vec2f,};@group(0) @binding(0) var<uniform> grid: vec2f;@group(0) @binding(1) var<storage> cellState: array<u32>;@vertexfn vertexMain(input: VertexInput) -> VertexOutput  {let i = f32(input.instance);let cell = vec2f(i % grid.x, floor(i / grid.x));let cellOffset = cell / grid * 2;let state = f32(cellState[input.instance]);let gridPos = (input.pos * state + 1) / grid - 1 + cellOffset;var output: VertexOutput;output.pos = vec4f(gridPos, 0, 1);output.cell = cell;return output;}@fragmentfn fragmentMain(input: VertexOutput) -> @location(0) vec4f {// return vec4f(input.cell, 0, 1);let c = input.cell/grid;return vec4f(c, 1.0 - c.x, 1);}`;const bindGroupLayout = this.createUniform(device);const pipelineLayout = device.createPipelineLayout({label: "Cell Pipeline Layout",bindGroupLayouts: [ bindGroupLayout ],});const cellShaderModule = device.createShaderModule({label: "Cell shader",code: shaderCodes});cellPipeline = device.createRenderPipeline({label: "Cell pipeline",layout: pipelineLayout,vertex: {module: cellShaderModule,entryPoint: "vertexMain",buffers: [vertexBufferLayout]},fragment: {module: cellShaderModule,entryPoint: "fragmentMain",targets: [{format: this.mCanvasFormat}]},});const simulationShaderModule = this.createComputeShader( device );// Create a compute pipeline that updates the game state.simulationPipeline = device.createComputePipeline({label: "Simulation pipeline",layout: pipelineLayout,compute: {module: simulationShaderModule,entryPoint: "computeMain",}});this.mRVertices = vertices;this.mVtxBuffer = vertexBuffer;this.mRPipeline = cellPipeline;this.mRSimulationPipeline = simulationPipeline;}const bindGroups = this.mUniformBindGroups;computePass.setPipeline(simulationPipeline),computePass.setBindGroup(0, bindGroups[this.mStep % 2]);const workgroupCount = Math.ceil(this.mGridSize / this.mShdWorkGroupSize);computePass.dispatchWorkgroups(workgroupCount, workgroupCount);pass.setPipeline(cellPipeline);pass.setVertexBuffer(0, vertexBuffer);// pass.setBindGroup(0, this.mUniformBindGroup);pass.setBindGroup(0, bindGroups[this.mStep % 2]);pass.draw(vertices.length / 2, this.mGridSize * this.mGridSize);this.mStep ++;}private updateWGPUCanvas(clearColor: Color4 = null): void {clearColor = clearColor ? clearColor : new Color4(0.05, 0.05, 0.1);const device = this.mWGPUDevice;const context = this.mWGPUContext;const rpassParam = {colorAttachments: [{clearValue: clearColor,// clearValue: [0.3,0.7,0.5,1.0], // yesview: context.getCurrentTexture().createView(),loadOp: "clear",storeOp: "store"}]};const encoder = device.createCommandEncoder();const pass = encoder.beginRenderPass( rpassParam );const computeEncoder = device.createCommandEncoder();const computePass = computeEncoder.beginComputePass()this.createRectGeometryData(device, pass, computePass);pass.end();computePass.end();device.queue.submit([ encoder.finish() ]);device.queue.submit([ computeEncoder.finish() ]);}private async initWebGPU(canvas: HTMLCanvasElement) {const gpu = (navigator as any).gpu;if (gpu) {console.log("WebGPU supported on this browser.");const adapter = await gpu.requestAdapter();if (adapter) {console.log("Appropriate GPUAdapter found.");const device = await adapter.requestDevice();if (device) {this.mWGPUDevice = device;console.log("Appropriate GPUDevice found.");const context = canvas.getContext("webgpu") as any;const canvasFormat = gpu.getPreferredCanvasFormat();this.mWGPUContext = context;this.mCanvasFormat = canvasFormat;console.log("canvasFormat: ", canvasFormat);context.configure({device: device,format: canvasFormat,alphaMode: "premultiplied"});} else {throw new Error("No appropriate GPUDevice found.");}} else {throw new Error("No appropriate GPUAdapter found.");}} else {throw new Error("WebGPU not supported on this browser.");}}run(): void {}
}

这篇关于Google codelab WebGPU入门教程源码<6> - 使用计算着色器实现计算元胞自动机之生命游戏模拟过程(源码)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

中文分词jieba库的使用与实景应用(一)

知识星球:https://articles.zsxq.com/id_fxvgc803qmr2.html 目录 一.定义: 精确模式(默认模式): 全模式: 搜索引擎模式: paddle 模式(基于深度学习的分词模式): 二 自定义词典 三.文本解析   调整词出现的频率 四. 关键词提取 A. 基于TF-IDF算法的关键词提取 B. 基于TextRank算法的关键词提取

使用SecondaryNameNode恢复NameNode的数据

1)需求: NameNode进程挂了并且存储的数据也丢失了,如何恢复NameNode 此种方式恢复的数据可能存在小部分数据的丢失。 2)故障模拟 (1)kill -9 NameNode进程 [lytfly@hadoop102 current]$ kill -9 19886 (2)删除NameNode存储的数据(/opt/module/hadoop-3.1.4/data/tmp/dfs/na

Hadoop数据压缩使用介绍

一、压缩原则 (1)运算密集型的Job,少用压缩 (2)IO密集型的Job,多用压缩 二、压缩算法比较 三、压缩位置选择 四、压缩参数配置 1)为了支持多种压缩/解压缩算法,Hadoop引入了编码/解码器 2)要在Hadoop中启用压缩,可以配置如下参数

作业提交过程之HDFSMapReduce

作业提交全过程详解 (1)作业提交 第1步:Client调用job.waitForCompletion方法,向整个集群提交MapReduce作业。 第2步:Client向RM申请一个作业id。 第3步:RM给Client返回该job资源的提交路径和作业id。 第4步:Client提交jar包、切片信息和配置文件到指定的资源提交路径。 第5步:Client提交完资源后,向RM申请运行MrAp

Makefile简明使用教程

文章目录 规则makefile文件的基本语法:加在命令前的特殊符号:.PHONY伪目标: Makefilev1 直观写法v2 加上中间过程v3 伪目标v4 变量 make 选项-f-n-C Make 是一种流行的构建工具,常用于将源代码转换成可执行文件或者其他形式的输出文件(如库文件、文档等)。Make 可以自动化地执行编译、链接等一系列操作。 规则 makefile文件

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

使用opencv优化图片(画面变清晰)

文章目录 需求影响照片清晰度的因素 实现降噪测试代码 锐化空间锐化Unsharp Masking频率域锐化对比测试 对比度增强常用算法对比测试 需求 对图像进行优化,使其看起来更清晰,同时保持尺寸不变,通常涉及到图像处理技术如锐化、降噪、对比度增强等 影响照片清晰度的因素 影响照片清晰度的因素有很多,主要可以从以下几个方面来分析 1. 拍摄设备 相机传感器:相机传

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象