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

当前示例源码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机制中。

当前示例运行效果:

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

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 grid: vec2f;
@group(0) @binding(1) var cellState: array;
@group(0) @binding(2) var lifeState: array;
@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(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);
	}
}

你可能感兴趣的:(GPU/CPU,WebGL/WebGPU,3D引擎,3d,WebGPU,compute,shader)