@@ -55,6 +55,16 @@ const refreshUniforms = [
55
55
'transmissionMap'
56
56
] ;
57
57
58
+
59
+ /**
60
+ * A WeakMap to cache lights data for node materials.
61
+ * Cache lights data by render ID to avoid unnecessary recalculations.
62
+ *
63
+ * @private
64
+ * @type {WeakMap<LightsNode,Object> }
65
+ */
66
+ const _lightsCache = new WeakMap ( ) ;
67
+
58
68
/**
59
69
* This class is used by {@link WebGPURenderer} as management component.
60
70
* It's primary purpose is to determine whether render objects require a
@@ -196,6 +206,8 @@ class NodeMaterialObserver {
196
206
197
207
}
198
208
209
+ data . lights = this . getLightsData ( renderObject . lightsNode . getLights ( ) ) ;
210
+
199
211
this . renderObjects . set ( renderObject , data ) ;
200
212
201
213
}
@@ -299,9 +311,10 @@ class NodeMaterialObserver {
299
311
* Returns `true` if the given render object has not changed its state.
300
312
*
301
313
* @param {RenderObject } renderObject - The render object.
314
+ * @param {Array<Light> } lightsData - The current material lights.
302
315
* @return {boolean } Whether the given render object has changed its state or not.
303
316
*/
304
- equals ( renderObject ) {
317
+ equals ( renderObject , lightsData ) {
305
318
306
319
const { object, material, geometry } = renderObject ;
307
320
@@ -462,6 +475,22 @@ class NodeMaterialObserver {
462
475
463
476
}
464
477
478
+ // lights
479
+
480
+ if ( renderObjectData . lights ) {
481
+
482
+ for ( let i = 0 ; i < lightsData . length ; i ++ ) {
483
+
484
+ if ( renderObjectData . lights [ i ] . map !== lightsData [ i ] . map ) {
485
+
486
+ return false ;
487
+
488
+ }
489
+
490
+ }
491
+
492
+ }
493
+
465
494
// center
466
495
467
496
if ( renderObjectData . center ) {
@@ -488,6 +517,61 @@ class NodeMaterialObserver {
488
517
489
518
}
490
519
520
+ /**
521
+ * Returns the lights data for the given material lights.
522
+ *
523
+ * @param {Array<Light> } materialLights - The material lights.
524
+ * @return {Array<Object> } The lights data for the given material lights.
525
+ */
526
+ getLightsData ( materialLights ) {
527
+
528
+ const lights = [ ] ;
529
+
530
+ for ( const light of materialLights ) {
531
+
532
+ if ( light . isSpotLight === true && light . map !== null ) {
533
+
534
+ // only add lights that have a map
535
+
536
+ lights . push ( { map : light . map . version } ) ;
537
+
538
+ }
539
+
540
+ }
541
+
542
+ return lights ;
543
+
544
+ }
545
+
546
+ /**
547
+ * Returns the lights for the given lights node and render ID.
548
+ *
549
+ * @param {LightsNode } lightsNode - The lights node.
550
+ * @param {number } renderId - The render ID.
551
+ * @return {Array } The lights for the given lights node and render ID.
552
+ */
553
+ getLights ( lightsNode , renderId ) {
554
+
555
+ if ( _lightsCache . has ( lightsNode ) ) {
556
+
557
+ const cached = _lightsCache . get ( lightsNode ) ;
558
+
559
+ if ( cached . renderId === renderId ) {
560
+
561
+ return cached . lightsData ;
562
+
563
+ }
564
+
565
+ }
566
+
567
+ const lightsData = this . getLightsData ( lightsNode . getLights ( ) ) ;
568
+
569
+ _lightsCache . set ( lightsNode , { renderId, lightsData } ) ;
570
+
571
+ return lightsData ;
572
+
573
+ }
574
+
491
575
/**
492
576
* Checks if the given render object requires a refresh.
493
577
*
@@ -516,7 +600,8 @@ class NodeMaterialObserver {
516
600
if ( isStatic || isBundle )
517
601
return false ;
518
602
519
- const notEqual = this . equals ( renderObject ) !== true ;
603
+ const lightsData = this . getLights ( renderObject . lightsNode , renderId ) ;
604
+ const notEqual = this . equals ( renderObject , lightsData ) !== true ;
520
605
521
606
return notEqual ;
522
607
0 commit comments