Преглед на файлове

WebGPU: Add WebGPUUniformBuffer (#22486)

* add WebGPUUniformBuffer

* add WebGPUUniformBuffer to example

* fix layout names

* more particles

* removed WebGPUUniformBuffer.onBeforeUpdate()
sunag преди 3 години
родител
ревизия
3de8159732

+ 4 - 8
examples/jsm/renderers/webgpu/WebGPUBindings.js

@@ -99,13 +99,11 @@ class WebGPUBindings {
 
 			if ( isShared && isUpdated ) continue;
 
-			if ( binding.isUniformsGroup ) {
+			if ( binding.isUniformBuffer ) {
 
-				const array = binding.array;
+				const buffer = binding.getBuffer();
 				const bufferGPU = binding.bufferGPU;
 
-				binding.onBeforeUpdate( object, camera );
-
 				const needsBufferWrite = binding.update();
 
 				if ( needsBufferWrite === true ) {
@@ -113,7 +111,7 @@ class WebGPUBindings {
 					this.device.queue.writeBuffer(
 						bufferGPU,
 						0,
-						array,
+						buffer,
 						0
 					);
 
@@ -181,14 +179,12 @@ class WebGPUBindings {
 
 		for ( const binding of bindings ) {
 
-			if ( binding.isUniformsGroup ) {
+			if ( binding.isUniformBuffer ) {
 
 				if ( binding.bufferGPU === null ) {
 
 					const byteLength = binding.getByteLength();
 
-					binding.array = new Float32Array( new ArrayBuffer( byteLength ) );
-
 					binding.bufferGPU = this.device.createBuffer( {
 						size: byteLength,
 						usage: binding.usage,

+ 45 - 0
examples/jsm/renderers/webgpu/WebGPUUniformBuffer.js

@@ -0,0 +1,45 @@
+import WebGPUBinding from './WebGPUBinding.js';
+import { GPUBindingType } from './constants.js';
+
+class WebGPUUniformBuffer extends WebGPUBinding {
+
+	constructor( name, buffer = null ) {
+
+		super( name );
+
+		this.bytesPerElement = Float32Array.BYTES_PER_ELEMENT;
+		this.type = GPUBindingType.UniformBuffer;
+		this.visibility = GPUShaderStage.VERTEX;
+
+		this.usage = GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST;
+
+		this.buffer = buffer;
+		this.bufferGPU = null; // set by the renderer
+
+	}
+
+	getByteLength() {
+
+		const buffer = 	this.buffer;
+
+		return buffer.byteLength + ( ( 4 - ( buffer.byteLength % 4 ) ) % 4 ); // ensure 4 byte alignment, see #20441
+
+	}
+
+	getBuffer() {
+
+		return this.buffer;
+
+	}
+
+	update() {
+
+		return true;
+
+	}
+
+}
+
+WebGPUUniformBuffer.prototype.isUniformBuffer = true;
+
+export default WebGPUUniformBuffer;

+ 23 - 24
examples/jsm/renderers/webgpu/WebGPUUniformsGroup.js

@@ -1,27 +1,16 @@
-import WebGPUBinding from './WebGPUBinding.js';
+import WebGPUUniformBuffer from './WebGPUUniformBuffer.js';
 import { GPUBindingType } from './constants.js';
 
-class WebGPUUniformsGroup extends WebGPUBinding {
+class WebGPUUniformsGroup extends WebGPUUniformBuffer {
 
 	constructor( name ) {
 
 		super( name );
 
-		 // the order of uniforms in this array must match the order of uniforms in the shader
+		// the order of uniforms in this array must match the order of uniforms in the shader
 
 		this.uniforms = [];
 
-		this.onBeforeUpdate = function () {};
-
-		this.bytesPerElement = Float32Array.BYTES_PER_ELEMENT;
-		this.type = GPUBindingType.UniformBuffer;
-		this.visibility = GPUShaderStage.VERTEX;
-
-		this.usage = GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST;
-
-		this.array = null; // set by the renderer
-		this.bufferGPU = null; // set by the renderer
-
 	}
 
 	addUniform( uniform ) {
@@ -46,11 +35,21 @@ class WebGPUUniformsGroup extends WebGPUBinding {
 
 	}
 
-	setOnBeforeUpdate( callback ) {
+	getBuffer() {
 
-		this.onBeforeUpdate = callback;
+		let buffer = this.buffer;
 
-		return this;
+		if ( buffer === null ) {
+
+			const byteLength = this.getByteLength();
+
+			buffer = new Float32Array( new ArrayBuffer( byteLength ) );
+
+			this.buffer = buffer;
+
+		}
+
+		return buffer;
 
 	}
 
@@ -130,7 +129,7 @@ class WebGPUUniformsGroup extends WebGPUBinding {
 
 		let updated = false;
 
-		const a = this.array;
+		const a = this.buffer;
 		const v = uniform.getValue();
 		const offset = uniform.offset;
 
@@ -149,7 +148,7 @@ class WebGPUUniformsGroup extends WebGPUBinding {
 
 		let updated = false;
 
-		const a = this.array;
+		const a = this.buffer;
 		const v = uniform.getValue();
 		const offset = uniform.offset;
 
@@ -170,7 +169,7 @@ class WebGPUUniformsGroup extends WebGPUBinding {
 
 		let updated = false;
 
-		const a = this.array;
+		const a = this.buffer;
 		const v = uniform.getValue();
 		const offset = uniform.offset;
 
@@ -192,7 +191,7 @@ class WebGPUUniformsGroup extends WebGPUBinding {
 
 		let updated = false;
 
-		const a = this.array;
+		const a = this.buffer;
 		const v = uniform.getValue();
 		const offset = uniform.offset;
 
@@ -215,7 +214,7 @@ class WebGPUUniformsGroup extends WebGPUBinding {
 
 		let updated = false;
 
-		const a = this.array;
+		const a = this.buffer;
 		const c = uniform.getValue();
 		const offset = uniform.offset;
 
@@ -237,7 +236,7 @@ class WebGPUUniformsGroup extends WebGPUBinding {
 
 		let updated = false;
 
-		const a = this.array;
+		const a = this.buffer;
 		const e = uniform.getValue().elements;
 		const offset = uniform.offset;
 
@@ -267,7 +266,7 @@ class WebGPUUniformsGroup extends WebGPUBinding {
 
 		let updated = false;
 
-		const a = this.array;
+		const a = this.buffer;
 		const e = uniform.getValue().elements;
 		const offset = uniform.offset;
 

+ 30 - 5
examples/webgpu_compute.html

@@ -23,10 +23,13 @@
 
 			import * as THREE from 'three';
 
+			import { GUI } from './jsm/libs/dat.gui.module.js';
+
 			import WebGPURenderer from './jsm/renderers/webgpu/WebGPURenderer.js';
 			import WebGPU from './jsm/renderers/webgpu/WebGPU.js';
 
 			import WebGPUStorageBuffer from './jsm/renderers/webgpu/WebGPUStorageBuffer.js';
+			import WebGPUUniformBuffer from './jsm/renderers/webgpu/WebGPUUniformBuffer.js';
 			import WebGPUUniformsGroup from './jsm/renderers/webgpu/WebGPUUniformsGroup.js';
 			import { Vector2Uniform } from './jsm/renderers/webgpu/WebGPUUniform.js';
 
@@ -36,6 +39,8 @@
 
 			let camera, scene, renderer;
 			let pointer;
+			let scaleUniformBuffer;
+			let scaleVector = new THREE.Vector3( 1, 1, 1 );
 
 			const computeParams = [];
 
@@ -57,7 +62,7 @@
 				scene = new THREE.Scene();
 				scene.background = new THREE.Color( 0x000000 );
 
-				const particleNum = 50000; // 16-bit limit
+				const particleNum = 65000; // 16-bit limit
 				const particleSize = 3;
 
 				const particleArray = new Float32Array( particleNum * particleSize );
@@ -75,15 +80,20 @@
 				const particleBuffer = new WebGPUStorageBuffer( 'particle', new THREE.BufferAttribute( particleArray, 3 ) );
 				const velocityBuffer = new WebGPUStorageBuffer( 'velocity', new THREE.BufferAttribute( velocityArray, 3 ) );
 
+				scaleUniformBuffer = new WebGPUUniformBuffer( 'scaleUniform', new Float32Array( 3 ) ); // single vector3
+
 				pointer = new THREE.Vector2( - 10.0, - 10.0 ); // Out of bounds first
 
 				const pointerGroup = new WebGPUUniformsGroup( 'mouseUniforms' ).addUniform(
 					new Vector2Uniform( 'pointer', pointer )
 				);
 
+				// Object keys need follow the binding shader sequence
+
 				const computeBindings = [
 					particleBuffer,
 					velocityBuffer,
+					scaleUniformBuffer,
 					pointerGroup
 				];
 
@@ -103,7 +113,11 @@
 						float velocity[ PARTICLE_NUM * PARTICLE_SIZE ];
 					} velocity;
 
-					layout(set = 0, binding = 2) uniform MouseUniforms {
+					layout(set = 0, binding = 2) uniform Scale {
+						vec3 value;
+					} scaleUniform;
+
+					layout(set = 0, binding = 3) uniform MouseUniforms {
 						vec2 pointer;
 					} mouseUniforms;
 
@@ -147,9 +161,10 @@
 
 						}
 
-						particle.particle[ index * 3 + 0 ] = position.x;
-						particle.particle[ index * 3 + 1 ] = position.y;
-						particle.particle[ index * 3 + 2 ] = position.z;
+						particle.particle[ index * 3 + 0 ] = position.x * scaleUniform.value.x;
+						particle.particle[ index * 3 + 1 ] = position.y * scaleUniform.value.y;
+						particle.particle[ index * 3 + 2 ] = position.z * scaleUniform.value.z;
+
 					}
 				`;
 
@@ -179,6 +194,14 @@
 				window.addEventListener( 'resize', onWindowResize );
 				window.addEventListener( 'mousemove', onMouseMove );
 
+				// gui
+
+				const gui = new GUI();
+
+				gui.add( scaleVector, 'x', 0.9, 1.1, 0.01 );
+				gui.add( scaleVector, 'y', 0.9, 1.1, 0.01 );
+				gui.add( scaleVector, 'z', 0.9, 1.1, 0.01 );
+
 				return renderer.init();
 
 			}
@@ -213,6 +236,8 @@
 				renderer.compute( computeParams );
 				renderer.render( scene, camera );
 
+				scaleVector.toArray( scaleUniformBuffer.buffer, 0 );
+
 			}
 
 			function error( error ) {