rayzee 11.2.1 → 11.4.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 (76) hide show
  1. package/README.md +91 -34
  2. package/dist/ArchiveImporter-Cgyx5AF7.js +7860 -0
  3. package/dist/BidirectionalIntegrator-BKF-cwH2.js +954 -0
  4. package/dist/{BufferLayout-D_IBo2ci.js → BufferLayout-xPRH9jYD.js} +41 -5
  5. package/dist/{NeuralRetouch-Cr-otSW8.js → NeuralRetouch-C3Q2XqbF.js} +4 -3
  6. package/dist/{NeuralSuperRes-B7E3_M0t.js → NeuralSuperRes-DV5TtURP.js} +11 -5
  7. package/dist/{PathTracer-D6nbknj5.js → PathTracer-D3MvEaZK.js} +4384 -4618
  8. package/dist/{PhysicalSky-Dq5VSiCQ.js → PhysicalSky-CY4jiz6a.js} +2 -2
  9. package/dist/{RayzeeRenderer-DbjqO6v-.js → RayzeeRenderer-D23m6NqG.js} +486 -391
  10. package/dist/SolarLimb-bZE6y63S.js +762 -0
  11. package/dist/{ToneMapGPU-BOjpul7A.js → ToneMapGPU-CTDBvmmS.js} +31 -22
  12. package/dist/addons/archives.es.js +1 -1
  13. package/dist/addons/bidirectional.es.js +1 -1
  14. package/dist/addons/physical-sky.es.js +1 -1
  15. package/dist/rayzee-core.es.js +7 -7
  16. package/dist/rayzee.es.js +1327 -838
  17. package/dist/rayzee.umd.js +146 -134
  18. package/dist/sceneCachePolicy-AKOEu2lf.js +1602 -0
  19. package/package.json +1 -1
  20. package/src/EngineDefaults.js +2 -2
  21. package/src/Passes/AIUpscaler.js +2 -0
  22. package/src/PathTracerApp.js +126 -19
  23. package/src/Pipeline/CompletionTracker.js +7 -3
  24. package/src/Processor/ArchiveImporter.js +173 -94
  25. package/src/Processor/ArchiveReader.js +20 -23
  26. package/src/Processor/AssetLoader.js +48 -1
  27. package/src/Processor/BVHRefitter.js +109 -13
  28. package/src/Processor/BufferLayout.js +115 -0
  29. package/src/Processor/ChunkedRecords.js +3 -2
  30. package/src/Processor/EmissiveTriangleBuilder.js +6 -6
  31. package/src/Processor/GeometryExtractor.js +189 -79
  32. package/src/Processor/HostMemory.js +39 -9
  33. package/src/Processor/InstanceTable.js +714 -42
  34. package/src/Processor/PBRT/PBRTCurves.js +224 -6
  35. package/src/Processor/PBRT/PBRTMaterials.js +3 -0
  36. package/src/Processor/PBRT/PBRTSceneBuilder.js +82 -25
  37. package/src/Processor/PackedRayBuffer.js +5 -2
  38. package/src/Processor/SceneProcessor.js +747 -141
  39. package/src/Processor/TLASBuilder.js +32 -17
  40. package/src/Processor/ToneMapCPU.js +16 -4
  41. package/src/Processor/ToneMapGPU.js +30 -14
  42. package/src/Processor/USD/USDLayer.js +1149 -0
  43. package/src/Processor/USD/USDScene.js +1655 -0
  44. package/src/Processor/USD/USDStage.js +682 -0
  45. package/src/Processor/USD/USDText.js +674 -0
  46. package/src/Processor/USD/index.js +138 -0
  47. package/src/Processor/Workers/BVHRefitWorker.js +3 -3
  48. package/src/RayzeeRenderer.js +221 -33
  49. package/src/RenderSettings.js +4 -2
  50. package/src/Stages/AutoExposure.js +484 -494
  51. package/src/Stages/Compositor.js +27 -6
  52. package/src/Stages/LocalExposure.js +546 -0
  53. package/src/Stages/NormalDepth.js +7 -12
  54. package/src/Stages/PathTracer.js +18 -21
  55. package/src/Stages/PathTracerStage.js +282 -103
  56. package/src/Storage/GeometrySpill.js +46 -14
  57. package/src/Storage/SceneGraphCodec.js +17 -3
  58. package/src/Storage/SpillStore.js +9 -0
  59. package/src/TSL/BVHTraversal.js +183 -7
  60. package/src/TSL/Common.js +57 -13
  61. package/src/TSL/ShadeKernel.js +3 -2
  62. package/src/TSL/TextureSampling.js +11 -8
  63. package/src/TSL/patches.js +84 -0
  64. package/src/index.js +1 -0
  65. package/src/integrators/BidirectionalIntegrator.js +20 -2
  66. package/src/managers/DenoisingManager.js +15 -19
  67. package/src/managers/InteractionManager.js +19 -6
  68. package/src/managers/MaterialDataManager.js +22 -5
  69. package/src/managers/UniformManager.js +3 -0
  70. package/src/managers/VideoRenderManager.js +30 -4
  71. package/src/neural/NeuralRetouch.js +1 -0
  72. package/src/neural/NeuralSuperRes.js +6 -1
  73. package/dist/ArchiveImporter-D_x863yu.js +0 -5198
  74. package/dist/BidirectionalIntegrator-DmkxxEOR.js +0 -946
  75. package/dist/SolarLimb-CPaeZVwz.js +0 -721
  76. package/dist/sceneCachePolicy-C4-4qwt6.js +0 -485
@@ -94,9 +94,10 @@ export class TLASBuilder {
94
94
  */
95
95
  build( table ) {
96
96
 
97
- const aabbs = new Float64Array( table.count * 6 );
98
- table.writeWorldAABBs( aabbs );
99
- const built = this.buildStructure( aabbs, table.count );
97
+ const clustered = table.clusterCount > 0;
98
+ const aabbs = clustered ? table.clusterBounds : new Float64Array( table.entryCount * 6 );
99
+ if ( ! clustered ) table.writeEntryWorldAABBs( aabbs );
100
+ const built = this.buildStructure( aabbs, clustered ? table.clusterCount : table.entryCount );
100
101
  TLASBuilder.fillLeaves( built.data, built.nodeCount, table );
101
102
  return built;
102
103
 
@@ -235,22 +236,34 @@ export class TLASBuilder {
235
236
  */
236
237
  static fillLeaves( data, nodeCount, table ) {
237
238
 
238
- const world = table.world, src = table.sourceMesh;
239
- const blasOffset = table.tplBlasOffset, visible = table.visible, leafOf = table.tlasLeafIndex;
240
239
  const idx = bvhIndexView( data );
241
240
 
241
+ if ( table.clusterCount > 0 ) {
242
+
243
+ // Built over clusters: each leaf holds one, its copies' transforms in records (table.writeRecord).
244
+ for ( let node = 0; node < nodeCount; node ++ ) {
245
+
246
+ const o = node * FLOATS_PER_NODE;
247
+ if ( idx[ o + 3 ] === BVH_LEAF_MARKERS.BLAS_POINTER_LEAF ) table.writeClusterLeaf( data, idx, o, idx[ o + 1 ], table.clusterWorld, node );
248
+
249
+ }
250
+
251
+ return;
252
+
253
+ }
254
+
242
255
  for ( let node = 0; node < nodeCount; node ++ ) {
243
256
 
244
257
  const o = node * FLOATS_PER_NODE;
245
258
  if ( idx[ o + 3 ] !== BVH_LEAF_MARKERS.BLAS_POINTER_LEAF ) continue;
246
259
 
247
- const i = idx[ o + 1 ] & TLAS_PLACEMENT_MASK;
248
- idx[ o ] = blasOffset[ src[ i ] ];
249
- data[ o + 2 ] = visible[ i ] ? 1.0 : 0.0;
260
+ const e = idx[ o + 1 ] & TLAS_PLACEMENT_MASK;
261
+ idx[ o ] = table.entryRoot( e );
262
+ data[ o + 2 ] = table.entryVisible( e ) ? 1.0 : 0.0;
250
263
 
251
- TLASBuilder.writeLeafMatrix( data, idx, o, world, i );
264
+ TLASBuilder.writeLeafMatrix( data, idx, o, table, table.repOf( e ), e );
252
265
 
253
- leafOf[ i ] = node;
266
+ table.setLeafOf( e, node );
254
267
 
255
268
  }
256
269
 
@@ -261,25 +274,27 @@ export class TLASBuilder {
261
274
  * its own whenever a placement moves, so a rigid transform costs a matrix rather than a
262
275
  * rewrite of the geometry the placement may be sharing.
263
276
  *
264
- * Slot [1] is rewritten too: the placement index, with {@link TLAS_LEAF_IDENTITY} set when
265
- * the matrix is identity so traversal can skip the ray transform for that leaf.
277
+ * Slot [1] is rewritten too: the TLAS entry (the placement, unless placements are grouped), with
278
+ * {@link TLAS_LEAF_IDENTITY} set when the matrix is identity so traversal can skip the ray transform for that leaf.
266
279
  *
267
280
  * @param {Float32Array} data - the node buffer, or one chunk of it
268
281
  * @param {Uint32Array} idx - u32 view over the same memory as `data`
269
282
  * @param {number} off - float offset of the leaf within `data`
270
- * @param {Float32Array} world - the instance table's object-to-world column
271
- * @param {number} placement
283
+ * @param {import('./InstanceTable.js').InstanceTable} table
284
+ * @param {number} placement - whose transform the leaf carries
285
+ * @param {number} [entry] - the TLAS entry it stands for
272
286
  */
273
- static writeLeafMatrix( data, idx, off, world, placement ) {
287
+ static writeLeafMatrix( data, idx, off, table, placement, entry = placement ) {
274
288
 
275
289
  const inv = _inverseScratch;
276
- invertAffineInto( world, placement * 16, inv );
290
+ const row = table.matrixRow( placement ), world = table.rowArray;
291
+ invertAffineInto( world, row, inv );
277
292
 
278
293
  data[ off + 4 ] = inv[ 0 ]; data[ off + 5 ] = inv[ 4 ]; data[ off + 6 ] = inv[ 8 ]; data[ off + 7 ] = inv[ 12 ];
279
294
  data[ off + 8 ] = inv[ 1 ]; data[ off + 9 ] = inv[ 5 ]; data[ off + 10 ] = inv[ 9 ]; data[ off + 11 ] = inv[ 13 ];
280
295
  data[ off + 12 ] = inv[ 2 ]; data[ off + 13 ] = inv[ 6 ]; data[ off + 14 ] = inv[ 10 ]; data[ off + 15 ] = inv[ 14 ];
281
296
 
282
- idx[ off + 1 ] = ( placement | ( isIdentityAt( world, placement * 16 ) ? TLAS_LEAF_IDENTITY : 0 ) ) >>> 0;
297
+ idx[ off + 1 ] = ( entry | ( isIdentityAt( world, row ) ? TLAS_LEAF_IDENTITY : 0 ) ) >>> 0;
283
298
 
284
299
  }
285
300
 
@@ -128,21 +128,33 @@ export function applySaturation( out, saturation ) {
128
128
  * @param {number} options.toneMapping - a registered view transform id
129
129
  * @param {number} [options.saturation=1]
130
130
  * @param {boolean} [options.preserveAlpha=false]
131
+ * @param {{fn: function(number, number, number, number): number, width: number, height: number}} [options.pixelGain] -
132
+ * the twin of the GPU pass's `gain`: `fn( u, v, luminance, log2 exposure )` per pixel, before the curve
131
133
  * @returns {Uint8ClampedArray} RGBA bytes
132
134
  */
133
- export function toneMapToRGBA8( linear, { exposure, toneMapping, saturation = 1, preserveAlpha = false } ) {
135
+ export function toneMapToRGBA8( linear, { exposure, toneMapping, saturation = 1, preserveAlpha = false, pixelGain = null } ) {
134
136
 
135
137
  const curve = TONE_MAP_FNS.get( toneMapping ) ?? TONE_MAP_FNS.get( NoToneMapping );
136
138
  const gain = effectiveExposure( exposure, toneMapping );
137
139
  const encoded = isOutputEncoded( toneMapping );
138
140
  const out = new Uint8ClampedArray( linear.length );
139
141
  const scratch = [ 0, 0, 0 ];
142
+ const logExposure = Math.log2( exposure );
140
143
 
141
144
  for ( let i = 0; i < linear.length; i += 4 ) {
142
145
 
143
- scratch[ 0 ] = linear[ i ] * gain;
144
- scratch[ 1 ] = linear[ i + 1 ] * gain;
145
- scratch[ 2 ] = linear[ i + 2 ] * gain;
146
+ let g = gain;
147
+ if ( pixelGain ) {
148
+
149
+ const p = i >> 2, x = p % pixelGain.width, y = ( p - x ) / pixelGain.width;
150
+ const lum = linear[ i ] * 0.2126 + linear[ i + 1 ] * 0.7152 + linear[ i + 2 ] * 0.0722;
151
+ g *= pixelGain.fn( ( x + 0.5 ) / pixelGain.width, ( y + 0.5 ) / pixelGain.height, lum, logExposure );
152
+
153
+ }
154
+
155
+ scratch[ 0 ] = linear[ i ] * g;
156
+ scratch[ 1 ] = linear[ i + 1 ] * g;
157
+ scratch[ 2 ] = linear[ i + 2 ] * g;
146
158
 
147
159
  applySaturation( scratch, saturation );
148
160
  curve( scratch[ 0 ], scratch[ 1 ], scratch[ 2 ], 1.0, scratch );
@@ -88,7 +88,7 @@ fn rayzee_store( i: u32, linear: vec4<f32>, mapped: vec3<f32> ) {
88
88
 
89
89
  const BYTES_PER_PIXEL = { rgba8: 4, planar: 16 };
90
90
 
91
- const toneMapPassWGSL = ( transformWGSL, input, output ) => /* wgsl */ `
91
+ const toneMapPassWGSL = ( transformWGSL, input, output, gainWGSL ) => /* wgsl */ `
92
92
  struct Params {
93
93
  width: u32,
94
94
  height: u32,
@@ -104,6 +104,7 @@ ${SOURCES[ input ]}
104
104
 
105
105
  ${transformWGSL}
106
106
  ${OUTPUTS[ output ]}
107
+ ${gainWGSL ?? ''}
107
108
 
108
109
  @compute @workgroup_size(8, 8)
109
110
  fn main( @builtin(global_invocation_id) gid: vec3<u32> ) {
@@ -113,7 +114,9 @@ fn main( @builtin(global_invocation_id) gid: vec3<u32> ) {
113
114
  if ( params.flipY == 1u ) { srcY = params.height - 1u - gid.y; }
114
115
 
115
116
  let linear = rayzee_source( gid.x, srcY );
116
- rayzee_store( gid.y * params.width + gid.x, linear, rayzee_tone_map( linear.rgb, params.mode, params.exposure, params.saturation ) );
117
+ let uv = vec2<f32>( ( f32( gid.x ) + 0.5 ) / f32( params.width ), ( f32( gid.y ) + 0.5 ) / f32( params.height ) );
118
+ let rgb = linear.rgb${gainWGSL ? ' * rayzee_gain( uv, linear.rgb, params.exposure )' : ''};
119
+ rayzee_store( gid.y * params.width + gid.x, linear, rayzee_tone_map( rgb, params.mode, params.exposure, params.saturation ) );
117
120
  }
118
121
  `;
119
122
 
@@ -136,7 +139,7 @@ export class PackedToneMapper {
136
139
  this.output = output;
137
140
  this.width = 0;
138
141
  this.height = 0;
139
- this._pipeline = null;
142
+ this._pipelines = new Map();
140
143
  this._storage = null;
141
144
  this._map = null;
142
145
  this._params = null;
@@ -157,21 +160,31 @@ export class PackedToneMapper {
157
160
  * heard of. Without this the readback silently falls through to the clamp and a saved image
158
161
  * comes back untone-mapped.
159
162
  */
160
- _ensurePipeline() {
163
+ _ensurePipeline( gain = null ) {
161
164
 
162
165
  const { wgsl, bindings, version } = currentShader();
163
- if ( this._pipeline && this._shaderVersion === version ) return;
166
+ if ( this._shaderVersion !== version ) {
164
167
 
165
- this._bindings = bindings;
166
- this._shaderVersion = version;
167
- this._pipeline = this.device.createComputePipeline( {
168
+ this._pipelines.clear();
169
+ this._bindings = bindings;
170
+ this._shaderVersion = version;
171
+
172
+ }
173
+
174
+ const key = gain?.key ?? '';
175
+ let pipeline = this._pipelines.get( key );
176
+ if ( pipeline ) return pipeline;
177
+
178
+ pipeline = this.device.createComputePipeline( {
168
179
  label: this.label,
169
180
  layout: 'auto',
170
181
  compute: {
171
- module: this.device.createShaderModule( { label: this.label, code: toneMapPassWGSL( wgsl, this.input, this.output ) } ),
182
+ module: this.device.createShaderModule( { label: this.label, code: toneMapPassWGSL( wgsl, this.input, this.output, gain?.wgsl ) } ),
172
183
  entryPoint: 'main',
173
184
  },
174
185
  } );
186
+ this._pipelines.set( key, pipeline );
187
+ return pipeline;
175
188
 
176
189
  }
177
190
 
@@ -262,6 +275,8 @@ export class PackedToneMapper {
262
275
  * @param {number} [tone.saturation=1]
263
276
  * @param {boolean} [tone.flipY=false]
264
277
  * @param {boolean} [tone.preserveAlpha=false] - the source's alpha, rounded as the CPU rounds it; else 255
278
+ * @param {{key: string, wgsl: string, entries: GPUBindGroupEntry[]}} [tone.gain] - a per-pixel gain before the
279
+ * curve: WGSL defining `rayzee_gain( uv, linear, exposure ) -> f32` over bind group 1
265
280
  * @returns {Promise<Uint8ClampedArray>} RGBA bytes, `width * height * 4`
266
281
  */
267
282
  async toRGBA8( src, tone ) {
@@ -283,14 +298,14 @@ export class PackedToneMapper {
283
298
 
284
299
  }
285
300
 
286
- async _run( src, { exposure = 1, toneMapping = 0, saturation = 1, flipY = false, preserveAlpha = false } = {} ) {
301
+ async _run( src, { exposure = 1, toneMapping = 0, saturation = 1, flipY = false, preserveAlpha = false, gain = null } = {} ) {
287
302
 
288
303
  if ( this.disposed ) throw new Error( 'PackedToneMapper: disposed' );
289
304
  if ( ! this._storage ) throw new Error( 'PackedToneMapper: call ensureSize() first' );
290
305
 
291
306
  // A config can be loaded between two readbacks, so the registry is re-checked here rather
292
307
  // than only on resize.
293
- this._ensurePipeline();
308
+ const pipeline = this._ensurePipeline( gain );
294
309
  this._ensureTables();
295
310
 
296
311
  const { width, height } = this;
@@ -309,7 +324,7 @@ export class PackedToneMapper {
309
324
  .map( ( [ binding, held ] ) => ( { binding, resource: held.view } ) );
310
325
 
311
326
  const group = this.device.createBindGroup( {
312
- layout: this._pipeline.getBindGroupLayout( 0 ),
327
+ layout: pipeline.getBindGroupLayout( 0 ),
313
328
  entries: [
314
329
  ...tableEntries,
315
330
  { binding: 0, resource: this.input === 'texture' ? src.createView() : { buffer: src, size: width * height * 8 } },
@@ -320,8 +335,9 @@ export class PackedToneMapper {
320
335
 
321
336
  const encoder = this.device.createCommandEncoder( { label: this.label } );
322
337
  const pass = encoder.beginComputePass();
323
- pass.setPipeline( this._pipeline );
338
+ pass.setPipeline( pipeline );
324
339
  pass.setBindGroup( 0, group );
340
+ if ( gain ) pass.setBindGroup( 1, this.device.createBindGroup( { layout: pipeline.getBindGroupLayout( 1 ), entries: gain.entries } ) );
325
341
  pass.dispatchWorkgroups( Math.ceil( width / 8 ), Math.ceil( height / 8 ) );
326
342
  pass.end();
327
343
  encoder.copyBufferToBuffer( this._storage, 0, this._map, 0, bytes );
@@ -360,7 +376,7 @@ export class PackedToneMapper {
360
376
  this._releaseBuffers();
361
377
  for ( const held of this._tables.values() ) held.texture.destroy();
362
378
  this._tables.clear();
363
- this._pipeline = null;
379
+ this._pipelines.clear();
364
380
 
365
381
  }
366
382