rayzee 10.0.0 → 11.1.0

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.
Files changed (176) hide show
  1. package/README.md +252 -44
  2. package/dist/ActiveColor-YvuQq44O.js +13 -0
  3. package/dist/ArchiveImporter-Hn35o6Z5.js +5145 -0
  4. package/dist/AssetConfig-DSEntE65.js +30 -0
  5. package/dist/BidirectionalIntegrator-CBw8hkeu.js +946 -0
  6. package/dist/BufferLayout-D_IBo2ci.js +150 -0
  7. package/dist/ColorManagement-oeEk7oSu.js +1488 -0
  8. package/dist/EngineEvents-Ci8dVWCP.js +73 -0
  9. package/dist/EngineIssues-CIZnXHsF.js +72 -0
  10. package/dist/FileFormats-sPGJeCRc.js +102 -0
  11. package/dist/Logger-dDDGj9Av.js +97 -0
  12. package/dist/{NeuralRetouch-CYgkQY8Z.js → NeuralRetouch-BzNpiVHZ.js} +8 -6
  13. package/dist/{NeuralSuperRes-PkgDLQcD.js → NeuralSuperRes-Bk7bHg2B.js} +55 -120
  14. package/dist/PathTracer-72XufKAr.js +29976 -0
  15. package/dist/PhysicalSky-BgjdV88k.js +1219 -0
  16. package/dist/RayzeeRenderer-1QRO97eq.js +3551 -0
  17. package/dist/SolarLimb-CPaeZVwz.js +721 -0
  18. package/dist/ToneMapGPU-CjU3osDd.js +177 -0
  19. package/dist/ViewTransforms-CYN7bq2w.js +255 -0
  20. package/dist/WorkingMatrix-C6y233hT.js +27 -0
  21. package/dist/ZipReader-gDSWr0I5.js +98 -0
  22. package/dist/addons/archives.es.js +3 -0
  23. package/dist/addons/bidirectional.es.js +2 -0
  24. package/dist/addons/color.es.js +3 -0
  25. package/dist/addons/formats.es.js +2 -0
  26. package/dist/addons/physical-sky.es.js +2 -0
  27. package/dist/addons/storage.es.js +3 -0
  28. package/dist/archiveFormats-tnAoUL1j.js +94 -0
  29. package/dist/identity-DrQsGT2o.js +39 -0
  30. package/dist/openStorage-DwcBRUj7.js +820 -0
  31. package/dist/rayzee-core.es.js +12 -0
  32. package/dist/rayzee.es.js +2551 -44024
  33. package/dist/rayzee.umd.js +528 -487
  34. package/dist/sceneCachePolicy-C67jbci-.js +443 -0
  35. package/dist/shared-BGBcSxBQ.js +17 -0
  36. package/package.json +23 -2
  37. package/src/Color/ActiveColor.js +34 -0
  38. package/src/Color/BasicColor.js +147 -0
  39. package/src/Color/ColorManagement.js +7 -31
  40. package/src/Color/ViewTransforms.js +5 -1
  41. package/src/EngineDefaults.js +62 -1029
  42. package/src/EngineEvents.js +2 -0
  43. package/src/EngineIssues.js +2 -0
  44. package/src/Headless.js +6 -5
  45. package/src/Passes/AIUpscaler.js +58 -141
  46. package/src/Passes/OIDNDenoiser.js +92 -65
  47. package/src/Passes/OIDNTemporalHistory.js +1 -1
  48. package/src/PathTracerApp.js +620 -4026
  49. package/src/Pipeline/PipelineContext.js +0 -4
  50. package/src/Platform.js +36 -0
  51. package/src/Processor/ArchiveCache.js +20 -7
  52. package/src/Processor/ArchiveImporter.js +1265 -0
  53. package/src/Processor/ArchiveReader.js +22 -4
  54. package/src/Processor/AssetLoader.js +327 -1763
  55. package/src/Processor/AtmosphereModel.js +1 -2
  56. package/src/Processor/BVHBuilder.js +14 -126
  57. package/src/Processor/BVHLeafFold.js +4 -6
  58. package/src/Processor/BVHRefitter.js +67 -46
  59. package/src/Processor/BufferLayout.js +291 -0
  60. package/src/Processor/EmissiveTriangleBuilder.js +1 -1
  61. package/src/Processor/EnvironmentExactTable.js +187 -0
  62. package/src/Processor/EquirectHDRInfo.js +30 -223
  63. package/src/Processor/FileFormats.js +116 -0
  64. package/src/Processor/GLTFDecoders.js +85 -0
  65. package/src/Processor/GLTFDiffuseTransmission.js +63 -0
  66. package/src/Processor/GeometryExtractor.js +15 -5
  67. package/src/Processor/HostMemory.js +7 -1
  68. package/src/Processor/IESParser.js +47 -35
  69. package/src/Processor/InstanceTable.js +1 -1
  70. package/src/Processor/KernelManager.js +35 -2
  71. package/src/Processor/MaterialPacking.js +10 -8
  72. package/src/Processor/PBRT/PBRTMaterials.js +254 -42
  73. package/src/Processor/PBRT/PBRTParser.js +49 -19
  74. package/src/Processor/PBRT/PBRTScattering.js +93 -0
  75. package/src/Processor/PBRT/PBRTSceneBuilder.js +1050 -75
  76. package/src/Processor/PBRT/PBRTTextureBake.js +179 -0
  77. package/src/Processor/PBRT/PFM.js +59 -0
  78. package/src/Processor/PackedRayBuffer.js +116 -9
  79. package/src/Processor/ParallelBVHBuilder.js +3 -6
  80. package/src/Processor/PhysicalSky.js +5 -4
  81. package/src/Processor/PlatformImageLoader.js +50 -6
  82. package/src/Processor/QueueManager.js +39 -5
  83. package/src/Processor/ReinsertionOptimizer.js +2 -2
  84. package/src/Processor/SceneMetadata.js +30 -5
  85. package/src/Processor/SceneProcessor.js +53 -62
  86. package/src/Processor/ShaderBuilder.js +6 -16
  87. package/src/Processor/SimpleSky.js +1 -62
  88. package/src/Processor/SolarLimb.js +3 -0
  89. package/src/Processor/SplitBLAS.js +1 -1
  90. package/src/Processor/StorageTexturePool.js +22 -1
  91. package/src/Processor/TLASBuilder.js +1 -3
  92. package/src/Processor/TextureBuckets.js +237 -0
  93. package/src/Processor/TextureCreator.js +181 -8
  94. package/src/Processor/ToneMapGPU.js +64 -15
  95. package/src/Processor/Workers/BVHRefitWorker.js +5 -2
  96. package/src/Processor/Workers/BVHSubtreeWorker.js +1 -34
  97. package/src/Processor/Workers/BVHWorker.js +5 -18
  98. package/src/Processor/Workers/CDFWorker.js +6 -183
  99. package/src/Processor/Workers/TexturesWorker.js +103 -18
  100. package/src/Processor/archiveFormats.js +7 -0
  101. package/src/Processor/utils.js +2 -1
  102. package/src/RayzeeRenderer.js +3900 -0
  103. package/src/RenderSettings.js +68 -62
  104. package/src/Stages/ASVGF.js +13 -14
  105. package/src/Stages/AutoExposure.js +17 -17
  106. package/src/Stages/BilateralFilter.js +2 -1
  107. package/src/Stages/Compositor.js +8 -23
  108. package/src/Stages/DenoiserSettings.js +182 -0
  109. package/src/Stages/EdgeFilter.js +2 -1
  110. package/src/Stages/MotionVector.js +1 -1
  111. package/src/Stages/NRD.js +11 -5
  112. package/src/Stages/NormalDepth.js +12 -8
  113. package/src/Stages/PathTracer.js +336 -43
  114. package/src/Stages/PathTracerStage.js +69 -66
  115. package/src/Stages/Variance.js +1 -1
  116. package/src/Storage/BLASCache.js +1 -1
  117. package/src/Storage/CDFCache.js +18 -17
  118. package/src/Storage/DownloadCache.js +1 -1
  119. package/src/Storage/SceneGraphCodec.js +46 -3
  120. package/src/Storage/SpillStore.js +1 -1
  121. package/src/Storage/StorageManager.js +45 -9
  122. package/src/Storage/areas.js +4 -0
  123. package/src/TSL/BVHTraversal.js +50 -25
  124. package/src/TSL/Bidirectional.js +208 -0
  125. package/src/TSL/BidirectionalLamps.js +132 -0
  126. package/src/TSL/Clearcoat.js +15 -6
  127. package/src/TSL/Common.js +20 -15
  128. package/src/TSL/ConnectKernel.js +167 -0
  129. package/src/TSL/Debugger.js +1 -1
  130. package/src/TSL/Displacement.js +4 -3
  131. package/src/TSL/EmissiveSampling.js +65 -18
  132. package/src/TSL/Environment.js +77 -106
  133. package/src/TSL/EnvironmentCDF.js +85 -39
  134. package/src/TSL/ExtendKernel.js +8 -3
  135. package/src/TSL/FinalWriteKernel.js +4 -4
  136. package/src/TSL/GenerateKernel.js +18 -4
  137. package/src/TSL/HitFacet.js +35 -5
  138. package/src/TSL/LightBVHSampling.js +40 -9
  139. package/src/TSL/LightGenerateKernel.js +293 -0
  140. package/src/TSL/LightGuide.js +198 -0
  141. package/src/TSL/LightSplatKernel.js +180 -0
  142. package/src/TSL/LightVisibility.js +111 -0
  143. package/src/TSL/LightsCore.js +13 -38
  144. package/src/TSL/LightsDirect.js +28 -29
  145. package/src/TSL/LightsIndirect.js +3 -1
  146. package/src/TSL/LightsSampling.js +239 -51
  147. package/src/TSL/MaterialEvaluation.js +113 -31
  148. package/src/TSL/MaterialProperties.js +44 -17
  149. package/src/TSL/MaterialTransmission.js +52 -47
  150. package/src/TSL/MergeKernel.js +224 -0
  151. package/src/TSL/PathTracerCore.js +65 -29
  152. package/src/TSL/Random.js +5 -1
  153. package/src/TSL/SceneResources.js +51 -0
  154. package/src/TSL/ShadeKernel.js +985 -101
  155. package/src/TSL/Struct.js +10 -0
  156. package/src/TSL/Sun.js +1 -1
  157. package/src/TSL/TextureSampling.js +66 -61
  158. package/src/addons/archives.js +14 -0
  159. package/src/addons/bidirectional.js +13 -0
  160. package/src/addons/color.js +32 -0
  161. package/src/addons/formats.js +16 -0
  162. package/src/addons/physicalSky.js +14 -0
  163. package/src/addons/storage.js +19 -0
  164. package/src/core.js +31 -0
  165. package/src/index.js +13 -23
  166. package/src/integrators/BidirectionalIntegrator.js +838 -0
  167. package/src/managers/AnimationManager.js +88 -6
  168. package/src/managers/CameraManager.js +103 -46
  169. package/src/managers/DenoisingManager.js +14 -10
  170. package/src/managers/EnvironmentManager.js +125 -103
  171. package/src/managers/GoboManager.js +9 -0
  172. package/src/managers/MaterialDataManager.js +48 -37
  173. package/src/managers/UniformManager.js +32 -10
  174. package/dist/ToneMapGPU-B6XIe3DU.js +0 -544
  175. package/dist/rolldown-runtime-CAFD8bLK.js +0 -11
  176. package/src/Processor/TreeletOptimizer.js +0 -574
@@ -1,44 +1,7 @@
1
1
  import { DataUtils, HalfFloatType, FloatType, SRGBColorSpace } from 'three';
2
2
  import CDFWorker from './Workers/CDFWorker.js?worker&inline';
3
3
  import { createWorker } from '../Platform.js';
4
-
5
- /**
6
- * Binary search to find the closest index
7
- */
8
- function binarySearchFindClosestIndexOf( array, targetValue, offset = 0, count = array.length ) {
9
-
10
- let lower = offset;
11
- let upper = offset + count - 1;
12
-
13
- while ( lower < upper ) {
14
-
15
- const mid = ( lower + upper ) >> 1;
16
-
17
- if ( array[ mid ] < targetValue ) {
18
-
19
- lower = mid + 1;
20
-
21
- } else {
22
-
23
- upper = mid;
24
-
25
- }
26
-
27
- }
28
-
29
- return lower - offset;
30
-
31
- }
32
-
33
- /**
34
- * Calculate luminance from RGB values
35
- */
36
- function colorToLuminance( r, g, b ) {
37
-
38
- // https://en.wikipedia.org/wiki/Relative_luminance
39
- return 0.2126 * r + 0.7152 * g + 0.0722 * b;
40
-
41
- }
4
+ import { buildExactEnvironmentTable } from './EnvironmentExactTable.js';
42
5
 
43
6
  /**
44
7
  * sRGB to linear conversion (IEC 61966-2-1 transfer function)
@@ -154,27 +117,24 @@ export function extractFloatData( envMap ) {
154
117
  }
155
118
 
156
119
  /**
157
- * EquirectHDRInfo - Importance sampling data for equirectangular HDR maps
158
- *
159
- * Builds inverted marginal and conditional CDFs from an HDR environment map.
160
- * Outputs Float32Arrays consumed directly by StorageInstancedBufferAttribute
161
- * on the GPU — no intermediate DataTexture or HalfFloat conversion needed.
162
- *
163
- * Supports two modes:
164
- * - `updateFrom(hdr)`: synchronous, runs on main thread
165
- * - `updateFromAsync(hdr)`: offloads CDF math to a Web Worker
120
+ * EquirectHDRInfo - an equirectangular environment's sampling table (EnvironmentExactTable.js), built on the
121
+ * main thread (`updateFrom`) or in CDFWorker (`updateFromAsync`). `totalSum` is the map's ∫ luminance dω, 0
122
+ * when there is nothing to sample.
166
123
  */
167
124
  export class EquirectHDRInfo {
168
125
 
169
126
  constructor() {
170
127
 
171
- // Placeholder data matching the default storage buffer sizes in PathTracer
172
- this.marginalData = new Float32Array( [ 0, 1 ] );
173
- this.conditionalData = new Float32Array( [ 0, 0, 1, 1 ] );
174
128
  this.totalSum = 0;
175
- this.compensationDelta = 0;
176
129
  this.width = 0;
177
130
  this.height = 0;
131
+ this.exactConditional = null;
132
+ this.exactMarginal = null;
133
+ this.exactRowGuide = null;
134
+ this.exactMarginalGuide = null;
135
+ this.exactWidth = 0;
136
+ this.exactHeight = 0;
137
+ this.radianceIntegral = 0;
178
138
 
179
139
  this._worker = null;
180
140
 
@@ -182,8 +142,10 @@ export class EquirectHDRInfo {
182
142
 
183
143
  dispose() {
184
144
 
185
- this.marginalData = null;
186
- this.conditionalData = null;
145
+ this.exactConditional = null;
146
+ this.exactMarginal = null;
147
+ this.exactRowGuide = null;
148
+ this.exactMarginalGuide = null;
187
149
 
188
150
  if ( this._worker ) {
189
151
 
@@ -194,28 +156,28 @@ export class EquirectHDRInfo {
194
156
 
195
157
  }
196
158
 
159
+ _adopt( table, width, height ) {
160
+
161
+ Object.assign( this, table );
162
+ this.width = width;
163
+ this.height = height;
164
+ this.totalSum = table.radianceIntegral;
165
+
166
+ }
167
+
197
168
  /**
198
- * Synchronous CDF build on main thread (fallback path).
169
+ * Synchronous build on the main thread (fallback path).
199
170
  */
200
171
  updateFrom( hdr ) {
201
172
 
202
173
  const { floatData, width, height } = extractFloatData( hdr );
203
-
204
- const result = EquirectHDRInfo.computeCDF( floatData, width, height );
205
-
206
- this.marginalData = result.marginalData;
207
- this.conditionalData = result.conditionalData;
208
- this.totalSum = result.totalSum;
209
- this.compensationDelta = result.compensationDelta;
210
- this.width = width;
211
- this.height = height;
174
+ this._adopt( buildExactEnvironmentTable( floatData, width, height ), width, height );
212
175
 
213
176
  }
214
177
 
215
178
  /**
216
- * Async CDF build offloaded to a Web Worker.
217
- * Float extraction (HalfFloat → Float32) runs on main thread (needs Three.js DataUtils),
218
- * then the pure-math CDF computation runs off-thread.
179
+ * The build offloaded to a Web Worker. Float extraction (HalfFloat → Float32) runs on the main thread
180
+ * (it needs three's DataUtils); the table's math runs off it.
219
181
  * @returns {Promise<void>}
220
182
  */
221
183
  async updateFromAsync( hdr ) {
@@ -253,12 +215,8 @@ export class EquirectHDRInfo {
253
215
 
254
216
  } );
255
217
 
256
- this.marginalData = result.marginalData;
257
- this.conditionalData = result.conditionalData;
258
- this.totalSum = result.totalSum;
259
- this.compensationDelta = result.compensationDelta;
260
- this.width = result.width;
261
- this.height = result.height;
218
+ const { width: w, height: h, ...table } = result;
219
+ this._adopt( table, w, h );
262
220
 
263
221
  } finally {
264
222
 
@@ -273,155 +231,4 @@ export class EquirectHDRInfo {
273
231
 
274
232
  }
275
233
 
276
- /**
277
- * Pure-math CDF computation. Used by both the sync path and CDFWorker.
278
- * Static so it can be called without an instance.
279
- */
280
- static computeCDF( floatData, width, height ) {
281
-
282
- const numPixels = width * height;
283
-
284
- // Pass 1: compute per-pixel luminance weighted by sin(theta) and raw total sum.
285
- // sin(theta) compensates for the equirectangular projection: pixels near the poles
286
- // cover less solid angle, so weighting by sin(theta) makes the CDF proportional to
287
- // luminance per solid angle rather than luminance per pixel.
288
- const pixelWeights = new Float32Array( numPixels );
289
- let rawTotalSum = 0.0;
290
-
291
- for ( let y = 0; y < height; y ++ ) {
292
-
293
- const sinTheta = Math.sin( Math.PI * ( y + 0.5 ) / height );
294
-
295
- for ( let x = 0; x < width; x ++ ) {
296
-
297
- const i = y * width + x;
298
- const w = colorToLuminance(
299
- floatData[ 4 * i ],
300
- floatData[ 4 * i + 1 ],
301
- floatData[ 4 * i + 2 ],
302
- ) * sinTheta;
303
- pixelWeights[ i ] = w;
304
- rawTotalSum += w;
305
-
306
- }
307
-
308
- }
309
-
310
- // MIS Compensation (Karlík et al. 2019, Eq. 14)
311
- // With equal sample allocation (c_I = 0.5): delta = 2*(1 - 0.5)*meanWeight = meanWeight
312
- // Subtracting mean sharpens the env map PDF, reducing oversampling
313
- // of dim regions already well-covered by BSDF sampling.
314
- const meanWeight = rawTotalSum / numPixels;
315
- let compensatedTotalSum = 0.0;
316
-
317
- for ( let i = 0; i < numPixels; i ++ ) {
318
-
319
- pixelWeights[ i ] = Math.max( 0, pixelWeights[ i ] - meanWeight );
320
- compensatedTotalSum += pixelWeights[ i ];
321
-
322
- }
323
-
324
- // Fall back to raw weights if compensation zeroed everything (uniform env map)
325
- const useCompensation = compensatedTotalSum > 0;
326
- const totalSumValue = useCompensation ? compensatedTotalSum : rawTotalSum;
327
- const compensationDelta = useCompensation ? meanWeight : 0;
328
-
329
- if ( ! useCompensation ) {
330
-
331
- for ( let y = 0; y < height; y ++ ) {
332
-
333
- const sinTheta = Math.sin( Math.PI * ( y + 0.5 ) / height );
334
-
335
- for ( let x = 0; x < width; x ++ ) {
336
-
337
- const i = y * width + x;
338
- pixelWeights[ i ] = colorToLuminance(
339
- floatData[ 4 * i ],
340
- floatData[ 4 * i + 1 ],
341
- floatData[ 4 * i + 2 ],
342
- ) * sinTheta;
343
-
344
- }
345
-
346
- }
347
-
348
- }
349
-
350
- // Pass 2: build conditional and marginal CDFs from (compensated) weights
351
- const cdfConditional = new Float32Array( numPixels );
352
- const cdfMarginal = new Float32Array( height );
353
-
354
- let cumulativeWeightMarginal = 0.0;
355
-
356
- for ( let y = 0; y < height; y ++ ) {
357
-
358
- let cumulativeRowWeight = 0.0;
359
- for ( let x = 0; x < width; x ++ ) {
360
-
361
- const i = y * width + x;
362
- cumulativeRowWeight += pixelWeights[ i ];
363
- cdfConditional[ i ] = cumulativeRowWeight;
364
-
365
- }
366
-
367
- // Normalize row CDF to [0, 1]
368
- if ( cumulativeRowWeight !== 0 ) {
369
-
370
- for ( let i = y * width, l = y * width + width; i < l; i ++ ) {
371
-
372
- cdfConditional[ i ] /= cumulativeRowWeight;
373
-
374
- }
375
-
376
- }
377
-
378
- cumulativeWeightMarginal += cumulativeRowWeight;
379
- cdfMarginal[ y ] = cumulativeWeightMarginal;
380
-
381
- }
382
-
383
- // Normalize marginal CDF to [0, 1]
384
- if ( cumulativeWeightMarginal !== 0 ) {
385
-
386
- for ( let i = 0, l = cdfMarginal.length; i < l; i ++ ) {
387
-
388
- cdfMarginal[ i ] /= cumulativeWeightMarginal;
389
-
390
- }
391
-
392
- }
393
-
394
- // Create inverted CDF arrays (Float32 directly for storage buffers)
395
- const marginalData = new Float32Array( height );
396
- const conditionalData = new Float32Array( numPixels );
397
-
398
- // Invert marginal CDF
399
- for ( let i = 0; i < height; i ++ ) {
400
-
401
- const dist = ( i + 1 ) / height;
402
- const row = binarySearchFindClosestIndexOf( cdfMarginal, dist );
403
-
404
- marginalData[ i ] = ( row + 0.5 ) / height;
405
-
406
- }
407
-
408
- // Invert conditional CDFs
409
- for ( let y = 0; y < height; y ++ ) {
410
-
411
- for ( let x = 0; x < width; x ++ ) {
412
-
413
- const i = y * width + x;
414
- const dist = ( x + 1 ) / width;
415
- const col = binarySearchFindClosestIndexOf( cdfConditional, dist, y * width, width );
416
-
417
- conditionalData[ i ] = ( col + 0.5 ) / width;
418
-
419
- }
420
-
421
- }
422
-
423
- return { marginalData, conditionalData, totalSum: totalSumValue, compensationDelta };
424
-
425
- }
426
-
427
234
  }
@@ -0,0 +1,116 @@
1
+ import { FloatType, Mesh, MeshStandardMaterial, Points, PointsMaterial } from 'three';
2
+
3
+ /**
4
+ * File formats beyond glTF and .hdr, each registered on its own (`assetLoader.registerFormat( fbxFormat )`) so a host
5
+ * ships only the readers it uses. A model format's `parse( file, { filename, cache } )` resolves to `{ model, result? }`;
6
+ * an environment format's `createLoader( manager )` to a three.js loader whose `loadAsync` resolves to a texture.
7
+ * Each three.js loader is imported the first time its format is read.
8
+ */
9
+
10
+ export const fbxFormat = {
11
+ name: 'FBX', label: 'FBX', type: 'model', extensions: [ 'fbx' ],
12
+ async parse( file, { cache } ) {
13
+
14
+ cache.fbx ??= new ( await import( 'three/addons/loaders/FBXLoader.js' ) ).FBXLoader();
15
+ return { model: cache.fbx.parse( await file.arrayBuffer() ) };
16
+
17
+ },
18
+ };
19
+
20
+ export const objFormat = {
21
+ name: 'OBJ', label: 'OBJ', type: 'model', extensions: [ 'obj' ],
22
+ async parse( file, { filename, cache } ) {
23
+
24
+ cache.obj ??= new ( await import( 'three/addons/loaders/OBJLoader.js' ) ).OBJLoader();
25
+ const model = cache.obj.parse( await file.text() );
26
+ model.name = filename;
27
+ return { model };
28
+
29
+ },
30
+ };
31
+
32
+ export const stlFormat = {
33
+ name: 'STL', label: 'STL', type: 'model', extensions: [ 'stl' ],
34
+ async parse( file, { filename, cache } ) {
35
+
36
+ cache.stl ??= new ( await import( 'three/addons/loaders/STLLoader.js' ) ).STLLoader();
37
+ const model = new Mesh( cache.stl.parse( await file.arrayBuffer() ), new MeshStandardMaterial() );
38
+ model.name = filename;
39
+ return { model };
40
+
41
+ },
42
+ };
43
+
44
+ export const plyFormat = {
45
+ name: 'PLY (Polygon File Format)', label: 'PLY', type: 'model', extensions: [ 'ply' ],
46
+ async parse( file, { filename, cache } ) {
47
+
48
+ cache.ply ??= new ( await import( 'three/addons/loaders/PLYLoader.js' ) ).PLYLoader();
49
+ const geometry = cache.ply.parse( await file.arrayBuffer() );
50
+ let model;
51
+ if ( geometry.index !== null ) {
52
+
53
+ model = new Mesh( geometry, new MeshStandardMaterial() );
54
+
55
+ } else {
56
+
57
+ const material = new PointsMaterial( { size: 0.01 } );
58
+ material.vertexColors = geometry.hasAttribute( 'color' );
59
+ model = new Points( geometry, material );
60
+
61
+ }
62
+
63
+ model.name = filename;
64
+ return { model };
65
+
66
+ },
67
+ };
68
+
69
+ export const colladaFormat = {
70
+ name: 'Collada', label: 'Collada', type: 'model', extensions: [ 'dae' ],
71
+ async parse( file, { filename, cache } ) {
72
+
73
+ cache.collada ??= new ( await import( 'three/addons/loaders/ColladaLoader.js' ) ).ColladaLoader();
74
+ const collada = cache.collada.parse( await file.text() );
75
+ collada.scene.name = filename;
76
+ return { model: collada.scene, result: collada };
77
+
78
+ },
79
+ };
80
+
81
+ export const threeMFFormat = {
82
+ name: '3D Manufacturing Format', label: '3MF', type: 'model', extensions: [ '3mf' ],
83
+ async parse( file, { cache } ) {
84
+
85
+ cache.threemf ??= new ( await import( 'three/addons/loaders/3MFLoader.js' ) ).ThreeMFLoader();
86
+ return { model: cache.threemf.parse( await file.arrayBuffer() ) };
87
+
88
+ },
89
+ };
90
+
91
+ export const usdFormat = {
92
+ name: 'USD (Universal Scene Description)', label: 'USD', type: 'model', extensions: [ 'usd', 'usda', 'usdc', 'usdz' ],
93
+ async parse( file, { filename, cache } ) {
94
+
95
+ cache.usd ??= new ( await import( 'three/addons/loaders/USDLoader.js' ) ).USDLoader();
96
+ const data = await file.arrayBuffer();
97
+ // parse() returns the group at once but resolves textures later; the materials are read after, so wait for them.
98
+ const model = await new Promise( ( resolve, reject ) => cache.usd.parse( data, '', resolve, reject ) );
99
+ model.name = filename;
100
+ return { model };
101
+
102
+ },
103
+ };
104
+
105
+ export const exrFormat = {
106
+ name: 'EXR (OpenEXR)', label: 'EXR', type: 'environment', extensions: [ 'exr' ],
107
+ async createLoader( manager ) {
108
+
109
+ const { EXRLoader } = await import( 'three/addons/loaders/EXRLoader.js' );
110
+ return new EXRLoader( manager ).setDataType( FloatType );
111
+
112
+ },
113
+ };
114
+
115
+ /** Every format above. */
116
+ export const allFormats = [ fbxFormat, objFormat, stlFormat, plyFormat, colladaFormat, threeMFFormat, usdFormat, exrFormat ];
@@ -0,0 +1,85 @@
1
+ import { getAssetConfig } from '../AssetConfig.js';
2
+
3
+ const DRACO = 'KHR_draco_mesh_compression';
4
+ const BASISU = 'KHR_texture_basisu';
5
+ const MESHOPT = [ 'EXT_meshopt_compression', 'KHR_meshopt_compression' ];
6
+
7
+ const decoder = new TextDecoder();
8
+
9
+ // The glTF's JSON as text: a .glb's first chunk, a .gltf whole. Only searched, never parsed.
10
+ function jsonText( data ) {
11
+
12
+ if ( typeof data === 'string' ) return data;
13
+ if ( ! ( data instanceof ArrayBuffer ) ) return JSON.stringify( data?.extensionsUsed ?? [] );
14
+
15
+ const view = new DataView( data );
16
+ const isBinary = data.byteLength >= 20 && view.getUint32( 0, true ) === 0x46546C67;
17
+ if ( ! isBinary ) return decoder.decode( data );
18
+ const length = Math.min( view.getUint32( 12, true ), data.byteLength - 20 );
19
+ return decoder.decode( new Uint8Array( data, 20, length ) );
20
+
21
+ }
22
+
23
+ async function attachDecoders( loader, text, renderer ) {
24
+
25
+ const { dracoDecoderPath, ktx2TranscoderPath } = getAssetConfig();
26
+ const [ draco, ktx2, meshopt ] = await Promise.all( [
27
+ text.includes( DRACO ) && ! loader.dracoLoader ? import( 'three/addons/loaders/DRACOLoader.js' ) : null,
28
+ text.includes( BASISU ) && ! loader.ktx2Loader ? import( 'three/addons/loaders/KTX2Loader.js' ) : null,
29
+ MESHOPT.some( name => text.includes( name ) ) && ! loader.meshoptDecoder ? import( 'three/addons/libs/meshopt_decoder.module.js' ) : null,
30
+ ] );
31
+
32
+ if ( draco ) {
33
+
34
+ const dracoLoader = new draco.DRACOLoader();
35
+ dracoLoader.setDecoderConfig( { type: 'js' } );
36
+ dracoLoader.setDecoderPath( dracoDecoderPath );
37
+ loader.setDRACOLoader( dracoLoader );
38
+
39
+ }
40
+
41
+ if ( ktx2 ) {
42
+
43
+ const ktx2Loader = new ktx2.KTX2Loader();
44
+ ktx2Loader.setTranscoderPath( ktx2TranscoderPath );
45
+ if ( renderer ) {
46
+
47
+ ktx2Loader.detectSupport( renderer );
48
+ // RGBA only: GPU-compressed texture arrays are blocked by a three.js TSL limitation (the node compiler's
49
+ // state survives dispose(), so swapping DataArrayTexture for CompressedArrayTexture breaks WGSL compilation).
50
+ ktx2Loader.workerConfig = {
51
+ astcSupported: false, etc1Supported: false, etc2Supported: false,
52
+ dxtSupported: false, bptcSupported: false, pvrtcSupported: false,
53
+ };
54
+
55
+ }
56
+
57
+ loader.setKTX2Loader( ktx2Loader );
58
+
59
+ }
60
+
61
+ if ( meshopt ) loader.setMeshoptDecoder( meshopt.MeshoptDecoder );
62
+
63
+ }
64
+
65
+ /**
66
+ * Gives a GLTFLoader the Draco, KTX2 and meshopt decoders only when the file it parses uses them, importing each then:
67
+ * most glTFs use none, and the three are ~35 KB compressed a host would otherwise always ship.
68
+ * @param {Object} loader - a GLTFLoader
69
+ * @param {?Object} renderer - for KTX2's format detection
70
+ */
71
+ export function decodersOnDemand( loader, renderer ) {
72
+
73
+ const parse = loader.parse.bind( loader );
74
+ loader.parse = ( data, path, onLoad, onError ) => {
75
+
76
+ attachDecoders( loader, jsonText( data ), renderer ).then(
77
+ () => parse( data, path, onLoad, onError ),
78
+ ( error ) => onError?.( error ),
79
+ );
80
+
81
+ };
82
+
83
+ return loader;
84
+
85
+ }
@@ -0,0 +1,63 @@
1
+ import { Color, LinearSRGBColorSpace, SRGBColorSpace } from 'three';
2
+
3
+ export const DIFFUSE_TRANSMISSION_EXTENSION = 'KHR_materials_diffuse_transmission';
4
+
5
+ /**
6
+ * A GLTFLoader plugin for KHR_materials_diffuse_transmission, which three.js does not read: each material's factors
7
+ * and textures become the engine's `diffuseTransmission`, `diffuseTransmissionColor`, `diffuseTransmissionMap` (its
8
+ * alpha is the factor) and `diffuseTransmissionColorMap`. The engine folds the maps in like the other extension maps,
9
+ * through the albedo map's uv transform.
10
+ */
11
+ export function diffuseTransmissionPlugin( parser ) {
12
+
13
+ // The factor texture is read for its alpha alone and may be another slot's colour texture, so its colour space is
14
+ // left as it is.
15
+ const assign = ( material, key, info, colorSpace ) => {
16
+
17
+ const params = {};
18
+ return parser.assignTexture( params, key, info, colorSpace ).then( () => {
19
+
20
+ if ( params[ key ] ) material[ key ] = params[ key ];
21
+
22
+ } );
23
+
24
+ };
25
+
26
+ return {
27
+
28
+ name: DIFFUSE_TRANSMISSION_EXTENSION,
29
+
30
+ afterRoot( result ) {
31
+
32
+ const definitions = parser.json.materials ?? [];
33
+ const done = new Set();
34
+ const pending = [];
35
+
36
+ for ( const scene of result.scenes ?? [] ) scene.traverse( ( object ) => {
37
+
38
+ const materials = Array.isArray( object.material ) ? object.material : object.material ? [ object.material ] : [];
39
+ for ( const material of materials ) {
40
+
41
+ if ( done.has( material ) ) continue;
42
+ done.add( material );
43
+ const index = parser.associations.get( material )?.materials;
44
+ const extension = index === undefined ? null : definitions[ index ]?.extensions?.[ DIFFUSE_TRANSMISSION_EXTENSION ];
45
+ if ( ! extension ) continue;
46
+
47
+ material.diffuseTransmission = extension.diffuseTransmissionFactor ?? 0;
48
+ const [ r, g, b ] = extension.diffuseTransmissionColorFactor ?? [ 1, 1, 1 ];
49
+ material.diffuseTransmissionColor = new Color().setRGB( r, g, b, LinearSRGBColorSpace );
50
+ if ( extension.diffuseTransmissionTexture ) pending.push( assign( material, 'diffuseTransmissionMap', extension.diffuseTransmissionTexture ) );
51
+ if ( extension.diffuseTransmissionColorTexture ) pending.push( assign( material, 'diffuseTransmissionColorMap', extension.diffuseTransmissionColorTexture, SRGBColorSpace ) );
52
+
53
+ }
54
+
55
+ } );
56
+
57
+ return Promise.all( pending );
58
+
59
+ },
60
+
61
+ };
62
+
63
+ }
@@ -1,7 +1,7 @@
1
1
  import { BufferAttribute, Vector3, Vector2, Color, Matrix3, Matrix4, FrontSide, BackSide, DoubleSide, RGBAFormat } from "three";
2
- import {
3
- TEXTURE_CONSTANTS, TRIANGLE_DATA_LAYOUT, MATERIAL_DEFAULTS, packNormalOct, packTriangleFlags, MATERIAL_SIDE_CUTAWAY
4
- } from '../EngineDefaults.js';
2
+ import { MATERIAL_DEFAULTS } from '../EngineDefaults.js';
3
+ import { TRIANGLE_DATA_LAYOUT, packNormalOct, packTriangleFlags } from './BufferLayout.js';
4
+ import { TEXTURE_CONSTANTS } from './TextureBuckets.js';
5
5
  import { ISSUE_CODES } from '../EngineIssues.js';
6
6
  import { ChunkedRecords, SHARED_MEMORY_AVAILABLE } from './ChunkedRecords.js';
7
7
  import { createLogger, fmt, warnOnce } from '../utils/Logger.js';
@@ -11,7 +11,7 @@ const log = createLogger( 'geometry' );
11
11
 
12
12
  const MAX_TEXTURES_LIMIT = TEXTURE_CONSTANTS.MAX_TEXTURES_LIMIT;
13
13
 
14
- const COLOR_DEFAULTS = new Set( [ 'color', 'emissive', 'attenuationColor', 'sheenColor', 'specularColor', 'subsurfaceColor' ] );
14
+ const COLOR_DEFAULTS = new Set( [ 'color', 'emissive', 'attenuationColor', 'sheenColor', 'specularColor', 'subsurfaceColor', 'diffuseTransmissionColor' ] );
15
15
 
16
16
  /**
17
17
  * Where a packed material value came from: the three.js material carried it, a legacy-type
@@ -58,6 +58,8 @@ export function resolveMaterialTextures( material ) {
58
58
  sheenRoughnessMap: material.sheenRoughnessMap,
59
59
  specularIntensityMap: material.specularIntensityMap,
60
60
  specularColorMap: material.specularColorMap,
61
+ diffuseTransmissionMap: material.diffuseTransmissionMap,
62
+ diffuseTransmissionColorMap: material.diffuseTransmissionColorMap,
61
63
  iridescenceMap: material.iridescenceMap,
62
64
  iridescenceThicknessMap: material.iridescenceThicknessMap,
63
65
  };
@@ -1110,6 +1112,9 @@ export class GeometryExtractor {
1110
1112
  specularIntensity: pick( 'specularIntensity' ),
1111
1113
  specularColor: pick( 'specularColor' ),
1112
1114
 
1115
+ diffuseTransmission: pick( 'diffuseTransmission' ),
1116
+ diffuseTransmissionColor: pick( 'diffuseTransmissionColor' ),
1117
+
1113
1118
  normalScale: pick( 'normalScale' ),
1114
1119
  bumpScale: pick( 'bumpScale' ),
1115
1120
  displacementScale: pick( 'displacementScale' ),
@@ -1141,6 +1146,8 @@ export class GeometryExtractor {
1141
1146
  sheenRoughnessMap: this.processTexture( textures.sheenRoughnessMap, this.sheenRoughnessMaps ),
1142
1147
  specularIntensityMap: this.processTexture( textures.specularIntensityMap, this.specularIntensityMaps ),
1143
1148
  specularColorMap: this.processTexture( textures.specularColorMap, this.specularColorMaps ),
1149
+ diffuseTransmissionMap: this.processTexture( textures.diffuseTransmissionMap, this.diffuseTransmissionMaps ),
1150
+ diffuseTransmissionColorMap: this.processTexture( textures.diffuseTransmissionColorMap, this.diffuseTransmissionColorMaps ),
1144
1151
  iridescenceMap: this.processTexture( textures.iridescenceMap, this.iridescenceMaps ),
1145
1152
  iridescenceThicknessMap: this.processTexture( textures.iridescenceThicknessMap, this.iridescenceThicknessMaps ),
1146
1153
 
@@ -1171,7 +1178,6 @@ export class GeometryExtractor {
1171
1178
  getMaterialSide( material ) {
1172
1179
 
1173
1180
  if ( material.transmission > 0.0 ) return 2;
1174
- if ( material.userData?.cutaway === true ) return MATERIAL_SIDE_CUTAWAY;
1175
1181
  switch ( material.side ) {
1176
1182
 
1177
1183
  case FrontSide: return 0;
@@ -1538,6 +1544,8 @@ export class GeometryExtractor {
1538
1544
  this.iridescenceThicknessMaps = [];
1539
1545
  this.specularIntensityMaps = [];
1540
1546
  this.specularColorMaps = [];
1547
+ this.diffuseTransmissionMaps = [];
1548
+ this.diffuseTransmissionColorMaps = [];
1541
1549
  this.directionalLights = [];
1542
1550
  this.cameras = [];
1543
1551
 
@@ -1579,6 +1587,8 @@ export class GeometryExtractor {
1579
1587
  iridescenceThicknessMaps: this.iridescenceThicknessMaps,
1580
1588
  specularIntensityMaps: this.specularIntensityMaps,
1581
1589
  specularColorMaps: this.specularColorMaps,
1590
+ diffuseTransmissionMaps: this.diffuseTransmissionMaps,
1591
+ diffuseTransmissionColorMaps: this.diffuseTransmissionColorMaps,
1582
1592
  directionalLights: this.directionalLights,
1583
1593
  cameras: this.cameras
1584
1594
  };
@@ -14,7 +14,7 @@
14
14
  * that actually runs out (BVH assembly), where it asks only for that step's bytes.
15
15
  */
16
16
 
17
- import { TRIANGLE_DATA_LAYOUT } from '../EngineDefaults.js';
17
+ import { TRIANGLE_DATA_LAYOUT } from './BufferLayout.js';
18
18
  import { DEFAULT_CHUNK_BYTES } from './ChunkedRecords.js';
19
19
 
20
20
  /** Bytes one stored triangle occupies in the triangle records. */
@@ -59,6 +59,12 @@ export const SAFE_SCENE_BYTES = 7040 * 1024 * 1024;
59
59
  */
60
60
  export const MAX_SCENE_BYTES = 9216 * 1024 * 1024;
61
61
 
62
+ // Scene-archive budgets with the memory spill on: the triangles and BVH leave the heap as the build goes, so the host
63
+ // passes these instead of the importer's own. The whole 15-part Moana subset (55.7M / 7.0M) loads cold under them, at
64
+ // an 8.1 GB preflight estimate; the preflight, not the budget, refuses anything larger.
65
+ export const SPILL_TRIANGLE_BUDGET = 60_000_000;
66
+ export const SPILL_PLACEMENT_BUDGET = 8_000_000;
67
+
62
68
  /**
63
69
  * The host's memory in GB: the host's own figure when it gives one, else Chrome's
64
70
  * `navigator.deviceMemory`, else an assumed 4 (every other runtime lacks it).