Google codelab WebGPU入门教程源码<3> - 绘制网格(源码)

news2025/1/21 3:03:08

对应的教程文章: https://codelabs.developers.google.com/your-first-webgpu-app?hl=zh-cn#4

对应的源码执行效果: 

对应的教程源码: 

此处源码和教程本身提供的部分代码可能存在一点差异。

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 WGPURColorGrid {
	private mRVertices: Float32Array = null;
	private mRPipeline: any | null = null;
	private mVtxBuffer: any | null = null;
	private mCanvasFormat: any | null = null;
	private mWGPUDevice: any | null = null;
	private mWGPUContext: any | null = null;
	private mUniformBindGroup: any | null = null;
	private mGridSize = 32;
	constructor() {}
	initialize(): void {

		const canvas = document.createElement("canvas");
		canvas.width = 512;
		canvas.height = 512;
		document.body.appendChild(canvas);
		this.initWebGPU(canvas).then(() => {
			console.log("webgpu initialization finish ...");

			this.clearWGPUCanvas();
		});
		document.onmousedown = (evt):void => {
			this.clearWGPUCanvas( new Color4( Math.random(), Math.random(), Math.random()) );
		}
	}
	private createUniform(device: any, pipeline: any): void {
		// 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);

		this.mUniformBindGroup = device.createBindGroup({
			label: "Cell renderer bind group",
			layout: pipeline.getBindGroupLayout(0),
			entries: [{
				binding: 0,
				resource: { buffer: uniformBuffer }
			}],
		});
	}
	private createRectGeometryData(device: any, pass: any): void {

		let vertices = this.mRVertices;
		let vertexBuffer = this.mVtxBuffer;
		let cellPipeline = this.mRPipeline;
		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;

			@vertex
			fn 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 gridPos = (input.pos + 1) / grid - 1 + cellOffset;

				var output: VertexOutput;
				output.pos = vec4f(gridPos, 0, 1);
				output.cell = cell;
				return output;
			}

			@fragment
			fn fragmentMain(input: VertexOutput) -> @location(0) vec4f {
				let c = input.cell/grid;
				return vec4f(c, 1.0 - c.x, 1);
			}
			`;
			const cellShaderModule = device.createShaderModule({
				label: "Cell shader",
				code: shaderCodes
				});
			cellPipeline = device.createRenderPipeline({
				label: "Cell pipeline",
				layout: "auto",
				vertex: {
					module: cellShaderModule,
					entryPoint: "vertexMain",
					buffers: [vertexBufferLayout]
				},
				fragment: {
					module: cellShaderModule,
					entryPoint: "fragmentMain",
					targets: [{
						format: this.mCanvasFormat
					}]
				},
			});
			this.mRVertices = vertices;
			this.mVtxBuffer = vertexBuffer;
			this.mRPipeline = cellPipeline;

			this.createUniform(device, cellPipeline);
		}
		pass.setPipeline(cellPipeline);
		pass.setVertexBuffer(0, vertexBuffer);
		pass.setBindGroup(0, this.mUniformBindGroup);
		pass.draw(vertices.length / 2, this.mGridSize * this.mGridSize);
	}

	private clearWGPUCanvas(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], // yes
					view: context.getCurrentTexture().createView(),
					loadOp: "clear",
					storeOp: "store"
				}
			]
		};

		const encoder = device.createCommandEncoder();
		const pass = encoder.beginRenderPass( rpassParam );


		this.createRectGeometryData(device, pass);
		pass.end();
		const commandBuffer = encoder.finish();
		device.queue.submit([commandBuffer]);
	}
	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 {}
}

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

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

相关文章

时区、时间戳、时间点三者的关系

时区、时间戳、时间点这三个概念与Java的Date类和Calendar类紧密联系。分别说说区别。然后说一下Java的Date类和Calendar类 1. 时间戳 时间戳指的就是Unix时间戳(Unix timestamp)。它也被称为Unix时间(Unix time)、POSIX时间(POSIX time)&#xff0c;是一种时间表示方式&…

单词故事嵌入:通过自然语言处理解开叙事

一、介绍 在自然语言处理和文本分析领域&#xff0c;寻求理解和表示人类叙事丰富而复杂的结构是一个持续的挑战。在研究人员和数据科学家可以使用的众多工具和技术中&#xff0c;“Word Story Embeddings”作为一种创新且有前景的方法脱颖而出。这些嵌入建立在词嵌入的基础上&a…

深度学习OCR中文识别 - opencv python 计算机竞赛

文章目录 0 前言1 课题背景2 实现效果3 文本区域检测网络-CTPN4 文本识别网络-CRNN5 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; **基于深度学习OCR中文识别系统 ** 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;…

Jmeter- Beanshell语法和常用内置对象(网络整理)

在利用jmeter进行接口测试或者性能测试的时候&#xff0c;我们需要处理一些复杂的请求&#xff0c;此时就需要利用beanshell脚本了&#xff0c;BeanShell是一种完全符合Java语法规范的脚本语言,并且又拥有自己的一些语法和方法&#xff0c;所以它和java是可以无缝衔接的。beans…

入职算法工程师后敲的非常有趣使用的小工具

NOTE&#xff1a;代码仅用来参考&#xff0c;没时间解释啦&#xff01; &#x1f349;一、自动从数据库从抽取数据。 在某台服务器中&#xff0c;从存放数据集的数据库自动抽取标注好的数据标签&#xff0c;这一步操作有什么用呢&#xff1f;当我们发现我们数据不均衡的时候&a…

OpenSign:安全可靠的电子签名解决方案 | 开源日报 No.76

microsoft/Web-Dev-For-Beginners Stars: 71.5k License: MIT 这个开源项目是一个为期 12 周的全面课程&#xff0c;由微软云倡导者团队提供。它旨在帮助初学者掌握 JavaScript、CSS 和 HTML 的基础知识。每一节都包括预习和复习测验、详细的书面指南、解决方案、作业等内容。…

中小企业如何最大程度地利用CRM系统的潜力?

在当今竞争激烈的商业世界中&#xff0c;客户关系管理&#xff08;CRM&#xff09;数字化转型已经成为大企业成功的重要秘诀。大型跨国公司如亚马逊、苹果和微软等已经在CRM数字化方面走在了前列&#xff0c;实现了高度个性化的客户体验&#xff0c;加强了客户忠诚度。 然而&a…

UI自动化测试框架的搭建(详解)

前言 今天给大家分享一个seleniumtestngmavenant的UI自动化&#xff0c;可以用于功能测试&#xff0c;也可按复杂的业务流程编写测试用例&#xff0c;今天此篇文章不过多讲解如何实现CI/CD&#xff0c;只讲解自己能独立搭建UI框架&#xff0c;需要阅读者有一定的java语言基础&…

FPGA实现Avalon-MM接口通信

在Avalon总线协议&#xff08;一&#xff09;和Avalon总线协议&#xff08;二&#xff09;中大概了解Avalon总线的几种类型&#xff0c;目前比较常用到的就是Avalon-MM接口了&#xff0c;虽然在概念中有那么多的属性&#xff0c;但是具体使用起来还是非常简单的。 一、Avalon-…

《QT从基础到进阶·三十二》Q指针和D指针用法

二进制兼容&#xff1a; 如果程序从一个以前版本的库动态链接到新版本的库之后&#xff0c;能够继续正常运行&#xff0c;而不需要重新编译&#xff0c;那么我们就说这个库是二进制兼容的。&#xff08;通常只要dll的头文件总字节数不变基本满足二进制兼容&#xff0c;pimpl设计…

前端js面试题 (四)

文章目录 ES6新增的proxy手写&#xff0c;proxy访问某对象输出别的数字深度拷贝&#xff0c;为啥无法使用JSON.parse(JSON.stringify(obj))异步编程有哪些&#xff0c;async await来由&#xff0c;本质原理是什么事件队列输出题第一题第二题第三题 粘性布局的原理&#xff0c;以…

2023 年 数维杯(D题)国际大学生数学建模挑战赛 |数学建模完整代码+建模过程全解全析

大家面临着复杂的数学建模问题时&#xff0c;你是否曾经感到茫然无措&#xff1f;作为2022年美国大学生数学建模比赛的O奖得主&#xff0c;我为大家提供了一套优秀的解题思路&#xff0c;让你轻松应对各种难题。 让我们来看看数维杯D题&#xff01; 问题一&#xff1a;最佳清…

软件外包开发设计文档的编写

编写软件设计文档是软件开发过程中至关重要的一步&#xff0c;下面是一些在编写软件设计文档时需要注意的问题&#xff0c;通过注意这些问题&#xff0c;可以确保软件设计文档是清晰、完整且易于理解的&#xff0c;为整个开发团队提供有力的指导。北京木奇移动技术有限公司&…

candence出现no connect property onpin,,,,错误,该怎么办?

原因是上面有引脚添加了 属性no connect&#xff0c;但依然连接了网络&#xff0c;这个时候需要把线剪切&#xff0c;然后看到引脚上有个X, 解决方法&#xff1a; 工具栏&#xff02;place >no connect "X 再连上线&#xff0c;再生成网标的时候&#xff0c; 就不报错了…

【实施】Sentry-self-hosted部署

Sentry-self-hosted部署 介绍 Sentry 是一个开源的错误追踪&#xff08;error tracking&#xff09;平台。它主要用于监控和追踪应用程序中的错误、异常和崩溃。Sentry允许开发人员实时地收集和分析错误&#xff0c;并提供了强大的工具来排查和修复问题&#xff0c;研发最近是…

MCTS蒙特卡洛树搜索(The Monte Carlo Tree Search)

1、简介 蒙特卡罗树搜索是一类树搜索算法的统称&#xff0c;简称MCTS。它是一种用于某些决策过程的启发式搜索算法&#xff0c;且在搜索空间巨大的游戏中会比较有效。从全局来看&#xff0c;蒙特卡洛树搜索的主要目标是&#xff1a;给定一个游戏状态来选择最佳的下一步。等常见…

AD教程 (十六)常用PCB封装的直接调用

AD教程 &#xff08;十六&#xff09;常用PCB封装的直接调用 打开已经做好的PCB文件 点击设计&#xff0c;生成PCB库&#xff0c;会自动把PCB里所用到的所有封装&#xff0c;全部自动生成 CtrlA 将所有元器件的封装全部选中&#xff08;或者只选中所需要的&#xff09;&#x…

Java相关编程思想

少用继承多用“组合”——在现有类的基础上组织一个新类。 2.继承要用“is”来检验&#xff0c;如果继承者is被继承者&#xff0c;说明这是一个比较好的继承。 3.向上造型&#xff0c;把实现方法留给继承者去实现。&#xff08;动态绑定&#xff09; 4.把接口理解为抽象类的进一…

windows安装gdal库

提示&#xff1a;在windows上使用pip在cmd终端安装gdal 文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 原因是由于丹丹安装使用pip安装gdal时报错Microsoft visual C 1…

编码器脉冲信号测量2路DI高速计数器PNP/NPN转RS-485数据采集模块 解码转换成标准Modbus RTU协议 YL150-485

特点&#xff1a; ● 编码器解码转换成标准Modbus RTU协议 ● 可用作编码器计数器或者转速测量 ● 支持编码器计数&#xff0c;可识别正反转 ● 也可以设置作为2路独立DI高速计数器 ● 计数值支持断电自动保存 ● DI输入支持PNP和NPN输入 ● 继电器和机械开关输入时可以…