Browse Source

WebGPURenderer: Add material.wireframe support. (#25204)

* WebGPURenderer: Add material.wireframe support.

* fix call

* cleanup
sunag 2 years ago
parent
commit
2a4451c430

+ 110 - 7
examples/jsm/renderers/webgpu/WebGPUGeometries.js

@@ -1,3 +1,19 @@
+import { Uint32BufferAttribute, Uint16BufferAttribute } from 'three';
+
+function arrayNeedsUint32( array ) {
+
+	// assumes larger values usually on last
+
+	for ( let i = array.length - 1; i >= 0; -- i ) {
+
+		if ( array[ i ] >= 65535 ) return true; // account for PRIMITIVE_RESTART_FIXED_INDEX, #24565
+
+	}
+
+	return false;
+
+}
+
 class WebGPUGeometries {
 class WebGPUGeometries {
 
 
 	constructor( attributes, info ) {
 	constructor( attributes, info ) {
@@ -6,6 +22,7 @@ class WebGPUGeometries {
 		this.info = info;
 		this.info = info;
 
 
 		this.geometries = new WeakMap();
 		this.geometries = new WeakMap();
+		this.wireframeGeometries = new WeakMap();
 
 
 	}
 	}
 
 
@@ -15,15 +32,17 @@ class WebGPUGeometries {
 
 
 	}
 	}
 
 
-	update( geometry ) {
+	update( geometry, wireframe = false ) {
+
+		const { geometries, attributes, info } = this;
 
 
-		if ( this.geometries.has( geometry ) === false ) {
+		if ( geometries.has( geometry ) === false ) {
 
 
 			const disposeCallback = onGeometryDispose.bind( this );
 			const disposeCallback = onGeometryDispose.bind( this );
 
 
-			this.geometries.set( geometry, disposeCallback );
+			geometries.set( geometry, disposeCallback );
 
 
-			this.info.memory.geometries ++;
+			info.memory.geometries ++;
 
 
 			geometry.addEventListener( 'dispose', disposeCallback );
 			geometry.addEventListener( 'dispose', disposeCallback );
 
 
@@ -33,18 +52,102 @@ class WebGPUGeometries {
 
 
 		for ( const name in geometryAttributes ) {
 		for ( const name in geometryAttributes ) {
 
 
-			this.attributes.update( geometryAttributes[ name ] );
+			attributes.update( geometryAttributes[ name ] );
 
 
 		}
 		}
 
 
-		const index = geometry.index;
+		const index = this.getIndex( geometry, wireframe );
 
 
 		if ( index !== null ) {
 		if ( index !== null ) {
 
 
-			this.attributes.update( index, true );
+			attributes.update( index, true );
+
+		}
+
+	}
+
+	getIndex( geometry, wireframe = false ) {
+ 
+		let index = geometry.index;
+
+		if ( wireframe ) {
+
+			const wireframeGeometries = this.wireframeGeometries;
+
+			let wireframeAttribute = wireframeGeometries.get( geometry );
+
+			if ( wireframeAttribute === undefined ) {
+
+				wireframeAttribute = this.getWireframeIndex( geometry );
+
+				wireframeGeometries.set( geometry, wireframeAttribute );
+
+			} else if ( wireframeAttribute.version !== this.getWireframeVersion( geometry ) ) {
+
+				this.attributes.remove( wireframeAttribute );
+
+				wireframeAttribute = this.getWireframeIndex( geometry );
+
+				wireframeGeometries.set( geometry, wireframeAttribute );
+
+			}
+
+			index = wireframeAttribute;
 
 
 		}
 		}
 
 
+		return index;
+
+	}
+
+	getWireframeIndex( geometry ) {
+
+		const indices = [];
+
+		const geometryIndex = geometry.index;
+		const geometryPosition = geometry.attributes.position;
+
+		if ( geometryIndex !== null ) {
+
+			const array = geometryIndex.array;
+
+			for ( let i = 0, l = array.length; i < l; i += 3 ) {
+
+				const a = array[ i + 0 ];
+				const b = array[ i + 1 ];
+				const c = array[ i + 2 ];
+
+				indices.push( a, b, b, c, c, a );
+
+			}
+
+		} else {
+
+			const array = geometryPosition.array;
+
+			for ( let i = 0, l = ( array.length / 3 ) - 1; i < l; i += 3 ) {
+
+				const a = i + 0;
+				const b = i + 1;
+				const c = i + 2;
+
+				indices.push( a, b, b, c, c, a );
+
+			}
+
+		}
+
+		const attribute = new ( arrayNeedsUint32( indices ) ? Uint32BufferAttribute : Uint16BufferAttribute )( indices, 1 );
+		attribute.version = this.getWireframeVersion( geometry );
+
+		return attribute;
+
+	}
+
+	getWireframeVersion( geometry ) {
+
+		return ( geometry.index !== null ) ? geometry.index.version : geometry.attributes.position.version;
+
 	}
 	}
 
 
 }
 }

+ 3 - 1
examples/jsm/renderers/webgpu/WebGPUObjects.js

@@ -17,7 +17,9 @@ class WebGPUObjects {
 
 
 		if ( this.geometries.has( geometry ) === false || updateMap.get( geometry ) !== frame ) {
 		if ( this.geometries.has( geometry ) === false || updateMap.get( geometry ) !== frame ) {
 
 
-			this.geometries.update( geometry );
+			const material = object.material;
+
+			this.geometries.update( geometry, material.wireframe === true );
 
 
 			updateMap.set( geometry, frame );
 			updateMap.set( geometry, frame );
 
 

+ 1 - 1
examples/jsm/renderers/webgpu/WebGPURenderer.js

@@ -855,7 +855,7 @@ class WebGPURenderer {
 
 
 		// index
 		// index
 
 
-		const index = geometry.index;
+		const index = this._geometries.getIndex( geometry, material.wireframe === true );
 
 
 		const hasIndex = ( index !== null );
 		const hasIndex = ( index !== null );
 
 

+ 3 - 3
examples/jsm/renderers/webgpu/WebGPUUtils.js

@@ -63,10 +63,10 @@ class WebGPUUtils {
 
 
 	getPrimitiveTopology( object ) {
 	getPrimitiveTopology( object ) {
 
 
-		if ( object.isMesh ) return GPUPrimitiveTopology.TriangleList;
-		else if ( object.isPoints ) return GPUPrimitiveTopology.PointList;
-		else if ( object.isLineSegments ) return GPUPrimitiveTopology.LineList;
+		if ( object.isPoints ) return GPUPrimitiveTopology.PointList;
+		else if ( object.isLineSegments || ( object.isMesh && object.material.wireframe === true ) ) return GPUPrimitiveTopology.LineList;
 		else if ( object.isLine ) return GPUPrimitiveTopology.LineStrip;
 		else if ( object.isLine ) return GPUPrimitiveTopology.LineStrip;
+		else if ( object.isMesh ) return GPUPrimitiveTopology.TriangleList;
 
 
 	}
 	}