当前位置: 首页 > article >正文

Google codelab WebGPU入门教程源码<4> - 使用Uniform类型对象给着色器传数据(源码)

对应的教程文章: 

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

对应的源码执行效果:

对应的教程源码: 

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

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 WGPURUniform {
	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 = 4;
	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.clearWGPUCanvas();
		});
		document.onmousedown = (evt):void => {
			this.updateUniform(this.mWGPUDevice);
			this.clearWGPUCanvas( new Color4( Math.random(), Math.random(), Math.random()) );
		}
	}

	private mUniformObj: any = {uniformArray: null, uniformBuffer: null};

	private updateUniform(device: any): void {

		let n = Math.round(Math.random() * 3);
		this.mGridSize = 2 + n;
		const obj = this.mUniformObj;
		obj.uniformArray[0] = this.mGridSize;
		obj.uniformArray[1] = this.mGridSize;
		device.queue.writeBuffer(obj.uniformBuffer, 0, obj.uniformArray);
	}
	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 }
			}],
		});
		const obj = this.mUniformObj;
		obj.uniformArray = uniformArray;
		obj.uniformBuffer = 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 = `
			@group(0) @binding(0) var<uniform> grid: vec2f;

			@vertex
			fn vertexMain(@location(0) pos: vec2f,
						@builtin(instance_index) instance: u32) ->
				@builtin(position) vec4f {
					let i = f32(instance);
  					// Compute the cell coordinate from the instance_index
  					let cell = vec2f(i % grid.x, floor(i / grid.x));
  					let cellOffset = cell / grid * 2;
  					let gridPos = (pos + 1) / grid - 1 + cellOffset;

					return vec4f(gridPos, 0, 1);
			}
			@fragment
			fn fragmentMain() -> @location(0) vec4f {
				return vec4f(0.8, 0.1, 0.1, 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.kler.cn/a/146559.html

相关文章:

  • 内联变量(inline variables):在多个文件中共享全局常量
  • <OS 有关>Ubuntu 24 安装 openssh-server, tailscale+ssh 慢增加
  • 懒饭 3.0.2 | 谷歌版纯净无广告教做菜软件
  • 总结SpringBoot项目中读取resource目录下的文件多种方法
  • Boost Asio TCP异步服务端和客户端
  • JVM之垃圾回收器ZGC概述以及垃圾回收器总结的详细解析
  • C#,《小白学程序》第一课:初识程序,变量,数据与显示
  • 时间序列预测 — LSTM实现多变量多步负荷预测(Keras)
  • 【计算机基础】通过插件plantuml,实现在VScode里面绘制状态机
  • Linux C语言 27-递归
  • 【多线程】-- 04 静态代理模式
  • 蓝桥杯每日一题2023.11.25
  • pop链反序列化 [MRCTF2020]Ezpop1
  • AIGC系列之:Transformer原理及论文解读
  • MacOS “xxxxx“,已损坏,无法打开,你应该将它移到废纸篓
  • 【前沿技术了解】web图形Canvas、svg、WebGL、数据可视化引擎的技术选型
  • 【03】命令行与环境变量
  • MySQL基本SQL语句(上)
  • github国内访问小解(windows)
  • openpnp - 给底部相机加防尘罩
  • mysql常见的十种错误简要说明
  • ElasticSearch02
  • 羊大师:控制血糖,让你的健康更美好
  • 十四、机器学习进阶知识:KNN分类算法
  • @RequestMapping,@GetMapping,@PostMapping 的区别(详解)
  • Linux C语言 24-格式化操作