|
|
@@ -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;
|
|
|
|