浏览代码

Nodes & WebGPURenderer: RangeNode (#24240)

* Move render object dependencies to renderObject() like WebGLRenderer

* add RangeNode

* update webgpu examples
sunag 3 年之前
父节点
当前提交
4224d836ea

+ 11 - 2
examples/jsm/nodes/Nodes.js

@@ -45,6 +45,9 @@ import TextureNode from './accessors/TextureNode.js';
 import UVNode from './accessors/UVNode.js';
 import UserDataNode from './accessors/UserDataNode.js';
 
+// geometry
+import RangeNode from './geometry/RangeNode.js';
+
 // gpgpu
 import ComputeNode from './gpgpu/ComputeNode.js';
 
@@ -130,7 +133,10 @@ const nodeLib = {
 	VarNode,
 	VaryNode,
 
-	// compute
+	// geometry
+	RangeNode,
+
+	// gpgpu
 	ComputeNode,
 
 	// accessors
@@ -234,7 +240,10 @@ export {
 	VarNode,
 	VaryNode,
 
-	// compute
+	// geometry
+	RangeNode,
+
+	// gpgpu
 	ComputeNode,
 
 	// accessors

+ 101 - 0
examples/jsm/nodes/geometry/RangeNode.js

@@ -0,0 +1,101 @@
+import Node from '../core/Node.js';
+import { attribute, float } from '../shadernode/ShaderNodeBaseElements.js';
+import { MathUtils, InstancedBufferAttribute } from 'three';
+
+class RangeNode extends Node {
+
+	constructor( min, max ) {
+
+		super();
+
+		this.min = min;
+		this.max = max;
+
+	}
+
+	getVectorLength() {
+
+		const min = this.min;
+
+		let length = 1;
+
+		if ( min.isVector2 ) length = 2;
+		else if ( min.isVector3 ) length = 3;
+		else if ( min.isVector4 ) length = 4;
+		else if ( min.isColor ) length = 3;
+
+		return length;
+
+	}
+
+	getNodeType( builder ) {
+
+		return ( builder.object.isInstancedMesh === true ) ? builder.getTypeFromLength( this.getVectorLength() ) : 'float';
+
+	}
+
+	construct( builder ) {
+
+		const { min, max } = this;
+		const { object, geometry } = builder;
+
+		const vectorLength = this.getVectorLength();
+		const attributeName = 'node' + this.id;
+
+		let output = null;
+
+		if ( object.isInstancedMesh === true ) {
+
+			const length = vectorLength * object.count;
+			const array = new Float32Array( length );
+
+			if ( vectorLength === 1 ) {
+
+				for ( let i = 0; i < length; i ++ ) {
+
+					array[ i ] = MathUtils.lerp( min, max, Math.random() );
+
+				}
+
+			} else if ( min.isColor ) {
+
+				for ( let i = 0; i < length; i += 3 ) {
+
+					array[ i ] = MathUtils.lerp( min.r, max.r, Math.random() );
+					array[ i + 1 ] = MathUtils.lerp( min.g, max.g, Math.random() );
+					array[ i + 2 ] = MathUtils.lerp( min.b, max.b, Math.random() );
+
+				}
+
+			} else {
+
+				for ( let i = 0; i < length; i ++ ) {
+
+					const index = i % vectorLength;
+
+					const minValue = min.getComponent( index );
+					const maxValue = max.getComponent( index );
+
+					array[ i ] = MathUtils.lerp( minValue, maxValue, Math.random() );
+
+				}
+
+			}
+
+			geometry.setAttribute( attributeName, new InstancedBufferAttribute( array, vectorLength ) );
+
+			output = attribute( attributeName, builder.getTypeFromLength( vectorLength ) );
+
+		} else {
+
+			output = float( 0 );
+
+		}
+
+		return output;
+
+	}
+
+}
+
+export default RangeNode;

+ 7 - 0
examples/jsm/nodes/shadernode/ShaderNodeElements.js

@@ -22,6 +22,9 @@ import OscNode from '../utils/OscNode.js';
 import SpriteSheetUVNode from '../utils/SpriteSheetUVNode.js';
 import TimerNode from '../utils/TimerNode.js';
 
+// geometry
+import RangeNode from '../geometry/RangeNode.js';
+
 // procedural
 import CheckerNode from '../procedural/CheckerNode.js';
 
@@ -101,6 +104,10 @@ export const timerLocal = ( timeScale ) => nodeObject( new TimerNode( TimerNode.
 export const timerGlobal = ( timeScale ) => nodeObject( new TimerNode( TimerNode.GLOBAL, timeScale ) );
 export const timerDelta = ( timeScale ) => nodeObject( new TimerNode( TimerNode.DELTA, timeScale ) );
 
+// geometry
+
+export const range = ( min, max ) => nodeObject( new RangeNode( min, max ) );
+
 // procedural
 
 export const checker = nodeProxy( CheckerNode );

+ 23 - 22
examples/jsm/renderers/webgpu/WebGPURenderer.js

@@ -770,20 +770,6 @@ class WebGPURenderer {
 
 			const { object, geometry, material, group } = renderItem;
 
-			object.onBeforeRender( this, scene, camera, geometry, material, group );
-
-			object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld );
-			object.normalMatrix.getNormalMatrix( object.modelViewMatrix );
-
-			this._objects.update( object );
-
-			// send scene properties to object
-
-			const objectProperties = this._properties.get( object );
-
-			objectProperties.lightsNode = lightsNode;
-			objectProperties.scene = scene;
-
 			if ( camera.isArrayCamera ) {
 
 				const cameras = camera.cameras;
@@ -800,9 +786,7 @@ class WebGPURenderer {
 
 						passEncoder.setViewport( vp.x, vp.y, vp.width, vp.height, minDepth, maxDepth );
 
-						this._nodes.update( object, camera2 );
-						this._bindings.update( object );
-						this._renderObject( object, passEncoder );
+						this._renderObject( object, scene, camera2, geometry, material, group, lightsNode, passEncoder );
 
 					}
 
@@ -810,9 +794,7 @@ class WebGPURenderer {
 
 			} else {
 
-				this._nodes.update( object, camera );
-				this._bindings.update( object );
-				this._renderObject( object, passEncoder );
+				this._renderObject( object, scene, camera, geometry, material, group, lightsNode, passEncoder );
 
 			}
 
@@ -820,10 +802,30 @@ class WebGPURenderer {
 
 	}
 
-	_renderObject( object, passEncoder ) {
+	_renderObject( object, scene, camera, geometry, material, group, lightsNode, passEncoder ) {
 
 		const info = this._info;
 
+		// send scene properties to object
+
+		const objectProperties = this._properties.get( object );
+
+		objectProperties.lightsNode = lightsNode;
+		objectProperties.scene = scene;
+
+		//
+
+		object.onBeforeRender( this, scene, camera, geometry, material, group );
+
+		object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld );
+		object.normalMatrix.getNormalMatrix( object.modelViewMatrix );
+
+		// updates
+
+		this._nodes.update( object, camera );
+		this._bindings.update( object );
+		this._objects.update( object );
+
 		// pipeline
 
 		const renderPipeline = this._renderPipelines.get( object );
@@ -836,7 +838,6 @@ class WebGPURenderer {
 
 		// index
 
-		const geometry = object.geometry;
 		const index = geometry.index;
 
 		const hasIndex = ( index !== null );

+ 6 - 2
examples/webgpu_instance_mesh.html

@@ -30,7 +30,7 @@
 			import Stats from './jsm/libs/stats.module.js';
 			import { GUI } from './jsm/libs/lil-gui.module.min.js';
 
-			import { normalWorld } from 'three-nodes/Nodes.js';
+			import { mix, range, normalWorld, oscSine, timerLocal } from 'three-nodes/Nodes.js';
 
 			import WebGPU from './jsm/capabilities/WebGPU.js';
 			import WebGPURenderer from './jsm/renderers/webgpu/WebGPURenderer.js';
@@ -61,7 +61,11 @@
 				scene = new THREE.Scene();
 
 				const material = new THREE.MeshBasicMaterial();
-				material.colorNode = normalWorld;
+
+				// random colors between instances from 0x000000 to 0xFFFFFF
+				const randomColors = range( new THREE.Color( 0x000000 ), new THREE.Color( 0xFFFFFF ) );
+
+				material.colorNode = mix( normalWorld, randomColors, oscSine( timerLocal( .1 ) ) );
 
 				const loader = new THREE.BufferGeometryLoader();
 				loader.load( 'models/json/suzanne_buffergeometry.json', function ( geometry ) {

+ 10 - 0
examples/webgpu_skinning_instancing.html

@@ -28,6 +28,8 @@
 			import * as THREE from 'three';
 			import * as Nodes from 'three-nodes/Nodes.js';
 
+			import { mix, range, color, oscSine, timerLocal } from 'three-nodes/Nodes.js';
+
 			import { FBXLoader } from './jsm/loaders/FBXLoader.js';
 
 			import WebGPU from './jsm/capabilities/WebGPU.js';
@@ -83,8 +85,16 @@
 
 						if ( child.isMesh ) {
 
+							// random colors between instances from 0x000000 to 0xFFFFFF
+							const randomColors = range( new THREE.Color( 0x000000 ), new THREE.Color( 0xFFFFFF ) );
+
+							// random [ 0, 1 ] values between instances
+							const randomMetalness = range( 0, 1 );
+
 							child.material = new Nodes.MeshStandardNodeMaterial();
 							child.material.roughness = .1;
+							child.material.metalnessNode = randomMetalness;
+							child.material.colorNode =  mix( color( 0xFFFFFF ), randomColors, oscSine( timerLocal( .1 ) ) );
 
 							child.isInstancedMesh = true;
 							child.instanceMatrix = new THREE.InstancedBufferAttribute( new Float32Array( instanceCount * 16 ), 16 );