Explorar el Código

Nodes: `InstancedPointsNodeMaterial` - Add `pointWidthNode` (#29236)

* init

* adjustment

* adjust

* set instancePosition.xyz to fix warning when instancePosition is accessed as a StorageBufferNode in a compute shader

* cleanup and screenshot

* add instance points example to exception

* reduce instanced points complexity

* add pointColorNode usage example, remove unused values

* revision

---------
Christian Helgeson hace 1 año
padre
commit
7506a353d6

BIN
examples/screenshots/webgpu_instance_points.jpg


+ 55 - 31
examples/webgpu_instance_points.html

@@ -26,7 +26,7 @@
 		<script type="module">
 
 			import * as THREE from 'three';
-			import { color } from 'three/tsl';
+			import { color, storage, Fn, instanceIndex, sin, timerLocal, float, uniform, attribute, mix, vec3 } from 'three/tsl';
 
 			import Stats from 'three/addons/libs/stats.module.js';
 
@@ -42,11 +42,15 @@
 			let material;
 			let stats;
 			let gui;
+			let effectController;
 
 			// viewport
 			let insetWidth;
 			let insetHeight;
 
+			// compute
+			let computeSize;
+
 			init();
 
 			function init() {
@@ -72,10 +76,16 @@
 
 				backgroundNode = color( 0x222222 );
 
-				// Position and THREE.Color Data
+				effectController = {
 
-				const positions = [];
-				const colors = [];
+					pulseSpeed: uniform( 6 ),
+					minWidth: uniform( 6 ),
+					maxWidth: uniform( 12 ),
+					alphaToCoverage: true,
+
+				};
+
+				// Position and THREE.Color Data
 
 				const points = GeometryUtils.hilbert3D( new THREE.Vector3( 0, 0, 0 ), 20.0, 1, 0, 1, 2, 3, 4, 5, 6, 7 );
 
@@ -84,6 +94,10 @@
 				const point = new THREE.Vector3();
 				const pointColor = new THREE.Color();
 
+				const positions = [];
+				const colors = [];
+				const sizes = new Float32Array( divisions );
+
 				for ( let i = 0, l = divisions; i < l; i ++ ) {
 
 					const t = i / l;
@@ -94,6 +108,8 @@
 					pointColor.setHSL( t, 1.0, 0.5, THREE.SRGBColorSpace );
 					colors.push( pointColor.r, pointColor.g, pointColor.b );
 
+					sizes[ i ] = 10.0;
+
 				}
 
 				// Instanced Points
@@ -102,31 +118,59 @@
 				geometry.setPositions( positions );
 				geometry.setColors( colors );
 
+				const instanceSizeBufferAttribute = new THREE.StorageInstancedBufferAttribute( sizes, 1 );
+				geometry.setAttribute( 'instanceSize', instanceSizeBufferAttribute );
+				const instanceSizeStorage = storage( instanceSizeBufferAttribute, 'float', instanceSizeBufferAttribute.count );
+
+				computeSize = Fn( () => {
+
+					const { pulseSpeed, minWidth, maxWidth } = effectController;
+
+					const time = timerLocal().add( float( instanceIndex ) );
+
+					const sizeFactor = sin( time.mul( pulseSpeed ) ).add( 1 ).div( 2 );
+
+					instanceSizeStorage.element( instanceIndex ).assign( sizeFactor.mul( maxWidth.sub( minWidth ) ).add( minWidth ) );
+
+				} )().compute( divisions );
+			
 				geometry.instanceCount = positions.length / 3; // this should not be necessary
 
 				material = new THREE.InstancedPointsNodeMaterial( {
 
 					color: 0xffffff,
 					pointWidth: 10, // in pixel units
-
 					vertexColors: true,
 					alphaToCoverage: true,
 
 				} );
 
+				const attributeRange = attribute( 'instanceSize' ).sub( 1 );
+
+				material.pointWidthNode = attribute( 'instanceSize' );
+				material.pointColorNode = mix( vec3( 0.0 ), attribute( 'instanceColor' ), attributeRange.div( float( effectController.maxWidth.sub( 1 ) ) ) );
+
 				const instancedPoints = new InstancedPoints( geometry, material );
 				instancedPoints.scale.set( 1, 1, 1 );
 				scene.add( instancedPoints );
 
-				//
-
 				window.addEventListener( 'resize', onWindowResize );
 				onWindowResize();
 
 				stats = new Stats();
 				document.body.appendChild( stats.dom );
 
-				initGui();
+				gui = new GUI();
+
+				gui.add( effectController, 'alphaToCoverage' ).onChange( function ( val ) {
+
+					material.alphaToCoverage = val;
+
+				} );
+
+				gui.add( effectController.minWidth, 'value', 1, 20, 1 ).name( 'minWidth' );
+				gui.add( effectController.maxWidth, 'value', 2, 20, 1 ).name( 'maxWidth' );
+				gui.add( effectController.pulseSpeed, 'value', 1, 20, 0.1 ).name( 'pulseSpeed' );
 
 			}
 
@@ -149,6 +193,9 @@
 
 				stats.update();
 
+				// compute
+				renderer.compute( computeSize );
+
 				// main scene
 
 				renderer.setViewport( 0, 0, window.innerWidth, window.innerHeight );
@@ -189,29 +236,6 @@
 
 			//
 
-			function initGui() {
-
-				gui = new GUI();
-
-				const param = {
-					'width': 10,
-					'alphaToCoverage': true,
-				};
-
-				gui.add( param, 'width', 1, 20, 1 ).onChange( function ( val ) {
-
-					material.pointWidth = val;
-
-				} );
-
-				gui.add( param, 'alphaToCoverage' ).onChange( function ( val ) {
-
-					material.alphaToCoverage = val;
-
-				} );
-
-			}
-
 		</script>
 
 	</body>

+ 6 - 2
src/materials/nodes/InstancedPointsNodeMaterial.js

@@ -30,6 +30,8 @@ class InstancedPointsNodeMaterial extends NodeMaterial {
 
 		this.pointColorNode = null;
 
+		this.pointWidthNode = null;
+
 		this.setDefaultValues( _defaultValues );
 
 		this.setupShaders();
@@ -56,7 +58,7 @@ class InstancedPointsNodeMaterial extends NodeMaterial {
 			//vUv = uv;
 			varying( vec2(), 'vUv' ).assign( uv() ); // @TODO: Analyze other way to do this
 
-			const instancePosition = attribute( 'instancePosition' );
+			const instancePosition = attribute( 'instancePosition' ).xyz;
 
 			// camera space
 			const mvPos = property( 'vec4', 'mvPos' );
@@ -70,7 +72,9 @@ class InstancedPointsNodeMaterial extends NodeMaterial {
 			// offset in ndc space
 			const offset = property( 'vec2', 'offset' );
 			offset.assign( positionGeometry.xy );
-			offset.assign( offset.mul( materialPointWidth ) );
+
+			offset.mulAssign( this.pointWidthNode ? this.pointWidthNode : materialPointWidth );
+
 			offset.assign( offset.div( viewport.z ) );
 			offset.y.assign( offset.y.mul( aspect ) );
 

粤ICP备19079148号