Browse Source

NodeMaterialObserver: Add checking the lights (#31440)

* Revert "LightsNode: Honor map version in cache key. (#31396)"

This reverts commit 2f1c6c03e6b4a1bd8c08fa44ba6baf8f60c6809d.

* add lights check

* add stats
sunag 11 months ago
parent
commit
8a318e456d

+ 11 - 0
examples/webgpu_lights_projector.html

@@ -33,6 +33,8 @@
 			import * as THREE from 'three';
 			import { Fn, color, mx_worley_noise_float, time } from 'three/tsl';
 
+			import Stats from 'three/addons/libs/stats.module.js';
+
 			import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
 
 			import { PLYLoader } from 'three/addons/loaders/PLYLoader.js';
@@ -42,10 +44,17 @@
 
 			let projectorLight, lightHelper;
 
+			let stats;
+
 			init();
 
 			function init() {
 
+				// Stats
+
+				stats = new Stats();
+				document.body.appendChild( stats.dom );
+
 				// Renderer
 
 				renderer = new THREE.WebGPURenderer( { antialias: true } );
@@ -281,6 +290,8 @@
 
 				const time = performance.now() / 3000;
 
+				stats.update();
+
 				projectorLight.position.x = Math.cos( time ) * 2.5;
 				projectorLight.position.z = Math.sin( time ) * 2.5;
 

+ 87 - 2
src/materials/nodes/manager/NodeMaterialObserver.js

@@ -55,6 +55,16 @@ const refreshUniforms = [
 	'transmissionMap'
 ];
 
+
+/**
+ * A WeakMap to cache lights data for node materials.
+ * Cache lights data by render ID to avoid unnecessary recalculations.
+ *
+ * @private
+ * @type {WeakMap<LightsNode,Object>}
+ */
+const _lightsCache = new WeakMap();
+
 /**
  * This class is used by {@link WebGPURenderer} as management component.
  * It's primary purpose is to determine whether render objects require a
@@ -196,6 +206,8 @@ class NodeMaterialObserver {
 
 			}
 
+			data.lights = this.getLightsData( renderObject.lightsNode.getLights() );
+
 			this.renderObjects.set( renderObject, data );
 
 		}
@@ -299,9 +311,10 @@ class NodeMaterialObserver {
 	 * Returns `true` if the given render object has not changed its state.
 	 *
 	 * @param {RenderObject} renderObject - The render object.
+	 * @param {Array<Light>} lightsData - The current material lights.
 	 * @return {boolean} Whether the given render object has changed its state or not.
 	 */
-	equals( renderObject ) {
+	equals( renderObject, lightsData ) {
 
 		const { object, material, geometry } = renderObject;
 
@@ -462,6 +475,22 @@ class NodeMaterialObserver {
 
 		}
 
+		// lights
+
+		if ( renderObjectData.lights ) {
+
+			for ( let i = 0; i < lightsData.length; i ++ ) {
+
+				if ( renderObjectData.lights[ i ].map !== lightsData[ i ].map ) {
+
+					return false;
+
+				}
+
+			}
+
+		}
+
 		// center
 
 		if ( renderObjectData.center ) {
@@ -488,6 +517,61 @@ class NodeMaterialObserver {
 
 	}
 
+	/**
+	 * Returns the lights data for the given material lights.
+	 *
+	 * @param {Array<Light>} materialLights - The material lights.
+	 * @return {Array<Object>} The lights data for the given material lights.
+	 */
+	getLightsData( materialLights ) {
+
+		const lights = [];
+
+		for ( const light of materialLights ) {
+
+			if ( light.isSpotLight === true && light.map !== null ) {
+
+				// only add lights that have a map
+
+				lights.push( { map: light.map.version } );
+
+			}
+
+		}
+
+		return lights;
+
+	}
+
+	/**
+	 * Returns the lights for the given lights node and render ID.
+	 *
+	 * @param {LightsNode} lightsNode - The lights node.
+	 * @param {number} renderId - The render ID.
+	 * @return {Array} The lights for the given lights node and render ID.
+	 */
+	getLights( lightsNode, renderId ) {
+
+		if ( _lightsCache.has( lightsNode ) ) {
+
+			const cached = _lightsCache.get( lightsNode );
+
+			if ( cached.renderId === renderId ) {
+
+				return cached.lightsData;
+
+			}
+
+		}
+
+		const lightsData = this.getLightsData( lightsNode.getLights() );
+
+		_lightsCache.set( lightsNode, { renderId, lightsData } );
+
+		return lightsData;
+
+	}
+
 	/**
 	 * Checks if the given render object requires a refresh.
 	 *
@@ -516,7 +600,8 @@ class NodeMaterialObserver {
 		if ( isStatic || isBundle )
 			return false;
 
-		const notEqual = this.equals( renderObject ) !== true;
+		const lightsData = this.getLights( renderObject.lightsNode, renderId );
+		const notEqual = this.equals( renderObject, lightsData ) !== true;
 
 		return notEqual;
 

+ 1 - 2
src/nodes/lighting/LightsNode.js

@@ -127,10 +127,9 @@ class LightsNode extends Node {
 			if ( light.isSpotLight === true ) {
 
 				const hashMap = ( light.map !== null ) ? light.map.id : - 1;
-				const hashMapVersion = ( light.map !== null ) ? light.map.version : - 1;
 				const hashColorNode = ( light.colorNode ) ? light.colorNode.getCacheKey() : - 1;
 
-				_hashData.push( hashMap, hashMapVersion, hashColorNode );
+				_hashData.push( hashMap, hashColorNode );
 
 			}
 

粤ICP备19079148号