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