Sfoglia il codice sorgente

NodeMaterialObserver: Speed up material comparisons. (#33198)

Michael Herzog 1 mese fa
parent
commit
a7495fd758
1 ha cambiato i file con 79 aggiunte e 42 eliminazioni
  1. 79 42
      src/materials/nodes/manager/NodeMaterialObserver.js

+ 79 - 42
src/materials/nodes/manager/NodeMaterialObserver.js

@@ -65,6 +65,14 @@ const refreshUniforms = [
  */
 const _lightsCache = new WeakMap();
 
+/**
+ * Holds the material data for comparison.
+ *
+ * @private
+ * @type {WeakMap<Material,Object>}
+ */
+const _materialCache = new WeakMap();
+
 /**
  * This class is used by {@link WebGPURenderer} as management component.
  * It's primary purpose is to determine whether render objects require a
@@ -166,10 +174,9 @@ class NodeMaterialObserver {
 
 		if ( data === undefined ) {
 
-			const { geometry, material, object } = renderObject;
+			const { geometry, object } = renderObject;
 
 			data = {
-				material: this.getMaterialData( material ),
 				geometry: {
 					id: geometry.id,
 					attributes: this.getAttributesData( geometry.attributes ),
@@ -198,7 +205,7 @@ class NodeMaterialObserver {
 
 			}
 
-			if ( data.material.transmission > 0 ) {
+			if ( renderObject.material.transmission > 0 ) {
 
 				const { width, height } = renderObject.context;
 
@@ -277,32 +284,40 @@ class NodeMaterialObserver {
 	 */
 	getMaterialData( material ) {
 
-		const data = {};
+		let data = _materialCache.get( material );
 
-		for ( const property of this.refreshUniforms ) {
+		if ( data === undefined ) {
 
-			const value = material[ property ];
+			data = { _renderId: - 1, _equal: false };
 
-			if ( value === null || value === undefined ) continue;
+			for ( const property of this.refreshUniforms ) {
 
-			if ( typeof value === 'object' && value.clone !== undefined ) {
+				const value = material[ property ];
 
-				if ( value.isTexture === true ) {
+				if ( value === null || value === undefined ) continue;
 
-					data[ property ] = { id: value.id, version: value.version };
+				if ( typeof value === 'object' && value.clone !== undefined ) {
 
-				} else {
+					if ( value.isTexture === true ) {
 
-					data[ property ] = value.clone();
+						data[ property ] = { id: value.id, version: value.version };
 
-				}
+					} else {
 
-			} else {
+						data[ property ] = value.clone();
 
-				data[ property ] = value;
+					}
+
+				} else {
+
+					data[ property ] = value;
+
+				}
 
 			}
 
+			_materialCache.set( material, data );
+
 		}
 
 		return data;
@@ -314,9 +329,10 @@ class NodeMaterialObserver {
 	 *
 	 * @param {RenderObject} renderObject - The render object.
 	 * @param {Array<Light>} lightsData - The current material lights.
+	 * @param {number} renderId - The current render ID.
 	 * @return {boolean} Whether the given render object has changed its state or not.
 	 */
-	equals( renderObject, lightsData ) {
+	equals( renderObject, lightsData, renderId ) {
 
 		const { object, material, geometry } = renderObject;
 
@@ -334,57 +350,78 @@ class NodeMaterialObserver {
 
 		// material
 
-		const materialData = renderObjectData.material;
+		const materialData = this.getMaterialData( renderObject.material );
 
-		for ( const property in materialData ) {
+		// check the material for the "equal" state just once per render for all render objects
 
-			const value = materialData[ property ];
-			const mtlValue = material[ property ];
+		if ( materialData._renderId !== renderId ) {
 
-			if ( value.equals !== undefined ) {
+			materialData._renderId = renderId;
 
-				if ( value.equals( mtlValue ) === false ) {
+			for ( const property in materialData ) {
 
-					value.copy( mtlValue );
+				const value = materialData[ property ];
+				const mtlValue = material[ property ];
 
-					return false;
+				if ( property === '_renderId' ) continue;
+				if ( property === '_equal' ) continue;
 
-				}
+				if ( value.equals !== undefined ) {
 
-			} else if ( mtlValue.isTexture === true ) {
+					if ( value.equals( mtlValue ) === false ) {
 
-				if ( value.id !== mtlValue.id || value.version !== mtlValue.version ) {
+						value.copy( mtlValue );
 
-					value.id = mtlValue.id;
-					value.version = mtlValue.version;
+						materialData._equal = false;
+						return false;
 
-					return false;
+					}
 
-				}
+				} else if ( mtlValue.isTexture === true ) {
 
-			} else if ( value !== mtlValue ) {
+					if ( value.id !== mtlValue.id || value.version !== mtlValue.version ) {
 
-				materialData[ property ] = mtlValue;
+						value.id = mtlValue.id;
+						value.version = mtlValue.version;
 
-				return false;
+						materialData._equal = false;
+						return false;
+
+					}
+
+				} else if ( value !== mtlValue ) {
+
+					materialData[ property ] = mtlValue;
+
+					materialData._equal = false;
+					return false;
+
+				}
 
 			}
 
-		}
+			if ( materialData.transmission > 0 ) {
 
-		if ( materialData.transmission > 0 ) {
+				const { width, height } = renderObject.context;
 
-			const { width, height } = renderObject.context;
+				if ( renderObjectData.bufferWidth !== width || renderObjectData.bufferHeight !== height ) {
 
-			if ( renderObjectData.bufferWidth !== width || renderObjectData.bufferHeight !== height ) {
+					renderObjectData.bufferWidth = width;
+					renderObjectData.bufferHeight = height;
 
-				renderObjectData.bufferWidth = width;
-				renderObjectData.bufferHeight = height;
+					materialData._equal = false;
+					return false;
 
-				return false;
+				}
 
 			}
 
+			materialData._equal = true;
+
+		} else {
+
+			if ( materialData._equal === false ) return false;
+
 		}
 
 		// geometry
@@ -612,7 +649,7 @@ class NodeMaterialObserver {
 			return false;
 
 		const lightsData = this.getLights( renderObject.lightsNode, renderId );
-		const notEqual = this.equals( renderObject, lightsData ) !== true;
+		const notEqual = this.equals( renderObject, lightsData, renderId ) !== true;
 
 		return notEqual;
 

粤ICP备19079148号