rayzee 5.4.1 → 5.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,9 +9,16 @@
9
9
 
10
10
  import { StorageInstancedBufferAttribute } from 'three/webgpu';
11
11
  import { storage } from 'three/tsl';
12
- import { TEXTURE_CONSTANTS, MATERIAL_DATA_LAYOUT as M } from '../EngineDefaults.js';
12
+ import { MATERIAL_DATA_LAYOUT as M, TRIANGLE_DATA_LAYOUT as T } from '../EngineDefaults.js';
13
13
 
14
14
  const PIXELS_PER_MATERIAL = M.SLOTS_PER_MATERIAL;
15
+ // Per-triangle float offsets used by _patchTriangleSideForMaterial / _patchTriangleBlockerForMaterial.
16
+ const TRI_MAT_IDX_OFFSET = T.UV_C_MAT_OFFSET + 2; // uvData2.z in shader
17
+ const TRI_SIDE_OFFSET = T.NORMAL_C_OFFSET + 3; // normalCData.w in shader
18
+ const TRI_BLOCKER_OFFSET = T.NORMAL_A_OFFSET + 3; // nA.w in shader (opaque-blocker fast path)
19
+
20
+ // Material properties that affect the shadow-ray opaque-blocker flag.
21
+ const BLOCKER_PROPS = new Set( [ 'transmission', 'transparent', 'opacity', 'alphaMode' ] );
15
22
 
16
23
  export class MaterialDataManager {
17
24
 
@@ -41,7 +48,7 @@ export class MaterialDataManager {
41
48
 
42
49
  /**
43
50
  * Optional callbacks set by the owning stage.
44
- * @type {{ onReset?: Function, onFeaturesChanged?: Function }}
51
+ * @type {{ onReset?: Function, onFeaturesChanged?: Function, getTriangleData?: Function, onTriangleDataChanged?: Function }}
45
52
  */
46
53
  this.callbacks = {};
47
54
 
@@ -275,7 +282,11 @@ export class MaterialDataManager {
275
282
  case 'clearcoat': data[ stride + M.CLEARCOAT ] = value; break;
276
283
  case 'clearcoatRoughness': data[ stride + M.CLEARCOAT_ROUGHNESS ] = value; break;
277
284
  case 'opacity': data[ stride + M.OPACITY ] = value; break;
278
- case 'side': data[ stride + M.SIDE ] = value; break;
285
+ case 'side': data[ stride + M.SIDE ] = value;
286
+ // Side is also mirrored into per-triangle data (NORMAL_C.w) so BVH
287
+ // traversal can do side culling without reading the material buffer.
288
+ this._patchTriangleSideForMaterial( materialIndex, value );
289
+ break;
279
290
  case 'transparent': data[ stride + M.TRANSPARENT ] = value; break;
280
291
  case 'alphaTest': data[ stride + M.ALPHA_TEST ] = value; break;
281
292
  case 'alphaMode': data[ stride + M.ALPHA_MODE ] = value; break;
@@ -304,6 +315,13 @@ export class MaterialDataManager {
304
315
 
305
316
  this.materialStorageAttr.needsUpdate = true;
306
317
 
318
+ // Recompute triangle-data opaque-blocker flag when any input to it changes.
319
+ if ( BLOCKER_PROPS.has( property ) ) {
320
+
321
+ this._recomputeOpaqueBlockerForMaterial( materialIndex );
322
+
323
+ }
324
+
307
325
  const featureProperties = [ 'transmission', 'clearcoat', 'sheen', 'iridescence', 'dispersion', 'transparent', 'opacity', 'alphaTest' ];
308
326
  if ( featureProperties.includes( property ) ) {
309
327
 
@@ -414,6 +432,10 @@ export class MaterialDataManager {
414
432
  data[ stride + M.CLEARCOAT_ROUGHNESS ] = materialData.clearcoatRoughness ?? 0;
415
433
  data[ stride + M.OPACITY ] = materialData.opacity ?? 1;
416
434
  data[ stride + M.SIDE ] = materialData.side ?? 0;
435
+ // Mirror side into per-triangle data so BVH traversal avoids a material-buffer read.
436
+ this._patchTriangleSideForMaterial( materialIndex, materialData.side ?? 0 );
437
+ // Recompute shadow-ray opaque-blocker flag (reads alphaMode/transparent/transmission/opacity from buffer).
438
+ this._recomputeOpaqueBlockerForMaterial( materialIndex );
417
439
  data[ stride + M.TRANSPARENT ] = materialData.transparent ?? 0;
418
440
  data[ stride + M.ALPHA_TEST ] = materialData.alphaTest ?? 0;
419
441
  data[ stride + M.ALPHA_MODE ] = materialData.alphaMode ?? 0;
@@ -657,6 +679,74 @@ export class MaterialDataManager {
657
679
 
658
680
  }
659
681
 
682
+ /**
683
+ * Rewrite the per-triangle `side` flag (NORMAL_C.w) for every triangle whose
684
+ * materialIndex matches. Linear over triangles because there's no reverse
685
+ * index — side edits are a rare UI action so the scan cost is acceptable.
686
+ * @private
687
+ */
688
+ /**
689
+ * Re-derive the shadow-ray opaque-blocker flag for a material from its
690
+ * current buffer values and patch NORMAL_A.w on every matching triangle.
691
+ * Kept in sync with the blocker definition in GeometryExtractor.
692
+ * @private
693
+ */
694
+ _recomputeOpaqueBlockerForMaterial( materialIndex ) {
695
+
696
+ const matBuf = this.materialStorageAttr?.array;
697
+ if ( ! matBuf ) return;
698
+
699
+ const matStride = materialIndex * M.FLOATS_PER_MATERIAL;
700
+ const alphaMode = matBuf[ matStride + M.ALPHA_MODE ] | 0;
701
+ const transparent = matBuf[ matStride + M.TRANSPARENT ] | 0;
702
+ const transmission = matBuf[ matStride + M.TRANSMISSION ] || 0;
703
+ const opacity = matBuf[ matStride + M.OPACITY ] ?? 1;
704
+ const isOpaqueBlocker = ( alphaMode === 0 && transparent === 0 && transmission === 0 && opacity >= 1 ) ? 1.0 : 0.0;
705
+
706
+ this._patchTriangleFlagForMaterial( materialIndex, TRI_BLOCKER_OFFSET, isOpaqueBlocker );
707
+
708
+ }
709
+
710
+ /**
711
+ * Generic helper: patch a single per-triangle float at `triOffset` for every
712
+ * triangle whose materialIndex matches, then fire onTriangleDataChanged.
713
+ * @private
714
+ */
715
+ _patchTriangleFlagForMaterial( materialIndex, triOffset, value ) {
716
+
717
+ const triInfo = this.callbacks.getTriangleData?.();
718
+ const triData = triInfo?.array;
719
+ const triCount = triInfo?.count | 0;
720
+ if ( ! triData || triCount === 0 ) return;
721
+
722
+ const stride = T.FLOATS_PER_TRIANGLE;
723
+ let patched = 0;
724
+ for ( let i = 0; i < triCount; i ++ ) {
725
+
726
+ const base = i * stride;
727
+ if ( triData[ base + TRI_MAT_IDX_OFFSET ] === materialIndex ) {
728
+
729
+ triData[ base + triOffset ] = value;
730
+ patched ++;
731
+
732
+ }
733
+
734
+ }
735
+
736
+ if ( patched > 0 && this.callbacks.onTriangleDataChanged ) {
737
+
738
+ this.callbacks.onTriangleDataChanged();
739
+
740
+ }
741
+
742
+ }
743
+
744
+ _patchTriangleSideForMaterial( materialIndex, sideValue ) {
745
+
746
+ this._patchTriangleFlagForMaterial( materialIndex, TRI_SIDE_OFFSET, sideValue );
747
+
748
+ }
749
+
660
750
  // ===== DISPOSAL =====
661
751
 
662
752
  dispose() {