rayzee 7.26.3 → 7.26.4

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rayzee",
3
- "version": "7.26.3",
3
+ "version": "7.26.4",
4
4
  "type": "module",
5
5
  "description": "Real-time WebGPU path tracing engine built on Three.js",
6
6
  "main": "dist/rayzee.umd.js",
@@ -6,6 +6,53 @@ const log = createLogger( 'geometry' );
6
6
 
7
7
  const MAX_TEXTURES_LIMIT = 128;
8
8
 
9
+ /**
10
+ * glTF 2.0 alphaMode for a three.js material: 0 OPAQUE, 1 MASK, 2 BLEND.
11
+ *
12
+ * The single definition of this rule. alphaMode is the only alpha field the shader reads
13
+ * (MaterialTransmission takes the opaque fast path on 0 and gates its MASK branch on 1), so
14
+ * any control that changes alpha behaviour has to route through here or it does nothing.
15
+ *
16
+ * @param {import('three').Material} material
17
+ * @returns {0|1|2}
18
+ */
19
+ export function deriveAlphaMode( material ) {
20
+
21
+ // Follow glTF 2.0 specification for alphaMode
22
+ // Check if material explicitly sets alphaMode (from glTF loader)
23
+ if ( material.userData?.gltfExtensions?.KHR_materials_unlit?.alphaMode ) {
24
+
25
+ const mode = material.userData.gltfExtensions.KHR_materials_unlit.alphaMode;
26
+ if ( mode === 'BLEND' ) return 2;
27
+ if ( mode === 'MASK' ) return 1;
28
+ return 0; // OPAQUE
29
+
30
+ }
31
+
32
+ // Fallback logic based on material properties
33
+ if ( material.alphaTest > 0.0 ) {
34
+
35
+ return 1; // MASK - alphaTest takes priority
36
+
37
+ }
38
+
39
+ if ( material.transparent && material.opacity < 1.0 ) {
40
+
41
+ return 2; // BLEND - transparent with opacity < 1
42
+
43
+ }
44
+
45
+ // Check for alpha in diffuse texture
46
+ if ( material.map && material.map.format === RGBAFormat && material.transparent ) {
47
+
48
+ return 2; // BLEND - has alpha texture and transparent flag
49
+
50
+ }
51
+
52
+ return 0; // OPAQUE
53
+
54
+ }
55
+
9
56
  export class GeometryExtractor {
10
57
 
11
58
  constructor() {
@@ -189,42 +236,6 @@ export class GeometryExtractor {
189
236
 
190
237
  }
191
238
 
192
- getMaterialAlphaMode( material ) {
193
-
194
- // Follow glTF 2.0 specification for alphaMode
195
- // Check if material explicitly sets alphaMode (from glTF loader)
196
- if ( material.userData?.gltfExtensions?.KHR_materials_unlit?.alphaMode ) {
197
-
198
- const mode = material.userData.gltfExtensions.KHR_materials_unlit.alphaMode;
199
- if ( mode === 'BLEND' ) return 2;
200
- if ( mode === 'MASK' ) return 1;
201
- return 0; // OPAQUE
202
-
203
- }
204
-
205
- // Fallback logic based on material properties
206
- if ( material.alphaTest > 0.0 ) {
207
-
208
- return 1; // MASK - alphaTest takes priority
209
-
210
- }
211
-
212
- if ( material.transparent && material.opacity < 1.0 ) {
213
-
214
- return 2; // BLEND - transparent with opacity < 1
215
-
216
- }
217
-
218
- // Check for alpha in diffuse texture
219
- if ( material.map && material.map.format === RGBAFormat && material.transparent ) {
220
-
221
- return 2; // BLEND - has alpha texture and transparent flag
222
-
223
- }
224
-
225
- return 0; // OPAQUE
226
-
227
- }
228
239
 
229
240
  getMaterialType( material ) {
230
241
 
@@ -424,7 +435,7 @@ export class GeometryExtractor {
424
435
  // Transparency and alpha
425
436
  transparent: material.transparent ? 1 : 0,
426
437
  alphaTest: material.alphaTest ?? defaults.alphaTest,
427
- alphaMode: this.getMaterialAlphaMode( material ),
438
+ alphaMode: deriveAlphaMode( material ),
428
439
 
429
440
  // Rendering properties
430
441
  side: this.getMaterialSide( material ),
package/src/index.js CHANGED
@@ -17,6 +17,9 @@ export { EngineEvents } from './EngineEvents.js';
17
17
  // Asset URL / cache namespace overrides (call before constructing PathTracerApp)
18
18
  export { configureAssets, getAssetConfig } from './AssetConfig.js';
19
19
 
20
+ // glTF alphaMode derivation — the one definition, shared with hosts that edit materials
21
+ export { deriveAlphaMode } from './Processor/GeometryExtractor.js';
22
+
20
23
  // Scene-level authoring metadata embedded in model files (glTF `extras`)
21
24
  export { extractSceneMetadata, parseSceneMetadata } from './Processor/SceneMetadata.js';
22
25
 
@@ -29,6 +29,9 @@ export class UniformManager {
29
29
  /** @type {Set<string>} Uniforms that store boolean values as int 0/1 */
30
30
  this._booleans = new Set();
31
31
 
32
+ /** @type {Set<string>} Uniforms already warned about an array value (warn once each) */
33
+ this._arrayWarned = new Set();
34
+
32
35
  /** @type {Object} Light buffer uniformArray nodes */
33
36
  this._lightBuffers = {};
34
37
 
@@ -64,6 +67,32 @@ export class UniformManager {
64
67
 
65
68
  }
66
69
 
70
+ // Hosts wire UI controls straight to these, and slider components commonly emit [n]
71
+ // rather than n. A scalar uniform has no meaningful array value, and nothing downstream
72
+ // rejects one: the array lands in .value verbatim and poisons every later read. That is
73
+ // not hypothetical — maxBounces received [20], and PathTracer's `maxBounces +
74
+ // transmissiveBounces + maxSubsurfaceSteps` then evaluated to the STRING '2058', so the
75
+ // bounce loop ran to 2058 on any frame the survivor curve could not early-exit and hung
76
+ // the tab. Unwrap and warn once per uniform, so the caller is named rather than the
77
+ // symptom surfacing somewhere unrelated.
78
+ if ( Array.isArray( value ) && value.length === 1
79
+ && ( this._booleans.has( name ) || typeof node.value === 'number' ) ) {
80
+
81
+ if ( ! this._arrayWarned.has( name ) ) {
82
+
83
+ this._arrayWarned.add( name );
84
+ console.warn(
85
+ `UniformManager: "${name}" was set to [${value[ 0 ]}] but expects a scalar — ` +
86
+ 'unwrapping. Fix the caller; a slider handler is probably forwarding its ' +
87
+ 'array value unchanged.'
88
+ );
89
+
90
+ }
91
+
92
+ value = value[ 0 ];
93
+
94
+ }
95
+
67
96
  if ( this._booleans.has( name ) ) {
68
97
 
69
98
  node.value = value ? 1 : 0;
@@ -324,6 +353,7 @@ export class UniformManager {
324
353
 
325
354
  this._uniforms.clear();
326
355
  this._booleans.clear();
356
+ this._arrayWarned.clear();
327
357
  this._lightBuffers = {};
328
358
 
329
359
  }