rayzee 11.4.0 → 11.6.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.
- package/README.md +1 -0
- package/dist/{ArchiveImporter-Cgyx5AF7.js → ArchiveImporter-iofnC8zB.js} +2 -2
- package/dist/{BidirectionalIntegrator-BKF-cwH2.js → BidirectionalIntegrator-CqAilt2I.js} +289 -289
- package/dist/{EngineEvents-Ci8dVWCP.js → EngineEvents-CLckhYbL.js} +1 -0
- package/dist/{NeuralRetouch-C3Q2XqbF.js → NeuralRetouch-DFI4pOjO.js} +2 -2
- package/dist/{NeuralSuperRes-DV5TtURP.js → NeuralSuperRes-ChCiiilS.js} +3 -3
- package/dist/{PathTracer-D3MvEaZK.js → PathTracer-BX4sJLx7.js} +3194 -3162
- package/dist/{PhysicalSky-CY4jiz6a.js → PhysicalSky-Biv39eTA.js} +1 -1
- package/dist/{RayzeeRenderer-D23m6NqG.js → RayzeeRenderer-D8XRKU3A.js} +406 -437
- package/dist/{ToneMapGPU-CTDBvmmS.js → ToneMapGPU-sAs8wdgI.js} +14 -1
- package/dist/addons/archives.es.js +1 -1
- package/dist/addons/bidirectional.es.js +1 -1
- package/dist/addons/physical-sky.es.js +1 -1
- package/dist/rayzee-core.es.js +5 -5
- package/dist/rayzee.es.js +544 -460
- package/dist/rayzee.umd.js +63 -55
- package/dist/{sceneCachePolicy-AKOEu2lf.js → sceneCachePolicy-W5PLbzuR.js} +2 -2
- package/package.json +2 -2
- package/src/EngineEvents.js +2 -0
- package/src/Passes/AIUpscaler.js +15 -12
- package/src/Passes/OIDNDenoiser.js +106 -98
- package/src/PathTracerApp.js +2 -2
- package/src/Processor/TextureReadback.js +18 -1
- package/src/Processor/ToneMapGPU.js +22 -3
- package/src/RayzeeRenderer.js +4 -4
- package/src/Stages/LocalExposure.js +25 -2
- package/src/Stages/PathTracer.js +2 -10
- package/src/managers/DenoisingManager.js +97 -19
|
@@ -495,7 +495,8 @@ export class LocalExposure extends RenderStage {
|
|
|
495
495
|
|
|
496
496
|
/**
|
|
497
497
|
* The gain for a tone-mapping pass outside three.js (`PackedToneMapper`'s `gain`), or null before the
|
|
498
|
-
* first build. `cpu()` reads the grid back for the CPU tone map
|
|
498
|
+
* first build. `cpu()` reads the grid back for the CPU tone map; `copyTo( device )` copies it to another
|
|
499
|
+
* GPU device (the neural models' own).
|
|
499
500
|
*/
|
|
500
501
|
toneGain() {
|
|
501
502
|
|
|
@@ -508,10 +509,12 @@ export class LocalExposure extends RenderStage {
|
|
|
508
509
|
this._paramsBuffer ??= backend.device.createBuffer( { label: 'local-exposure-params', size: 64, usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST } );
|
|
509
510
|
backend.device.queue.writeBuffer( this._paramsBuffer, 0, this._params );
|
|
510
511
|
const params = this._params.slice();
|
|
512
|
+
const read = () => Promise.all( [ this.renderer.getArrayBufferAsync( this._grid.value ), this.renderer.getArrayBufferAsync( this._blur.value ) ] );
|
|
511
513
|
|
|
512
514
|
return {
|
|
513
515
|
key: 'local-exposure',
|
|
514
516
|
wgsl: LOCAL_EXPOSURE_WGSL,
|
|
517
|
+
device: backend.device,
|
|
515
518
|
entries: [
|
|
516
519
|
{ binding: 0, resource: { buffer: grid } },
|
|
517
520
|
{ binding: 1, resource: { buffer: blur } },
|
|
@@ -519,11 +522,31 @@ export class LocalExposure extends RenderStage {
|
|
|
519
522
|
],
|
|
520
523
|
cpu: async () => {
|
|
521
524
|
|
|
522
|
-
const [ g, b ] = await
|
|
525
|
+
const [ g, b ] = await read();
|
|
523
526
|
const gridData = new Float32Array( g ), blurData = new Float32Array( b );
|
|
524
527
|
return ( u, v, lum, logExposure ) => localExposureGain( params, gridData, blurData, u, v, lum, logExposure );
|
|
525
528
|
|
|
526
529
|
},
|
|
530
|
+
copyTo: async device => {
|
|
531
|
+
|
|
532
|
+
const [ g, b ] = await read();
|
|
533
|
+
const buffers = [[ g, GPUBufferUsage.STORAGE ], [ b, GPUBufferUsage.STORAGE ], [ params, GPUBufferUsage.UNIFORM ]].map( ( [ data, usage ] ) => {
|
|
534
|
+
|
|
535
|
+
const buffer = device.createBuffer( { label: 'local-exposure-copy', size: data.byteLength, usage: usage | GPUBufferUsage.COPY_DST } );
|
|
536
|
+
device.queue.writeBuffer( buffer, 0, data );
|
|
537
|
+
return buffer;
|
|
538
|
+
|
|
539
|
+
} );
|
|
540
|
+
|
|
541
|
+
return {
|
|
542
|
+
key: 'local-exposure',
|
|
543
|
+
wgsl: LOCAL_EXPOSURE_WGSL,
|
|
544
|
+
device,
|
|
545
|
+
entries: buffers.map( ( buffer, binding ) => ( { binding, resource: { buffer } } ) ),
|
|
546
|
+
destroy: () => buffers.forEach( buffer => buffer.destroy() ),
|
|
547
|
+
};
|
|
548
|
+
|
|
549
|
+
},
|
|
527
550
|
};
|
|
528
551
|
|
|
529
552
|
}
|
package/src/Stages/PathTracer.js
CHANGED
|
@@ -28,6 +28,7 @@ import {
|
|
|
28
28
|
} from '../TSL/SortGlobalKernels.js';
|
|
29
29
|
import { ENGINE_DEFAULTS } from '../EngineDefaults.js';
|
|
30
30
|
import { MAX_STORAGE_TEXTURE_SIZE } from '../Processor/StorageTexturePool.js';
|
|
31
|
+
import { readPixels } from '../Processor/TextureReadback.js';
|
|
31
32
|
import { ISSUE_CODES } from '../EngineIssues.js';
|
|
32
33
|
import { createLogger, fmt } from '../utils/Logger.js';
|
|
33
34
|
import { deviceMemoryGB } from '../Processor/HostMemory.js';
|
|
@@ -758,16 +759,7 @@ export class PathTracer extends PathTracerStage {
|
|
|
758
759
|
const height = pool.renderHeight;
|
|
759
760
|
const pixels = width * height;
|
|
760
761
|
|
|
761
|
-
const readAttachment =
|
|
762
|
-
|
|
763
|
-
const padded = await this.renderer.readRenderTargetPixelsAsync( pool.readTarget, 0, 0, width, height, index );
|
|
764
|
-
const stride = Math.ceil( width * 16 / 256 ) * 64;
|
|
765
|
-
if ( stride === width * 4 ) return new Float32Array( padded.buffer, padded.byteOffset, pixels * 4 ).slice();
|
|
766
|
-
const tight = new Float32Array( pixels * 4 );
|
|
767
|
-
for ( let y = 0; y < height; y ++ ) tight.set( padded.subarray( y * stride, y * stride + width * 4 ), y * width * 4 );
|
|
768
|
-
return tight;
|
|
769
|
-
|
|
770
|
-
};
|
|
762
|
+
const readAttachment = index => readPixels( this.renderer, pool.readTarget, width, height, index );
|
|
771
763
|
|
|
772
764
|
const readBuffer = async ( attr, Type ) => attr ? new Type( await this.renderer.getArrayBufferAsync( attr, null, 0, pixels * 4 ) ) : null;
|
|
773
765
|
const aux = this._auxGBufferEnabled && this._auxSamples > 0;
|
|
@@ -137,6 +137,11 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
137
137
|
this._retouch = null;
|
|
138
138
|
this._superResModule = null;
|
|
139
139
|
this._neuralPostBusy = false;
|
|
140
|
+
// The finished render's post passes: its guard, the run in flight, a queued rerun, and a cancel.
|
|
141
|
+
this._postIsStillComplete = null;
|
|
142
|
+
this._postRun = null;
|
|
143
|
+
this._postRedo = null;
|
|
144
|
+
this._postCancelled = false;
|
|
140
145
|
|
|
141
146
|
// The tier the finished image uses. The loaded tier is not always this one: while the
|
|
142
147
|
// image is still accumulating we run a cheaper model (see previewQuality).
|
|
@@ -192,6 +197,7 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
192
197
|
this._denoiserEndHandler = null;
|
|
193
198
|
this._denoiserTileHandler = null;
|
|
194
199
|
this._denoiserErrorHandler = null;
|
|
200
|
+
this._denoiserLoadHandler = null;
|
|
195
201
|
this._upscalerResChangedHandler = null;
|
|
196
202
|
this._upscalerStartHandler = null;
|
|
197
203
|
this._upscalerProgressHandler = null;
|
|
@@ -372,6 +378,12 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
372
378
|
this.denoiser.addEventListener( 'tileProgress', this._denoiserTileHandler );
|
|
373
379
|
this.denoiser.addEventListener( 'error', this._denoiserErrorHandler );
|
|
374
380
|
|
|
381
|
+
// 'error' too: a failed load never sends 'loaded'. The first load starts inside the constructor, before these listen.
|
|
382
|
+
this._denoiserLoadHandler = e =>
|
|
383
|
+
this.dispatchEvent( { type: EngineEvents.DENOISER_LOADING, loading: e.type === 'loading' } );
|
|
384
|
+
for ( const type of [ 'loading', 'loaded', 'error' ] ) this.denoiser.addEventListener( type, this._denoiserLoadHandler );
|
|
385
|
+
if ( this.denoiser.state?.isLoading ) this.dispatchEvent( { type: EngineEvents.DENOISER_LOADING, loading: true } );
|
|
386
|
+
|
|
375
387
|
}
|
|
376
388
|
|
|
377
389
|
/**
|
|
@@ -1148,6 +1160,7 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
1148
1160
|
/** Turns the neural-rendering (detail) pass on or off, and sets its appearance controls. */
|
|
1149
1161
|
setNeuralRendering( enabled, settings = null ) {
|
|
1150
1162
|
|
|
1163
|
+
const changed = this.neuralRendering !== !! enabled;
|
|
1151
1164
|
this.neuralRendering = !! enabled;
|
|
1152
1165
|
if ( settings ) this.neuralRenderingSettings = { ...this.neuralRenderingSettings, ...settings };
|
|
1153
1166
|
if ( ! this.neuralRendering ) {
|
|
@@ -1157,6 +1170,8 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
1157
1170
|
|
|
1158
1171
|
}
|
|
1159
1172
|
|
|
1173
|
+
if ( changed ) this._redoPostPasses();
|
|
1174
|
+
|
|
1160
1175
|
}
|
|
1161
1176
|
|
|
1162
1177
|
_releaseNeuralRetouch() {
|
|
@@ -1167,14 +1182,8 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
1167
1182
|
}
|
|
1168
1183
|
|
|
1169
1184
|
/**
|
|
1170
|
-
* The
|
|
1171
|
-
*
|
|
1172
|
-
*
|
|
1173
|
-
* Order is forced by the models. Super resolution hands back light that can be fed onward; the
|
|
1174
|
-
* detail pass writes an `rgba8unorm` texture with no `COPY_SRC`, so nothing can read its result
|
|
1175
|
-
* and it has to be last — and it presents in its own display space rather than the engine's tone
|
|
1176
|
-
* curve. Which shape super resolution returns therefore depends on what follows it: packed
|
|
1177
|
-
* halves when the detail pass is next, display bytes when it is the end of the chain.
|
|
1185
|
+
* The post-chain over the picture the closing denoise just produced: the detail pass at render size,
|
|
1186
|
+
* then the chosen upscaler (neural super resolution or the ONNX one), either or both.
|
|
1178
1187
|
*
|
|
1179
1188
|
* Deliberately fire-and-forget: the render is already finished and a failure must not break it.
|
|
1180
1189
|
*/
|
|
@@ -1182,6 +1191,7 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
1182
1191
|
|
|
1183
1192
|
const wantSR = this.upscaler?.enabled && this.upscalerBackend === 'neural';
|
|
1184
1193
|
const wantNR = this.neuralRendering;
|
|
1194
|
+
const wantESRGAN = this.upscaler?.enabled && ! wantSR;
|
|
1185
1195
|
if ( ! wantSR && ! wantNR ) return;
|
|
1186
1196
|
|
|
1187
1197
|
// A second completion can land while the first pass is still in flight — the models are
|
|
@@ -1230,7 +1240,12 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
1230
1240
|
|
|
1231
1241
|
}
|
|
1232
1242
|
|
|
1233
|
-
if ( ! wantSR && ! runNR )
|
|
1243
|
+
if ( ! wantSR && ! runNR ) {
|
|
1244
|
+
|
|
1245
|
+
if ( wantESRGAN && ! this._postCancelled ) await this.upscaler.start();
|
|
1246
|
+
return;
|
|
1247
|
+
|
|
1248
|
+
}
|
|
1234
1249
|
|
|
1235
1250
|
// Must be the effective value, not the settings one: AutoExposure overwrites
|
|
1236
1251
|
// `renderer.toneMappingExposure` every frame and never touches settings, so reading
|
|
@@ -1291,6 +1306,15 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
1291
1306
|
|
|
1292
1307
|
}
|
|
1293
1308
|
|
|
1309
|
+
if ( this._postRedo || this._postCancelled ) return;
|
|
1310
|
+
|
|
1311
|
+
if ( wantESRGAN ) {
|
|
1312
|
+
|
|
1313
|
+
await this.upscaler.start( new ImageData( image.rgba8, image.width, image.height ) );
|
|
1314
|
+
return;
|
|
1315
|
+
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1294
1318
|
sr.presentRGBA8( this.upscalerCanvas, image.rgba8, image.width, image.height );
|
|
1295
1319
|
|
|
1296
1320
|
if ( ! isStillComplete() ) {
|
|
@@ -1360,10 +1384,61 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
1360
1384
|
|
|
1361
1385
|
}
|
|
1362
1386
|
|
|
1387
|
+
/** The neural chain or the ONNX upscaler over the finished render, as the switches ask. */
|
|
1388
|
+
_runPostPasses( isStillComplete ) {
|
|
1389
|
+
|
|
1390
|
+
this._postIsStillComplete = isStillComplete;
|
|
1391
|
+
this._postCancelled = false;
|
|
1392
|
+
|
|
1393
|
+
// The neural chain owns the overlay canvas when it runs, and hands its result to the ONNX upscaler.
|
|
1394
|
+
if ( this.neuralRendering || ( this.upscaler?.enabled && this.upscalerBackend === 'neural' ) ) {
|
|
1395
|
+
|
|
1396
|
+
this._postRun = this._runNeuralPost( isStillComplete );
|
|
1397
|
+
|
|
1398
|
+
} else {
|
|
1399
|
+
|
|
1400
|
+
this._postRun = this.upscaler?.enabled ? this.upscaler.start() : null;
|
|
1401
|
+
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1404
|
+
}
|
|
1405
|
+
|
|
1406
|
+
/** Runs the post passes again on a finished render whose switches changed, once the run in flight ends. */
|
|
1407
|
+
_redoPostPasses() {
|
|
1408
|
+
|
|
1409
|
+
const isStillComplete = this._postIsStillComplete;
|
|
1410
|
+
// No chain yet: the closing denoise is still running and the chain reads the switches when it starts.
|
|
1411
|
+
if ( ! isStillComplete?.() || this._postRedo ) return;
|
|
1412
|
+
|
|
1413
|
+
this.upscaler?.abort();
|
|
1414
|
+
this._postCancelled = false;
|
|
1415
|
+
this._postRedo = Promise.resolve( this._postRun ).catch( () => {} ).then( () => {
|
|
1416
|
+
|
|
1417
|
+
this._postRedo = null;
|
|
1418
|
+
if ( this._postCancelled || this._postIsStillComplete !== isStillComplete || ! isStillComplete() ) return;
|
|
1419
|
+
this._restoreRenderDisplay();
|
|
1420
|
+
this._runPostPasses( isStillComplete );
|
|
1421
|
+
|
|
1422
|
+
} );
|
|
1423
|
+
|
|
1424
|
+
}
|
|
1425
|
+
|
|
1426
|
+
/** Stops the post passes on the finished render, which stays on screen as rendered. The switches stay as they are. */
|
|
1427
|
+
cancelPostPasses() {
|
|
1428
|
+
|
|
1429
|
+
this._postCancelled = true;
|
|
1430
|
+
this.upscaler?.abort();
|
|
1431
|
+
this._restoreRenderDisplay();
|
|
1432
|
+
// A retouch in flight cannot be stopped, only discarded, and ends later.
|
|
1433
|
+
this.dispatchEvent( { type: EngineEvents.UPSCALING_END } );
|
|
1434
|
+
|
|
1435
|
+
}
|
|
1436
|
+
|
|
1363
1437
|
onRenderComplete( { isStillComplete } ) {
|
|
1364
1438
|
|
|
1365
1439
|
// Remove any stale completion-chain listener from a previous render cycle
|
|
1366
1440
|
this._cleanupCompletionListener();
|
|
1441
|
+
this._postIsStillComplete = null;
|
|
1367
1442
|
|
|
1368
1443
|
// What closes the render, if anything. A full pass at the chosen tier when that switch is
|
|
1369
1444
|
// on; otherwise, if OIDN owns the live view, one last cheap refresh — the cadence's last
|
|
@@ -1383,16 +1458,7 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
1383
1458
|
// denoise. Ordered after `_denoiserEndHandler`, which publishes the picture.
|
|
1384
1459
|
if ( closing ) this._onDisplayRefresh?.();
|
|
1385
1460
|
|
|
1386
|
-
|
|
1387
|
-
// exclusive. The neural chain also runs on its own when only its detail pass is on.
|
|
1388
|
-
if ( this.neuralRendering || ( this.upscaler?.enabled && this.upscalerBackend === 'neural' ) ) {
|
|
1389
|
-
|
|
1390
|
-
this._runNeuralPost( isStillComplete );
|
|
1391
|
-
return;
|
|
1392
|
-
|
|
1393
|
-
}
|
|
1394
|
-
|
|
1395
|
-
if ( this.upscaler?.enabled ) this.upscaler.start();
|
|
1461
|
+
this._runPostPasses( isStillComplete );
|
|
1396
1462
|
|
|
1397
1463
|
};
|
|
1398
1464
|
|
|
@@ -1467,6 +1533,7 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
1467
1533
|
|
|
1468
1534
|
// Remove stale completion-chain listener before aborting
|
|
1469
1535
|
this._cleanupCompletionListener();
|
|
1536
|
+
this._postIsStillComplete = null;
|
|
1470
1537
|
|
|
1471
1538
|
// The 2D canvas is the upscaler's alone: a reset means its enlarged result no longer
|
|
1472
1539
|
// describes anything, so the render canvas comes back.
|
|
@@ -1509,6 +1576,7 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
1509
1576
|
|
|
1510
1577
|
// Remove pending completion-chain listener
|
|
1511
1578
|
this._cleanupCompletionListener();
|
|
1579
|
+
this._postIsStillComplete = null;
|
|
1512
1580
|
// Owns a second GPUDevice plus 3 MB of weights, so it must not outlive the manager.
|
|
1513
1581
|
this._releaseNeuralUpscaler();
|
|
1514
1582
|
this._releaseNeuralRetouch();
|
|
@@ -1523,6 +1591,13 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
1523
1591
|
if ( this._denoiserEndHandler ) this.denoiser.removeEventListener( 'end', this._denoiserEndHandler );
|
|
1524
1592
|
if ( this._denoiserTileHandler ) this.denoiser.removeEventListener( 'tileProgress', this._denoiserTileHandler );
|
|
1525
1593
|
if ( this._denoiserErrorHandler ) this.denoiser.removeEventListener( 'error', this._denoiserErrorHandler );
|
|
1594
|
+
if ( this._denoiserLoadHandler ) {
|
|
1595
|
+
|
|
1596
|
+
for ( const type of [ 'loading', 'loaded', 'error' ] ) this.denoiser.removeEventListener( type, this._denoiserLoadHandler );
|
|
1597
|
+
if ( this.denoiser.state?.isLoading ) this.dispatchEvent( { type: EngineEvents.DENOISER_LOADING, loading: false } );
|
|
1598
|
+
|
|
1599
|
+
}
|
|
1600
|
+
|
|
1526
1601
|
this.denoiser.dispose();
|
|
1527
1602
|
this.denoiser = null;
|
|
1528
1603
|
|
|
@@ -1547,6 +1622,7 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
1547
1622
|
this._denoiserEndHandler = null;
|
|
1548
1623
|
this._denoiserTileHandler = null;
|
|
1549
1624
|
this._denoiserErrorHandler = null;
|
|
1625
|
+
this._denoiserLoadHandler = null;
|
|
1550
1626
|
this._upscalerResChangedHandler = null;
|
|
1551
1627
|
this._upscalerStartHandler = null;
|
|
1552
1628
|
this._upscalerProgressHandler = null;
|
|
@@ -1737,10 +1813,12 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
1737
1813
|
/** Enables or disables the AI upscaler. */
|
|
1738
1814
|
setUpscalerEnabled( enabled ) {
|
|
1739
1815
|
|
|
1816
|
+
const changed = !! this.upscaler && this.upscaler.enabled !== !! enabled;
|
|
1740
1817
|
if ( this.upscaler ) this.upscaler.enabled = enabled;
|
|
1741
1818
|
else if ( enabled ) this._recordNoOverlayCanvas( 'upscaler' );
|
|
1742
1819
|
// The enlarged picture describes a setting that is no longer on.
|
|
1743
1820
|
if ( ! enabled ) this._restoreRenderDisplay();
|
|
1821
|
+
if ( changed ) this._redoPostPasses();
|
|
1744
1822
|
|
|
1745
1823
|
}
|
|
1746
1824
|
|