rayzee 9.0.0 → 9.1.1

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 (95) hide show
  1. package/README.md +139 -8
  2. package/dist/{NeuralRetouch-CYOJ21Wn.js → NeuralRetouch-BRquqfmZ.js} +1 -1
  3. package/dist/{NeuralSuperRes-CQLCLpcC.js → NeuralSuperRes-CbNvQjCw.js} +3 -2
  4. package/dist/{ToneMapGPU-BVE852iN.js → ToneMapGPU-DpUZDMbQ.js} +2 -1
  5. package/dist/rayzee.es.js +10353 -5337
  6. package/dist/rayzee.umd.js +265 -265
  7. package/package.json +1 -1
  8. package/src/AssetConfig.js +4 -0
  9. package/src/EngineDefaults.js +38 -56
  10. package/src/EngineEvents.js +3 -0
  11. package/src/EngineIssues.js +6 -0
  12. package/src/Headless.js +3 -1
  13. package/src/Passes/AIUpscaler.js +2 -1
  14. package/src/Passes/OIDNDenoiser.js +3 -6
  15. package/src/PathTracerApp.js +290 -19
  16. package/src/Processor/ArchiveCache.js +120 -0
  17. package/src/Processor/ArchiveReader.js +179 -32
  18. package/src/Processor/AssetLoader.js +514 -76
  19. package/src/Processor/AtmosphereModel.js +465 -0
  20. package/src/Processor/BVHBuilder.js +4 -1
  21. package/src/Processor/BVHLeafFold.js +100 -0
  22. package/src/Processor/BVHRefitter.js +98 -214
  23. package/src/Processor/ChunkedRecords.js +189 -4
  24. package/src/Processor/EmissiveTriangleBuilder.js +8 -0
  25. package/src/Processor/GeometryExtractor.js +238 -40
  26. package/src/Processor/InstanceTable.js +55 -37
  27. package/src/Processor/KernelManager.js +4 -1
  28. package/src/Processor/PBRT/PBRTCurves.js +104 -27
  29. package/src/Processor/PBRT/PBRTParser.js +132 -22
  30. package/src/Processor/PBRT/PBRTSceneBuilder.js +192 -49
  31. package/src/Processor/PBRT/buffers.js +27 -0
  32. package/src/Processor/PBRT/index.js +55 -15
  33. package/src/Processor/PackedRayBuffer.js +10 -13
  34. package/src/Processor/ParallelBVHBuilder.js +36 -15
  35. package/src/Processor/PhysicalSky.js +308 -0
  36. package/src/Processor/QueueManager.js +1 -0
  37. package/src/Processor/SceneProcessor.js +1132 -181
  38. package/src/Processor/SplitBLAS.js +249 -0
  39. package/src/Processor/SunPosition.js +41 -0
  40. package/src/Processor/TextureCreator.js +21 -0
  41. package/src/Processor/Workers/AIUpscalerWorker.js +79 -52
  42. package/src/Processor/Workers/BVHWorker.js +17 -13
  43. package/src/Processor/ZipReader.js +207 -0
  44. package/src/RenderSettings.js +38 -0
  45. package/src/SceneState/SceneState.js +367 -0
  46. package/src/SceneState/portable.js +52 -0
  47. package/src/Stages/NormalDepth.js +7 -6
  48. package/src/Stages/PathTracer.js +108 -4
  49. package/src/Stages/PathTracerStage.js +251 -104
  50. package/src/Storage/BLASCache.js +190 -0
  51. package/src/Storage/CDFCache.js +77 -0
  52. package/src/Storage/DownloadCache.js +266 -0
  53. package/src/Storage/GeometrySpill.js +217 -0
  54. package/src/Storage/SceneGraphCodec.js +503 -0
  55. package/src/Storage/SpillStore.js +112 -0
  56. package/src/Storage/StorageManager.js +934 -0
  57. package/src/Storage/StorageOps.js +137 -0
  58. package/src/Storage/StorageWorker.js +37 -0
  59. package/src/Storage/events.js +29 -0
  60. package/src/Storage/identity.js +77 -0
  61. package/src/Storage/index.js +9 -0
  62. package/src/Storage/inlineTransport.js +24 -0
  63. package/src/Storage/locks.js +99 -0
  64. package/src/Storage/openStorage.js +87 -0
  65. package/src/Storage/sceneCachePolicy.js +12 -0
  66. package/src/Storage/shared.js +9 -0
  67. package/src/Storage/transport.js +62 -0
  68. package/src/TSL/Atmosphere.js +684 -0
  69. package/src/TSL/BVHTraversal.js +288 -239
  70. package/src/TSL/Common.js +11 -2
  71. package/src/TSL/Displacement.js +6 -6
  72. package/src/TSL/EmissiveSampling.js +5 -5
  73. package/src/TSL/EnvironmentCDF.js +176 -0
  74. package/src/TSL/GenerateKernel.js +3 -3
  75. package/src/TSL/HitFacet.js +4 -4
  76. package/src/TSL/LightsDirect.js +8 -8
  77. package/src/TSL/LightsSampling.js +55 -37
  78. package/src/TSL/Random.js +1 -0
  79. package/src/TSL/ShadeKernel.js +75 -19
  80. package/src/TSL/Sun.js +40 -0
  81. package/src/TSL/TextureSampling.js +6 -7
  82. package/src/index.js +18 -0
  83. package/src/managers/CameraManager.js +169 -1
  84. package/src/managers/EnvironmentManager.js +263 -33
  85. package/src/managers/GoboManager.js +19 -8
  86. package/src/managers/IESManager.js +3 -3
  87. package/src/managers/LightManager.js +98 -5
  88. package/src/managers/MaterialDataManager.js +22 -2
  89. package/src/managers/TransformManager.js +26 -0
  90. package/src/managers/UniformManager.js +5 -3
  91. package/src/managers/VideoRenderManager.js +3 -1
  92. package/src/managers/timeline/CameraTrack.js +22 -0
  93. package/src/managers/timeline/TimelineManager.js +14 -0
  94. package/src/version.js +3 -0
  95. package/src/Processor/ProceduralSky.js +0 -291
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Streaming reader for .tar.gz / .tgz / .tar archives.
3
3
  *
4
- * ZIP is random-access and fflate's unzipSync is fine for it, but a gzipped tar is a
4
+ * ZIP is random-access (see ZipReader.js), but a gzipped tar is a
5
5
  * single compressed stream: the only way to reach the last entry is to decompress
6
6
  * everything before it. Holding that in memory is not an option — the pbrt-v4 Moana
7
7
  * archive is 5.9 GB compressed and 29 GB unpacked — so entries are decoded one at a
@@ -97,6 +97,38 @@ function paxPath( bytes ) {
97
97
 
98
98
  }
99
99
 
100
+ const paddedSize = size => size + ( ( BLOCK - ( size % BLOCK ) ) % BLOCK );
101
+
102
+ const isSpecialType = type => type === 'L' || type === 'x' || type === 'X';
103
+
104
+ function parseHeader( h ) {
105
+
106
+ const prefix = fieldString( h, 345, 155 );
107
+ const raw = fieldString( h, 0, 100 );
108
+ return {
109
+ type: String.fromCharCode( h[ 156 ] || 0x30 ),
110
+ size: fieldNumber( h, 124, 12 ),
111
+ name: prefix ? `${prefix}/${raw}` : raw,
112
+ };
113
+
114
+ }
115
+
116
+ /** Normalised path of a regular file entry, or null for directories, links and the rest. */
117
+ function regularPath( type, name ) {
118
+
119
+ if ( type === '5' || type === 'g' || type === 'K' || name.endsWith( '/' ) ) return null;
120
+ if ( type !== '0' && type !== ' ' ) return null;
121
+ return normalizeTarPath( name ) || null;
122
+
123
+ }
124
+
125
+ function isZeroBlock( h ) {
126
+
127
+ for ( let i = 0; i < BLOCK; i ++ ) if ( h[ i ] !== 0 ) return false;
128
+ return true;
129
+
130
+ }
131
+
100
132
  /**
101
133
  * Pull-free tar parser: chunks are pushed in as they decompress, and entry bodies are
102
134
  * copied straight out of them so a skipped entry never allocates.
@@ -150,8 +182,8 @@ class TarStream {
150
182
  if ( this._headerLen === BLOCK ) {
151
183
 
152
184
  this._headerLen = 0;
153
- this._readHeader();
154
185
  this._bodyStart = base + i; // body begins right after the header block
186
+ this._readHeader();
155
187
 
156
188
  }
157
189
 
@@ -210,21 +242,19 @@ class TarStream {
210
242
 
211
243
  }
212
244
 
213
- const type = String.fromCharCode( h[ 156 ] || 0x30 );
214
- const size = fieldNumber( h, 124, 12 );
215
- const prefix = fieldString( h, 345, 155 );
216
- const raw = fieldString( h, 0, 100 );
217
- const name = this._pendingName ?? ( prefix ? `${prefix}/${raw}` : raw );
245
+ const { type, size, name: headerName } = parseHeader( h );
246
+ const name = this._pendingName ?? headerName;
218
247
  this._pendingName = null;
219
248
 
220
249
  this._size = size;
221
250
  this._copied = 0;
222
- this._remaining = size + ( ( BLOCK - ( size % BLOCK ) ) % BLOCK );
251
+ this._remaining = paddedSize( size );
223
252
  this._dst = null;
224
253
  this._special = null;
254
+ this._indexed = false;
225
255
  this._state = this._remaining > 0 ? 'body' : 'header';
226
256
 
227
- if ( type === 'L' || type === 'x' || type === 'X' ) {
257
+ if ( isSpecialType( type ) ) {
228
258
 
229
259
  this._special = type === 'L' ? 'longname' : 'pax';
230
260
  this._dst = new Uint8Array( size );
@@ -232,30 +262,29 @@ class TarStream {
232
262
 
233
263
  }
234
264
 
235
- if ( type === '5' || type === 'g' || type === 'K' || name.endsWith( '/' ) ) return;
236
- if ( type !== '0' && type !== ' ' ) return;
237
-
238
- const path = normalizeTarPath( name );
265
+ const path = regularPath( type, name );
239
266
  if ( ! path ) return;
240
267
 
241
268
  this.listing.push( { path, size } );
269
+ this._indexed = this.filter ? this.filter( path, size ) : true;
242
270
 
243
- const wanted = this.filter ? this.filter( path, size ) : true;
244
- if ( ! wanted ) return;
271
+ if ( this._indexed && ! ( this.retain && ! this.retain( path, size ) ) ) {
245
272
 
246
- this._indexed = true;
273
+ if ( this.retainedBytes + size > this.byteBudget ) {
247
274
 
248
- if ( this.retain && ! this.retain( path, size ) ) return;
275
+ this.truncated = true;
249
276
 
250
- if ( this.retainedBytes + size > this.byteBudget ) {
277
+ } else {
251
278
 
252
- this.truncated = true;
253
- return;
279
+ this._dst = new Uint8Array( size );
280
+ this.retainedBytes += size;
281
+
282
+ }
254
283
 
255
284
  }
256
285
 
257
- this._dst = new Uint8Array( size );
258
- this.retainedBytes += size;
286
+ // An empty file has no body block, so nothing else would finish it.
287
+ if ( this._remaining === 0 ) this._endBody();
259
288
 
260
289
  }
261
290
 
@@ -399,23 +428,132 @@ export async function readTarGz( source, options = {} ) {
399
428
 
400
429
  }
401
430
 
431
+ const WINDOW_BYTES = 1 << 20;
432
+
402
433
  /**
403
- * A seekable view over an uncompressed .tar: entries are indexed on one streaming pass and read
404
- * back on demand from the source, so the archive is never resident.
434
+ * Lists every regular file of a seekable .tar with its body offset, reading only the headers:
435
+ * each entry's body is skipped by seeking, so a 7 GB archive of large files costs a few
436
+ * thousand small reads instead of a full pass.
437
+ * @param {Blob|File} source
438
+ * @returns {Promise<Array<{path:string, size:number, offset:number}>>}
439
+ */
440
+ export async function indexTarHeaders( source, { onProgress = null } = {} ) {
441
+
442
+ const size = source.size;
443
+ const listing = [];
444
+ let window = null;
445
+ let windowStart = 0;
446
+ let pendingName = null;
447
+ let pos = 0;
448
+ let nextReport = 0;
449
+
450
+ const bytesAt = async ( at, n ) => {
451
+
452
+ if ( window && at >= windowStart && at + n <= windowStart + window.length ) {
453
+
454
+ return window.subarray( at - windowStart, at - windowStart + n );
455
+
456
+ }
457
+
458
+ const end = Math.min( size, at + Math.max( n, WINDOW_BYTES ) );
459
+ window = new Uint8Array( await source.slice( at, end ).arrayBuffer() );
460
+ windowStart = at;
461
+ return window.subarray( 0, n );
462
+
463
+ };
464
+
465
+ while ( pos + BLOCK <= size ) {
466
+
467
+ const h = await bytesAt( pos, BLOCK );
468
+ if ( isZeroBlock( h ) ) break;
469
+
470
+ const { type, size: bodySize, name: headerName } = parseHeader( h );
471
+ const name = pendingName ?? headerName;
472
+ pendingName = null;
473
+ const bodyStart = pos + BLOCK;
474
+
475
+ if ( isSpecialType( type ) ) {
476
+
477
+ const body = await bytesAt( bodyStart, bodySize );
478
+ pendingName = type === 'L' ? fieldString( body, 0, body.length ) : paxPath( body );
479
+
480
+ } else {
481
+
482
+ const path = regularPath( type, name );
483
+ if ( path ) listing.push( { path, size: bodySize, offset: bodyStart } );
484
+
485
+ }
486
+
487
+ pos = bodyStart + paddedSize( bodySize );
488
+
489
+ if ( onProgress && pos >= nextReport ) {
490
+
491
+ nextReport = pos + ( 256 << 20 );
492
+ onProgress( { entries: listing.length, bytes: pos } );
493
+
494
+ }
495
+
496
+ }
497
+
498
+ return listing;
499
+
500
+ }
501
+
502
+ /**
503
+ * Indexes a tar stream as it goes by — for writing a decompressing archive to disk and knowing
504
+ * where every entry landed without a second pass.
505
+ */
506
+ export function createTarIndexer() {
507
+
508
+ const tar = new TarStream( { retain: () => false } );
509
+ return {
510
+ push: chunk => tar.push( chunk ),
511
+ finish: () => {
512
+
513
+ tar.end();
514
+ return tar.listing.filter( e => e.offset !== undefined );
515
+
516
+ },
517
+ };
518
+
519
+ }
520
+
521
+ /**
522
+ * A seekable view over an uncompressed .tar: entries are indexed and read back on demand from
523
+ * the source, so the archive is never resident.
405
524
  *
406
- * Only for `.tar` over a Blob/File — a gzip stream cannot be seeked, and a zip is already read
407
- * whole by fflate.
525
+ * Only for `.tar` over a Blob/File — a gzip stream cannot be seeked.
408
526
  *
409
527
  * @param {Blob|File} source
410
528
  * @param {object} [options] - `filter` and `retain` as in readTar
411
- * @returns {Promise<{entries, listing, read: (path:string)=>Promise<Uint8Array|null>, truncated}>}
529
+ * @param {{listing: Array}} [options.index] - a saved index (`result.index`): skips the walk
530
+ * @param {boolean} [options.headersOnly] - index by seeking between headers; nothing is retained
531
+ * @returns {Promise<{entries, listing, read: (path:string)=>Promise<Uint8Array|null>, truncated,
532
+ * index: ?{v:number, listing:Array}}>}
412
533
  */
413
534
  export async function openTar( source, options = {} ) {
414
535
 
415
- const tar = new TarStream( { ...options } );
416
- await forEachSlice( source, slice => tar.push( slice ) );
417
- tar.end();
418
- const { entries, listing, retainedBytes, truncated } = tar.result();
536
+ const { index = null, headersOnly = false, onProgress = null, ...streamOptions } = options;
537
+
538
+ let entries, listing, retainedBytes, truncated, full = null;
539
+
540
+ if ( index || headersOnly ) {
541
+
542
+ full = index?.listing ?? await indexTarHeaders( source, { onProgress } );
543
+ const { filter } = streamOptions;
544
+ listing = full.map( e => ( ! filter || filter( e.path, e.size ) ? { ...e } : { path: e.path, size: e.size } ) );
545
+ entries = Object.create( null );
546
+ retainedBytes = 0;
547
+ truncated = false;
548
+
549
+ } else {
550
+
551
+ const tar = new TarStream( { ...streamOptions } );
552
+ await forEachSlice( source, slice => tar.push( slice ) );
553
+ tar.end();
554
+ ( { entries, listing, retainedBytes, truncated } = tar.result() );
555
+
556
+ }
419
557
 
420
558
  const byPath = new Map();
421
559
  for ( const e of listing ) if ( e.offset !== undefined ) byPath.set( e.path, e );
@@ -429,7 +567,16 @@ export async function openTar( source, options = {} ) {
429
567
 
430
568
  };
431
569
 
432
- return { entries, listing, read, retainedBytes, truncated, indexed: byPath.size };
570
+ const readHead = async ( path, bytes ) => {
571
+
572
+ if ( entries[ path ] ) return entries[ path ].subarray( 0, bytes );
573
+ const e = byPath.get( path );
574
+ if ( ! e ) return null;
575
+ return new Uint8Array( await source.slice( e.offset, e.offset + Math.min( e.size, bytes ) ).arrayBuffer() );
576
+
577
+ };
578
+
579
+ return { entries, listing, read, readHead, retainedBytes, truncated, indexed: byPath.size, index: full ? { v: 1, listing: full } : null };
433
580
 
434
581
  }
435
582