Browse Source

Wireframe: Add WebGPU version. (#29534)

* Wireframe: Add WebGPU version.

* Examples: Clean up.
Michael Herzog 1 year ago
parent
commit
35127e2517

+ 1 - 0
examples/files.json

@@ -339,6 +339,7 @@
 		"webgpu_lights_phong",
 		"webgpu_lights_rectarealight",
 		"webgpu_lights_selective",
+		"webgpu_lines_fat_wireframe",
 		"webgpu_lines_fat",
 		"webgpu_loader_gltf",
 		"webgpu_loader_gltf_anisotropy",

+ 2 - 0
examples/jsm/lines/LineSegmentsGeometry.js

@@ -82,6 +82,8 @@ class LineSegmentsGeometry extends InstancedBufferGeometry {
 		this.setAttribute( 'instanceStart', new InterleavedBufferAttribute( instanceBuffer, 3, 0 ) ); // xyz
 		this.setAttribute( 'instanceEnd', new InterleavedBufferAttribute( instanceBuffer, 3, 3 ) ); // xyz
 
+		this.instanceCount = this.attributes.instanceStart.count;
+
 		//
 
 		this.computeBoundingBox();

+ 0 - 15
examples/jsm/lines/webgpu/LineSegments2.js

@@ -13,8 +13,6 @@ import {
 } from 'three';
 import { LineSegmentsGeometry } from '../../lines/LineSegmentsGeometry.js';
 
-const _viewport = new Vector4();
-
 const _start = new Vector3();
 const _end = new Vector3();
 
@@ -358,19 +356,6 @@ class LineSegments2 extends Mesh {
 
 	}
 
-	onBeforeRender( renderer ) {
-
-		const uniforms = this.material.uniforms;
-
-		if ( uniforms && uniforms.resolution ) {
-
-			renderer.getViewport( _viewport );
-			this.material.uniforms.resolution.value.set( _viewport.z, _viewport.w );
-
-		}
-
-	}
-
 }
 
 export { LineSegments2 };

+ 56 - 0
examples/jsm/lines/webgpu/Wireframe.js

@@ -0,0 +1,56 @@
+import {
+	InstancedInterleavedBuffer,
+	InterleavedBufferAttribute,
+	Line2NodeMaterial,
+	Mesh,
+	Vector3
+} from 'three';
+import { LineSegmentsGeometry } from '../../lines/LineSegmentsGeometry.js';
+
+const _start = new Vector3();
+const _end = new Vector3();
+
+class Wireframe extends Mesh {
+
+	constructor( geometry = new LineSegmentsGeometry(), material = new Line2NodeMaterial( { color: Math.random() * 0xffffff } ) ) {
+
+		super( geometry, material );
+
+		this.isWireframe = true;
+
+		this.type = 'Wireframe';
+
+	}
+
+	// for backwards-compatibility, but could be a method of LineSegmentsGeometry...
+
+	computeLineDistances() {
+
+		const geometry = this.geometry;
+
+		const instanceStart = geometry.attributes.instanceStart;
+		const instanceEnd = geometry.attributes.instanceEnd;
+		const lineDistances = new Float32Array( 2 * instanceStart.count );
+
+		for ( let i = 0, j = 0, l = instanceStart.count; i < l; i ++, j += 2 ) {
+
+			_start.fromBufferAttribute( instanceStart, i );
+			_end.fromBufferAttribute( instanceEnd, i );
+
+			lineDistances[ j ] = ( j === 0 ) ? 0 : lineDistances[ j - 1 ];
+			lineDistances[ j + 1 ] = lineDistances[ j ] + _start.distanceTo( _end );
+
+		}
+
+		const instanceDistanceBuffer = new InstancedInterleavedBuffer( lineDistances, 2, 1 ); // d0, d1
+
+		geometry.setAttribute( 'instanceDistanceStart', new InterleavedBufferAttribute( instanceDistanceBuffer, 1, 0 ) ); // d0
+		geometry.setAttribute( 'instanceDistanceEnd', new InterleavedBufferAttribute( instanceDistanceBuffer, 1, 1 ) ); // d1
+
+		return this;
+
+	}
+
+}
+
+export { Wireframe };

BIN
examples/screenshots/webgpu_lines_fat_wireframe.jpg


+ 0 - 1
examples/webgpu_lines_fat.html

@@ -102,7 +102,6 @@
 				const geometry = new LineGeometry();
 				geometry.setPositions( positions );
 				geometry.setColors( colors );
-				geometry.instanceCount = positions.length / 3 - 1;
 
 				matLine = new THREE.Line2NodeMaterial( {
 

+ 268 - 0
examples/webgpu_lines_fat_wireframe.html

@@ -0,0 +1,268 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<title>three.js webgpu - lines - fat - wireframe</title>
+		<meta charset="utf-8">
+		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+		<link type="text/css" rel="stylesheet" href="main.css">
+	</head>
+
+	<body>
+
+		<div id="container"></div>
+
+		<div id="info"><a href="https://threejs.org" target="_blank">three.js</a> - fat lines</div>
+
+		<script type="importmap">
+			{
+				"imports": {
+					"three": "../build/three.webgpu.js",
+					"three/tsl": "../build/three.webgpu.js",
+					"three/addons/": "./jsm/"
+				}
+			}
+		</script>
+
+		<script type="module">
+
+			import * as THREE from 'three';
+			import { color } from 'three/tsl';
+
+			import Stats from 'three/addons/libs/stats.module.js';
+
+			import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
+			import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
+			import { Wireframe } from 'three/addons/lines/webgpu/Wireframe.js';
+			import { WireframeGeometry2 } from 'three/addons/lines/WireframeGeometry2.js';
+
+			let wireframe, renderer, scene, camera, camera2, controls, backgroundNode;
+			let wireframe1;
+			let matLine, matLineBasic, matLineDashed;
+			let stats;
+			let gui;
+
+			// viewport
+			let insetWidth;
+			let insetHeight;
+
+			init();
+
+			function init() {
+
+				renderer = new THREE.WebGPURenderer( { antialias: true } );
+				renderer.setPixelRatio( window.devicePixelRatio );
+				renderer.setSize( window.innerWidth, window.innerHeight );
+				renderer.setClearColor( 0x000000, 0.0 );
+				renderer.setAnimationLoop( animate );
+				document.body.appendChild( renderer.domElement );
+
+				scene = new THREE.Scene();
+
+				camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 1000 );
+				camera.position.set( - 50, 0, 50 );
+
+				camera2 = new THREE.PerspectiveCamera( 40, 1, 1, 1000 );
+				camera2.position.copy( camera.position );
+
+				controls = new OrbitControls( camera, renderer.domElement );
+				controls.minDistance = 10;
+				controls.maxDistance = 500;
+
+				backgroundNode = color( 0x222222 );
+
+				// Wireframe ( WireframeGeometry2, Line2NodeMaterial )
+
+				let geo = new THREE.IcosahedronGeometry( 20, 1 );
+
+				const geometry = new WireframeGeometry2( geo );
+
+				matLine = new THREE.Line2NodeMaterial( {
+
+					color: 0x4080ff,
+					linewidth: 5, // in world units with size attenuation, pixels otherwise
+					dashed: false
+
+				} );
+
+				wireframe = new Wireframe( geometry, matLine );
+				wireframe.computeLineDistances();
+				wireframe.scale.set( 1, 1, 1 );
+				scene.add( wireframe );
+
+				// Line ( THREE.WireframeGeometry, THREE.LineBasicMaterial ) - rendered with gl.LINE
+
+				geo = new THREE.WireframeGeometry( geo );
+
+				matLineBasic = new THREE.LineBasicMaterial( { color: 0x4080ff } );
+				matLineDashed = new THREE.LineDashedMaterial( { scale: 2, dashSize: 1, gapSize: 1 } );
+
+				wireframe1 = new THREE.LineSegments( geo, matLineBasic );
+				wireframe1.computeLineDistances();
+				wireframe1.visible = false;
+				scene.add( wireframe1 );
+
+				//
+
+				window.addEventListener( 'resize', onWindowResize );
+				onWindowResize();
+
+				stats = new Stats();
+				document.body.appendChild( stats.dom );
+
+				initGui();
+
+			}
+
+			function onWindowResize() {
+
+				camera.aspect = window.innerWidth / window.innerHeight;
+				camera.updateProjectionMatrix();
+
+				renderer.setSize( window.innerWidth, window.innerHeight );
+
+				insetWidth = window.innerHeight / 4; // square
+				insetHeight = window.innerHeight / 4;
+
+				camera2.aspect = insetWidth / insetHeight;
+				camera2.updateProjectionMatrix();
+
+			}
+
+			function animate() {
+
+				// main scene
+
+				renderer.setClearColor( 0x000000, 0 );
+
+				renderer.setViewport( 0, 0, window.innerWidth, window.innerHeight );
+
+				renderer.autoClear = true;
+
+				scene.backgroundNode = null;
+				renderer.render( scene, camera );
+
+				// inset scene
+
+				const posY = window.innerHeight - insetHeight - 20;
+
+				renderer.clearDepth(); // important!
+
+				renderer.setScissorTest( true );
+
+				renderer.setScissor( 20, posY, insetWidth, insetHeight );
+
+				renderer.setViewport( 20, posY, insetWidth, insetHeight );
+
+				camera2.position.copy( camera.position );
+				camera2.quaternion.copy( camera.quaternion );
+
+				renderer.autoClear = false;
+
+				scene.backgroundNode = backgroundNode;
+				renderer.render( scene, camera2 );
+
+				renderer.setScissorTest( false );
+
+				stats.update();
+
+			}
+
+			//
+
+			function initGui() {
+
+				gui = new GUI();
+
+				const param = {
+					'line type': 0,
+					'width (px)': 5,
+					'dashed': false,
+					'dash scale': 1,
+					'dash / gap': 1
+				};
+
+
+				gui.add( param, 'line type', { 'LineGeometry': 0, 'gl.LINE': 1 } ).onChange( function ( val ) {
+
+					switch ( val ) {
+
+						case 0:
+							wireframe.visible = true;
+
+							wireframe1.visible = false;
+
+							break;
+
+						case 1:
+							wireframe.visible = false;
+
+							wireframe1.visible = true;
+
+							break;
+
+					}
+
+				} );
+
+				gui.add( param, 'width (px)', 1, 10 ).onChange( function ( val ) {
+
+					matLine.linewidth = val;
+
+				} );
+
+				gui.add( param, 'dashed' ).onChange( function ( val ) {
+
+					matLine.dashed = val;
+					wireframe1.material = val ? matLineDashed : matLineBasic;
+
+				} );
+
+				gui.add( param, 'dash scale', 0.5, 1, 0.1 ).onChange( function ( val ) {
+
+					matLine.dashScale = val;
+					matLineDashed.scale = val;
+
+				} );
+
+				gui.add( param, 'dash / gap', { '2 : 1': 0, '1 : 1': 1, '1 : 2': 2 } ).onChange( function ( val ) {
+
+					switch ( val ) {
+
+						case 0:
+							matLine.dashSize = 2;
+							matLine.gapSize = 1;
+
+							matLineDashed.dashSize = 2;
+							matLineDashed.gapSize = 1;
+
+							break;
+
+						case 1:
+							matLine.dashSize = 1;
+							matLine.gapSize = 1;
+
+							matLineDashed.dashSize = 1;
+							matLineDashed.gapSize = 1;
+
+							break;
+
+						case 2:
+							matLine.dashSize = 1;
+							matLine.gapSize = 2;
+
+							matLineDashed.dashSize = 1;
+							matLineDashed.gapSize = 2;
+
+							break;
+
+					}
+
+				} );
+
+			}
+
+		</script>
+
+	</body>
+
+</html>

粤ICP备19079148号