@@ -99,6 +99,14 @@ const _materialCache = new WeakMap();
9999 */
100100const _geometryCache = new WeakMap ( ) ;
101101
102+ /**
103+ * Holds the texture data for comparison.
104+ *
105+ * @private
106+ * @type {WeakMap<Texture,Object> }
107+ */
108+ const _textureCache = new WeakMap ( ) ;
109+
102110/**
103111 * This class is used by {@link WebGPURenderer} as management component.
104112 * It's primary purpose is to determine whether render objects require a
@@ -355,6 +363,14 @@ class NodeMaterialObserver {
355363 drawRange : { start : geometry . drawRange . start , count : geometry . drawRange . count }
356364 } ;
357365
366+ // force refresh on dispose
367+
368+ geometry . addEventListener ( 'dispose' , ( ) => {
369+
370+ data . _version ++ ;
371+
372+ } ) ;
373+
358374 _geometryCache . set ( geometry , data ) ;
359375
360376 }
@@ -363,6 +379,47 @@ class NodeMaterialObserver {
363379
364380 }
365381
382+ /**
383+ * Returns a texture data structure holding the texture state for
384+ * monitoring.
385+ *
386+ * @param {Texture } texture - The texture.
387+ * @return {Object } An object for monitoring the texture.
388+ */
389+ getTextureData ( texture ) {
390+
391+ let data = _textureCache . get ( texture ) ;
392+
393+ if ( data === undefined ) {
394+
395+ data = { _version : 0 } ;
396+
397+ // force refresh on dispose
398+
399+ const onDispose = ( ) => {
400+
401+ data . _version ++ ;
402+
403+ } ;
404+
405+ if ( texture . renderTarget !== null ) {
406+
407+ texture . renderTarget . addEventListener ( 'dispose' , onDispose ) ;
408+
409+ } else {
410+
411+ texture . addEventListener ( 'dispose' , onDispose ) ;
412+
413+ }
414+
415+ _textureCache . set ( texture , data ) ;
416+
417+ }
418+
419+ return data ;
420+
421+ }
422+
366423 /**
367424 * Returns a material data structure holding the material property values for
368425 * monitoring.
@@ -382,13 +439,17 @@ class NodeMaterialObserver {
382439
383440 const value = material [ property ] ;
384441
385- if ( value === null || value === undefined ) continue ;
442+ if ( value === undefined ) continue ;
443+
444+ if ( value === null ) {
386445
387- if ( typeof value === 'object' && value . clone !== undefined ) {
446+ data [ property ] = null ; // track unset properties
447+
448+ } else if ( typeof value === 'object' && value . clone !== undefined ) {
388449
389450 if ( value . isTexture === true ) {
390451
391- data [ property ] = { id : value . id , version : 0 } ;
452+ data [ property ] = { id : value . id , version : 0 , cacheVersion : this . getTextureData ( value ) . _version } ;
392453
393454 } else {
394455
@@ -456,7 +517,35 @@ class NodeMaterialObserver {
456517 if ( property === '_renderId' ) continue ;
457518 if ( property === '_version' ) continue ;
458519
459- if ( value . equals !== undefined ) {
520+ if ( value === null || mtlValue === null || mtlValue === undefined ) {
521+
522+ // a property was assigned or removed since the last observation so a new snapshot is required
523+
524+ if ( value !== ( mtlValue === undefined ? null : mtlValue ) ) {
525+
526+ if ( mtlValue === null || mtlValue === undefined ) {
527+
528+ materialData [ property ] = null ;
529+
530+ } else if ( mtlValue . isTexture === true ) {
531+
532+ materialData [ property ] = { id : mtlValue . id , version : mtlValue . version , cacheVersion : this . getTextureData ( mtlValue ) . _version } ;
533+
534+ } else if ( typeof mtlValue === 'object' && mtlValue . clone !== undefined ) {
535+
536+ materialData [ property ] = mtlValue . clone ( ) ;
537+
538+ } else {
539+
540+ materialData [ property ] = mtlValue ;
541+
542+ }
543+
544+ changed = true ;
545+
546+ }
547+
548+ } else if ( value . equals !== undefined ) {
460549
461550 if ( value . equals ( mtlValue ) === false ) {
462551
@@ -468,10 +557,13 @@ class NodeMaterialObserver {
468557
469558 } else if ( mtlValue . isTexture === true ) {
470559
471- if ( value . id !== mtlValue . id || value . version !== mtlValue . version ) {
560+ const textureData = this . getTextureData ( mtlValue ) ;
561+
562+ if ( value . id !== mtlValue . id || value . version !== mtlValue . version || value . cacheVersion !== textureData . _version ) {
472563
473564 value . id = mtlValue . id ;
474565 value . version = mtlValue . version ;
566+ value . cacheVersion = textureData . _version ;
475567
476568 changed = true ;
477569
@@ -521,6 +613,8 @@ class NodeMaterialObserver {
521613 if ( renderObjectData . geometryId !== geometry . id ) {
522614
523615 renderObjectData . geometryId = geometry . id ;
616+ renderObjectData . geometryVersion = this . getGeometryData ( geometry ) . _version ;
617+
524618 return false ;
525619
526620 }
@@ -692,7 +786,12 @@ class NodeMaterialObserver {
692786
693787 for ( let i = 0 ; i < lightsData . length ; i ++ ) {
694788
695- if ( renderObjectData . lights [ i ] . map !== lightsData [ i ] . map ) {
789+ const lightData = renderObjectData . lights [ i ] ;
790+
791+ if ( lightData . map !== lightsData [ i ] . map || lightData . cacheVersion !== lightsData [ i ] . cacheVersion ) {
792+
793+ lightData . map = lightsData [ i ] . map ;
794+ lightData . cacheVersion = lightsData [ i ] . cacheVersion ;
696795
697796 return false ;
698797
@@ -762,7 +861,7 @@ class NodeMaterialObserver {
762861
763862 // only add lights that have a map
764863
765- lights . push ( { map : light . map . version } ) ;
864+ lights . push ( { map : light . map . version , cacheVersion : this . getTextureData ( light . map ) . _version } ) ;
766865
767866 }
768867
0 commit comments