Bladeren bron

WebGPURenderer: Refactor UBO updates.

Mugen87 4 jaren geleden
bovenliggende
commit
d5c3089f86

+ 42 - 40
examples/jsm/renderers/webgpu/WebGPUBindings.js

@@ -1,7 +1,7 @@
 import WebGPUUniformsGroup from './WebGPUUniformsGroup.js';
+import { FloatUniform, Matrix4Uniform } from './WebGPUUniform.js';
 import WebGPUSampler from './WebGPUSampler.js';
 import WebGPUSampledTexture from './WebGPUSampledTexture.js';
-import { Matrix4 } from '../../../../build/three.module.js';
 
 class WebGPUBindings {
 
@@ -97,7 +97,9 @@ class WebGPUBindings {
 				const array = binding.array;
 				const bufferGPU = binding.bufferGPU;
 
-				const needsBufferWrite = binding.update( object, camera );
+				binding.onBeforeUpdate( object, camera );
+
+				const needsBufferWrite = binding.update();
 
 				if ( needsBufferWrite === true ) {
 
@@ -242,33 +244,36 @@ class WebGPUBindings {
 
 		// ubos
 
+		const modelViewUniform = new Matrix4Uniform( 'modelMatrix' );
+		const modelViewMatrixUniform = new Matrix4Uniform( 'modelViewMatrix' );
+
 		const modelGroup = new WebGPUUniformsGroup();
 		modelGroup.setName( 'modelUniforms' );
-		modelGroup.setUniform( 'modelMatrix', new Matrix4() );
-		modelGroup.setUniform( 'modelViewMatrix', new Matrix4() );
-		modelGroup.setUpdateCallback( function ( object/*, camera */ ) {
+		modelGroup.addUniform( modelViewUniform );
+		modelGroup.addUniform( modelViewMatrixUniform );
+		modelGroup.setOnBeforeUpdate( function ( object/*, camera */ ) {
 
-			let updated = false;
+			modelViewUniform.setValue( object.matrixWorld );
+			modelViewMatrixUniform.setValue( object.modelViewMatrix );
 
-			if ( modelGroup.updateMatrix4( object.matrixWorld, 0 ) ) updated = true;
-			if ( modelGroup.updateMatrix4( object.modelViewMatrix, 16 ) ) updated = true;
+		} );
 
-			return updated;
+		// opacity
 
-		} );
+		const opacityUniform = new FloatUniform( 'opacity', 1 );
 
 		const cameraGroup = this.sharedUniformsGroups.get( 'cameraUniforms' );
 
 		const opacityGroup = new WebGPUUniformsGroup();
 		opacityGroup.setName( 'opacityUniforms' );
-		opacityGroup.setUniform( 'opacity', 1.0 );
+		opacityGroup.addUniform( opacityUniform );
 		opacityGroup.visibility = GPUShaderStage.FRAGMENT;
-		opacityGroup.setUpdateCallback( function ( object/*, camera */ ) {
+		opacityGroup.setOnBeforeUpdate( function ( object/*, camera */ ) {
 
 			const material = object.material;
 			const opacity = ( material.transparent === true ) ? material.opacity : 1.0;
 
-			return opacityGroup.updateNumber( opacity, 0 );
+			opacityUniform.setValue( opacity );
 
 		} );
 
@@ -300,18 +305,17 @@ class WebGPUBindings {
 
 		// ubos
 
+		const modelViewUniform = new Matrix4Uniform( 'modelMatrix' );
+		const modelViewMatrixUniform = new Matrix4Uniform( 'modelViewMatrix' );
+
 		const modelGroup = new WebGPUUniformsGroup();
 		modelGroup.setName( 'modelUniforms' );
-		modelGroup.setUniform( 'modelMatrix', new Matrix4() );
-		modelGroup.setUniform( 'modelViewMatrix', new Matrix4() );
-		modelGroup.setUpdateCallback( function ( object/*, camera */ ) {
-
-			let updated = false;
-
-			if ( modelGroup.updateMatrix4( object.matrixWorld, 0 ) ) updated = true;
-			if ( modelGroup.updateMatrix4( object.modelViewMatrix, 16 ) ) updated = true;
+		modelGroup.addUniform( modelViewUniform );
+		modelGroup.addUniform( modelViewMatrixUniform );
+		modelGroup.setOnBeforeUpdate( function ( object/*, camera */ ) {
 
-			return updated;
+			modelViewUniform.setValue( object.matrixWorld );
+			modelViewMatrixUniform.setValue( object.modelViewMatrix );
 
 		} );
 
@@ -332,18 +336,17 @@ class WebGPUBindings {
 
 		// ubos
 
+		const modelViewUniform = new Matrix4Uniform( 'modelMatrix' );
+		const modelViewMatrixUniform = new Matrix4Uniform( 'modelViewMatrix' );
+
 		const modelGroup = new WebGPUUniformsGroup();
 		modelGroup.setName( 'modelUniforms' );
-		modelGroup.setUniform( 'modelMatrix', new Matrix4() );
-		modelGroup.setUniform( 'modelViewMatrix', new Matrix4() );
-		modelGroup.setUpdateCallback( function ( object/*, camera */ ) {
-
-			let updated = false;
-
-			if ( modelGroup.updateMatrix4( object.matrixWorld, 0 ) ) updated = true;
-			if ( modelGroup.updateMatrix4( object.modelViewMatrix, 16 ) ) updated = true;
+		modelGroup.addUniform( modelViewUniform );
+		modelGroup.addUniform( modelViewMatrixUniform );
+		modelGroup.setOnBeforeUpdate( function ( object/*, camera */ ) {
 
-			return updated;
+			modelViewUniform.setValue( object.matrixWorld );
+			modelViewMatrixUniform.setValue( object.modelViewMatrix );
 
 		} );
 
@@ -360,18 +363,17 @@ class WebGPUBindings {
 
 	_setupSharedUniformsGroups() {
 
+		const projectionMatrixUniform = new Matrix4Uniform( 'projectionMatrix' );
+		const viewMatrixUniform = new Matrix4Uniform( 'viewMatrix' );
+
 		const cameraGroup = new WebGPUUniformsGroup();
 		cameraGroup.setName( 'cameraUniforms' );
-		cameraGroup.setUniform( 'projectionMatrix', new Matrix4() );
-		cameraGroup.setUniform( 'viewMatrix', new Matrix4() );
-		cameraGroup.setUpdateCallback( function ( object, camera ) {
-
-			let updated = false;
-
-			if ( cameraGroup.updateMatrix4( camera.projectionMatrix, 0 ) ) updated = true;
-			if ( cameraGroup.updateMatrix4( camera.matrixWorldInverse, 16 ) ) updated = true;
+		cameraGroup.addUniform( projectionMatrixUniform );
+		cameraGroup.addUniform( viewMatrixUniform );
+		cameraGroup.setOnBeforeUpdate( function ( object, camera ) {
 
-			return updated;
+			projectionMatrixUniform.setValue( camera.projectionMatrix );
+			viewMatrixUniform.setValue( camera.matrixWorldInverse );
 
 		} );
 

+ 129 - 0
examples/jsm/renderers/webgpu/WebGPUUniform.js

@@ -0,0 +1,129 @@
+import { Color, Matrix3, Matrix4, Vector2, Vector3, Vector4 } from '../../../../build/three.module.js';
+
+class WebGPUUniform {
+
+	constructor( name, value ) {
+
+		this.name = name;
+		this.value = value;
+
+		this.byteLength = 0;
+		this.itemSize = 0;
+		this.value = null;
+
+	}
+
+	setValue( value ) {
+
+		this.value = value;
+
+	}
+
+}
+
+class FloatUniform extends WebGPUUniform {
+
+	constructor( name, value = 0 ) {
+
+		super( name, value );
+
+		this.byteLength = 4;
+		this.itemSize = 1;
+
+		Object.defineProperty( this, 'isFloatUniform', { value: true } );
+
+	}
+
+}
+
+class Vector2Uniform extends WebGPUUniform {
+
+	constructor( name, value = new Vector2() ) {
+
+		super( name, value );
+
+		this.byteLength = 8;
+		this.itemSize = 2;
+
+		Object.defineProperty( this, 'isVector2Uniform', { value: true } );
+
+	}
+
+}
+
+class Vector3Uniform extends WebGPUUniform {
+
+	constructor( name, value = new Vector3() ) {
+
+		super( name, value );
+
+		this.byteLength = 12;
+		this.itemSize = 3;
+
+		Object.defineProperty( this, 'isVector3Uniform', { value: true } );
+
+	}
+
+}
+
+class Vector4Uniform extends WebGPUUniform {
+
+	constructor( name, value = new Vector4() ) {
+
+		super( name, value );
+
+		this.byteLength = 16;
+		this.itemSize = 4;
+
+		Object.defineProperty( this, 'isVector4Uniform', { value: true } );
+
+	}
+
+}
+
+class ColorUniform extends WebGPUUniform {
+
+	constructor( name, value = new Color() ) {
+
+		super( name, value );
+
+		this.byteLength = 12;
+		this.itemSize = 3;
+
+		Object.defineProperty( this, 'isColorUniform', { value: true } );
+
+	}
+
+}
+
+class Matrix3Uniform extends WebGPUUniform {
+
+	constructor( name, value = new Matrix3() ) {
+
+		super( name, value );
+
+		this.byteLength = 48; // (3 * 4) * 4 bytes
+		this.itemSize = 12;
+
+		Object.defineProperty( this, 'isMatrix3Uniform', { value: true } );
+
+	}
+
+}
+
+class Matrix4Uniform extends WebGPUUniform {
+
+	constructor( name, value = new Matrix4() ) {
+
+		super( name, value );
+
+		this.byteLength = 64;
+		this.itemSize = 16;
+
+		Object.defineProperty( this, 'isMatrix4Uniform', { value: true } );
+
+	}
+
+}
+
+export { FloatUniform, Vector2Uniform, Vector3Uniform, Vector4Uniform, ColorUniform, Matrix3Uniform, Matrix4Uniform };

+ 54 - 57
examples/jsm/renderers/webgpu/WebGPUUniformsGroup.js

@@ -7,9 +7,9 @@ class WebGPUUniformsGroup extends WebGPUBinding {
 		super();
 
 		this.name = '';
-		this.uniforms = new Map();
+		this.uniforms = [];
 
-		this.update = function () {};
+		this.onBeforeUpdate = function () {};
 
 		this.type = 'uniform-buffer';
 		this.visibility = GPUShaderStage.VERTEX;
@@ -29,25 +29,31 @@ class WebGPUUniformsGroup extends WebGPUBinding {
 
 	}
 
-	setUniform( name, uniform ) {
+	addUniform( uniform ) {
 
-		this.uniforms.set( name, uniform );
+		this.uniforms.push( uniform );
 
 		return this;
 
 	}
 
-	removeUniform( name ) {
+	removeUniform( uniform ) {
 
-		this.uniforms.delete( name );
+		const index = this.uniforms.indexOf( uniform );
+
+		if ( index !== - 1 ) {
+
+			this.uniforms.splice( index, 1 );
+
+		}
 
 		return this;
 
 	}
 
-	setUpdateCallback( callback ) {
+	setOnBeforeUpdate( callback ) {
 
-		this.update = callback;
+		this.onBeforeUpdate = callback;
 
 		return this;
 
@@ -57,15 +63,8 @@ class WebGPUUniformsGroup extends WebGPUBinding {
 
 		this.name = source.name;
 
-		const uniformsSource = source.uniforms;
-
-		this.uniforms.clear();
-
-		for ( const entry of uniformsSource ) {
-
-			this.uniforms.set( ...entry );
-
-		}
+		this.uniforms.length = 0;
+		this.uniforms.push( ...source.uniforms );
 
 		return this;
 
@@ -79,65 +78,59 @@ class WebGPUUniformsGroup extends WebGPUBinding {
 
 	getByteLength() {
 
-		let size = 0;
+		let byteLength = 0;
 
-		for ( const uniform of this.uniforms.values() ) {
+		for ( const uniform of this.uniforms ) {
 
-			size += this.getUniformByteLength( uniform );
+			byteLength += uniform.byteLength;
 
 		}
 
-		return size;
+		return byteLength;
 
 	}
 
-	getUniformByteLength( uniform ) {
-
-		let size;
-
-		if ( typeof uniform === 'number' ) {
+	update() {
 
-			size = 4;
-
-		} else if ( uniform.isVector2 ) {
-
-			size = 8;
-
-		} else if ( uniform.isVector3 || uniform.isColor ) {
-
-			size = 12;
-
-		} else if ( uniform.isVector4 ) {
+		let updated = false;
+		let offset = 0;
 
-			size = 16;
+		for ( const uniform of this.uniforms ) {
 
-		} else if ( uniform.isMatrix3 ) {
+			if ( this.updateByType( uniform, offset ) === true ) {
 
-			size = 48; // (3 * 4) * 4 bytes
+				updated = true;
 
-		} else if ( uniform.isMatrix4 ) {
+			}
 
-			size = 64;
+			offset += uniform.itemSize;
 
-		} else if ( uniform.isTexture ) {
+		}
 
-			console.error( 'THREE.UniformsGroup: Texture samplers can not be part of an uniforms group.' );
+		return updated;
 
-		} else {
+	}
 
-			console.error( 'THREE.UniformsGroup: Unsupported uniform value type.', uniform );
+	updateByType( uniform, offset ) {
 
-		}
+		if ( uniform.isFloatUniform ) return this.updateNumber( uniform, offset );
+		if ( uniform.isVector2Uniform ) return this.updateVector2( uniform, offset );
+		if ( uniform.isVector3Uniform ) return this.updateVector3( uniform, offset );
+		if ( uniform.isVector4Uniform ) return this.updateVector4( uniform, offset );
+		if ( uniform.isColorUniform ) return this.updateColor( uniform, offset );
+		if ( uniform.isMatrix3Uniform ) return this.updateMatrix3( uniform, offset );
+		if ( uniform.isMatrix4Uniform ) return this.updateMatrix4( uniform, offset );
 
-		return size;
+		console.error( 'THREE.WebGPUUniformsGroup: Unsupported uniform type.', uniform );
 
 	}
 
-	updateNumber( v, offset ) {
+	updateNumber( uniform, offset ) {
 
 		let updated = false;
 
 		const a = this.array;
+		const v = uniform.value;
 
 		if ( a[ offset ] !== v ) {
 
@@ -150,11 +143,12 @@ class WebGPUUniformsGroup extends WebGPUBinding {
 
 	}
 
-	updateVector2( v, offset ) {
+	updateVector2( uniform, offset ) {
 
 		let updated = false;
 
 		const a = this.array;
+		const v = uniform.value;
 
 		if ( a[ offset + 0 ] !== v.x || a[ offset + 1 ] !== v.y ) {
 
@@ -169,11 +163,12 @@ class WebGPUUniformsGroup extends WebGPUBinding {
 
 	}
 
-	updateVector3( v, offset ) {
+	updateVector3( uniform, offset ) {
 
 		let updated = false;
 
 		const a = this.array;
+		const v = uniform.value;
 
 		if ( a[ offset + 0 ] !== v.x || a[ offset + 1 ] !== v.y || a[ offset + 2 ] !== v.z ) {
 
@@ -189,11 +184,12 @@ class WebGPUUniformsGroup extends WebGPUBinding {
 
 	}
 
-	updateVector4( v, offset ) {
+	updateVector4( uniform, offset ) {
 
 		let updated = false;
 
 		const a = this.array;
+		const v = uniform.value;
 
 		if ( a[ offset + 0 ] !== v.x || a[ offset + 1 ] !== v.y || a[ offset + 2 ] !== v.z || a[ offset + 4 ] !== v.w ) {
 
@@ -210,11 +206,12 @@ class WebGPUUniformsGroup extends WebGPUBinding {
 
 	}
 
-	updateColor( c, offset ) {
+	updateColor( uniform, offset ) {
 
 		let updated = false;
 
 		const a = this.array;
+		const c = uniform.value;
 
 		if ( a[ offset + 0 ] !== c.r || a[ offset + 1 ] !== c.g || a[ offset + 2 ] !== c.b ) {
 
@@ -230,12 +227,12 @@ class WebGPUUniformsGroup extends WebGPUBinding {
 
 	}
 
-	updateMatrix3( m, offset ) {
+	updateMatrix3( uniform, offset ) {
 
 		let updated = false;
 
 		const a = this.array;
-		const e = m.elements;
+		const e = uniform.value.elements;
 
 		if ( a[ offset + 0 ] !== e[ 0 ] || a[ offset + 1 ] !== e[ 1 ] || a[ offset + 2 ] !== e[ 2 ] ||
 			a[ offset + 4 ] !== e[ 3 ] || a[ offset + 5 ] !== e[ 4 ] || a[ offset + 6 ] !== e[ 5 ] ||
@@ -259,12 +256,12 @@ class WebGPUUniformsGroup extends WebGPUBinding {
 
 	}
 
-	updateMatrix4( m, offset ) {
+	updateMatrix4( uniform, offset ) {
 
 		let updated = false;
 
 		const a = this.array;
-		const e = m.elements;
+		const e = uniform.value.elements;
 
 		if ( arraysEqual( a, e, offset ) === false ) {