rayzee 11.6.0 → 11.8.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 +26 -14
- package/dist/{ArchiveImporter-iofnC8zB.js → ArchiveImporter-_sJm5uaK.js} +1923 -1243
- package/dist/{BidirectionalIntegrator-CqAilt2I.js → BidirectionalIntegrator-Dzt4Z97x.js} +290 -289
- package/dist/{ColorManagement-oeEk7oSu.js → ColorManagement-30MfpHwQ.js} +1 -1
- package/dist/{EngineIssues-CIZnXHsF.js → EngineIssues-xljoXM0E.js} +18 -8
- package/dist/{NeuralRetouch-DFI4pOjO.js → NeuralRetouch-BKQCsmEs.js} +2 -2
- package/dist/{NeuralSuperRes-ChCiiilS.js → NeuralSuperRes-C4ymq68e.js} +2 -2
- package/dist/{PathTracer-BX4sJLx7.js → PathTracer-C_to_i40.js} +3158 -3102
- package/dist/{PhysicalSky-Biv39eTA.js → PhysicalSky-bMHbm_7H.js} +1 -1
- package/dist/{RayzeeRenderer-D8XRKU3A.js → RayzeeRenderer-B_aB6VTJ.js} +370 -372
- package/dist/SceneMetadata-CSmlJW4c.js +183 -0
- package/dist/{ToneMapGPU-sAs8wdgI.js → ToneMapGPU-4GPwoG_c.js} +13 -6
- package/dist/addons/archives.es.js +1 -1
- package/dist/addons/bidirectional.es.js +1 -1
- package/dist/addons/color.es.js +1 -1
- package/dist/addons/physical-sky.es.js +1 -1
- package/dist/addons/storage.es.js +1 -1
- package/dist/{openStorage-Fe9BoS1_.js → openStorage-B085D9FR.js} +1 -1
- package/dist/rayzee-core.es.js +5 -5
- package/dist/rayzee.es.js +917 -1624
- package/dist/rayzee.umd.js +113 -156
- package/dist/{sceneCachePolicy-W5PLbzuR.js → sceneCachePolicy-D_uBSbQF.js} +2 -2
- package/package.json +1 -1
- package/src/EngineIssues.js +20 -6
- package/src/Passes/AIUpscaler.js +4 -0
- package/src/Passes/OIDNDenoiser.js +17 -17
- package/src/PathTracerApp.js +16 -18
- package/src/Pipeline/BindingAudit.js +2 -3
- package/src/Pipeline/PipelineContext.js +0 -1
- package/src/Pipeline/RenderPipeline.js +1 -2
- package/src/Pipeline/RenderStage.js +1 -1
- package/src/Processor/ArchiveImporter.js +23 -6
- package/src/Processor/AssetLoader.js +15 -0
- package/src/Processor/LightSerializer.js +6 -2
- package/src/Processor/PBRT/PBRTMaterials.js +2 -1
- package/src/Processor/PBRT/PBRTSceneBuilder.js +1 -1
- package/src/Processor/PackedRayBuffer.js +2 -2
- package/src/Processor/PlatformImageLoader.js +9 -0
- package/src/Processor/StorageTexturePool.js +1 -1
- package/src/Processor/TextureCreator.js +44 -4
- package/src/Processor/ToneMapCPU.js +34 -5
- package/src/Processor/ToneMapGPU.js +15 -9
- package/src/Processor/USD/USDScene.js +981 -17
- package/src/RayzeeRenderer.js +82 -27
- package/src/Stages/AutoExposure.js +21 -8
- package/src/Stages/Compositor.js +39 -1
- package/src/Stages/DenoiserSettings.js +5 -81
- package/src/Stages/LocalExposure.js +44 -18
- package/src/Stages/MotionVector.js +21 -215
- package/src/Stages/NormalDepth.js +12 -8
- package/src/Stages/PathTracer.js +26 -2
- package/src/Stages/PathTracerStage.js +13 -18
- package/src/TSL/CameraRay.js +12 -1
- package/src/TSL/DebugKernel.js +3 -2
- package/src/TSL/FinalWriteKernel.js +6 -9
- package/src/TSL/GenerateKernel.js +6 -2
- package/src/TSL/LightSplatKernel.js +7 -4
- package/src/TSL/LightsCore.js +6 -2
- package/src/TSL/LightsSampling.js +45 -12
- package/src/TSL/SceneResources.js +11 -0
- package/src/TSL/ShadeKernel.js +4 -5
- package/src/index.js +1 -1
- package/src/integrators/BidirectionalIntegrator.js +1 -0
- package/src/managers/CameraManager.js +9 -0
- package/src/managers/DenoisingManager.js +79 -187
- package/src/managers/InteractionManager.js +6 -0
- package/src/managers/UniformManager.js +3 -1
- package/dist/SceneMetadata-D2Sh-0e-.js +0 -110
- package/src/Stages/ASVGF.js +0 -932
- package/src/Stages/BilateralFilter.js +0 -486
- package/src/Stages/EdgeFilter.js +0 -545
- package/src/Stages/Variance.js +0 -443
|
@@ -11,7 +11,7 @@ import { createLogger } from '../utils/Logger.js';
|
|
|
11
11
|
const neuralLog = createLogger( 'neural' );
|
|
12
12
|
import { CAMERA_PROJECTION_IDS } from '../EngineDefaults.js';
|
|
13
13
|
import {
|
|
14
|
-
DENOISER_DEFAULTS,
|
|
14
|
+
DENOISER_DEFAULTS, DENOISER_STRATEGIES, NRD_DEFAULTS, NRD_QUALITY_PRESETS, NRD_PRESET_KEYS,
|
|
15
15
|
} from '../Stages/DenoiserSettings.js';
|
|
16
16
|
|
|
17
17
|
// A refresh slower than this is a slideshow, not a live view, so the cadence swaps to a cheaper
|
|
@@ -85,7 +85,7 @@ const historyFade = ( samples ) => Math.max( 0, 1 - samples / HISTORY_HANDOFF_SA
|
|
|
85
85
|
|
|
86
86
|
/**
|
|
87
87
|
* Orchestrates all denoising, post-processing, and AI upscaling:
|
|
88
|
-
* - Real-time denoiser strategy switching (
|
|
88
|
+
* - Real-time denoiser strategy switching (OIDN / NRD / None)
|
|
89
89
|
* - OIDN (offline denoise on render completion)
|
|
90
90
|
* - AI Upscaler
|
|
91
91
|
* - Auto-exposure coordination
|
|
@@ -118,7 +118,7 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
118
118
|
this.pipeline = pipeline;
|
|
119
119
|
|
|
120
120
|
// Stage references — only used internally for orchestration
|
|
121
|
-
this._stages = stages; // { pathTracer,
|
|
121
|
+
this._stages = stages; // { pathTracer, normalDepth, motionVector, nrd, autoExposure, compositor }
|
|
122
122
|
|
|
123
123
|
this._getExposure = getExposure;
|
|
124
124
|
this._getSaturation = getSaturation;
|
|
@@ -349,7 +349,9 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
349
349
|
this.dispatchEvent( { type: EngineEvents.DENOISING_START, continuous: !! e.continuous } );
|
|
350
350
|
this._denoiserEndHandler = e => {
|
|
351
351
|
|
|
352
|
-
|
|
352
|
+
// A refresh that lands after the live view stopped wanting one would cover what replaced it.
|
|
353
|
+
const current = ! e.continuous || ( this.continuousDenoise && ! this._cadenceSuspended );
|
|
354
|
+
if ( this.denoiser?.hasOutput && current ) this._publishOutput();
|
|
353
355
|
this.dispatchEvent( { type: EngineEvents.DENOISING_END, continuous: !! e.continuous } );
|
|
354
356
|
|
|
355
357
|
};
|
|
@@ -424,6 +426,7 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
424
426
|
getToneMapping: () => this._getToneMapping(),
|
|
425
427
|
getSaturation: () => this._getSaturation(),
|
|
426
428
|
getDisplayGain: () => this._getDisplayGain?.() ?? null,
|
|
429
|
+
getTransparentBackground: () => !! this._settings?.get( 'transparentBackground' ),
|
|
427
430
|
} );
|
|
428
431
|
|
|
429
432
|
this.upscaler.enabled = DENOISER_DEFAULTS.enableUpscaler || false;
|
|
@@ -447,9 +450,8 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
447
450
|
// ── Denoiser Strategy ─────────────────────────────────────────
|
|
448
451
|
|
|
449
452
|
/**
|
|
450
|
-
* Active real-time denoiser, derived from stage state so it can't drift from
|
|
451
|
-
*
|
|
452
|
-
* @returns {'asvgf'|'nrd'|'edgeaware'|'none'}
|
|
453
|
+
* Active real-time denoiser, derived from stage state so it can't drift from setDenoiserStrategy.
|
|
454
|
+
* @returns {'none'|'nrd'|'oidn'}
|
|
453
455
|
*/
|
|
454
456
|
get denoiserStrategy() {
|
|
455
457
|
|
|
@@ -457,105 +459,55 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
457
459
|
// belongs in the same one-of-N choice. Two of these running at once would mean paying for
|
|
458
460
|
// a per-frame denoise whose result the OIDN overlay then covers.
|
|
459
461
|
if ( this.continuousDenoise ) return 'oidn';
|
|
460
|
-
if ( this._stages.asvgf?.enabled ) return 'asvgf';
|
|
461
462
|
if ( this._stages.nrd?.enabled ) return 'nrd';
|
|
462
|
-
if ( this._stages.edgeFilter?.enabled ) return 'edgeaware';
|
|
463
463
|
return 'none';
|
|
464
464
|
|
|
465
465
|
}
|
|
466
466
|
|
|
467
467
|
/**
|
|
468
468
|
* Switches the real-time denoiser strategy.
|
|
469
|
-
* @param {string} strategy -
|
|
470
|
-
* @param {string} [preset] - quality preset
|
|
469
|
+
* @param {string} strategy - one of DENOISER_STRATEGIES; any other name is recorded and runs 'none'
|
|
470
|
+
* @param {string} [preset] - NRD quality preset (NRD_QUALITY_PRESETS)
|
|
471
471
|
*/
|
|
472
472
|
setDenoiserStrategy( strategy, preset ) {
|
|
473
473
|
|
|
474
474
|
const s = this._stages;
|
|
475
475
|
|
|
476
|
-
|
|
477
|
-
if ( s.asvgf ) s.asvgf.enabled = false;
|
|
478
|
-
if ( s.nrd ) s.nrd.enabled = false;
|
|
479
|
-
if ( s.variance ) s.variance.enabled = false;
|
|
480
|
-
if ( s.bilateralFilter ) s.bilateralFilter.enabled = false;
|
|
481
|
-
if ( s.edgeFilter ) s.edgeFilter.setFilteringEnabled( false );
|
|
476
|
+
if ( ! DENOISER_STRATEGIES.includes( strategy ) ) {
|
|
482
477
|
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
switch ( strategy ) {
|
|
490
|
-
|
|
491
|
-
case 'asvgf':
|
|
492
|
-
s.asvgf.enabled = true;
|
|
493
|
-
if ( s.variance ) s.variance.enabled = true;
|
|
494
|
-
if ( s.bilateralFilter ) s.bilateralFilter.enabled = true;
|
|
495
|
-
s.asvgf.setTemporalEnabled?.( true );
|
|
496
|
-
this._applyASVGFPreset( preset || 'medium' );
|
|
497
|
-
break;
|
|
478
|
+
this._issues?.record(
|
|
479
|
+
ISSUE_CODES.DENOISER_UNAVAILABLE,
|
|
480
|
+
`'${strategy}' is not a live denoiser (${DENOISER_STRATEGIES.join( ', ' )}) — none is used`,
|
|
481
|
+
{ strategy }
|
|
482
|
+
);
|
|
483
|
+
strategy = 'none';
|
|
498
484
|
|
|
499
|
-
|
|
500
|
-
if ( s.nrd ) {
|
|
501
|
-
|
|
502
|
-
s.nrd.enabled = true;
|
|
503
|
-
// Stale history from the last time it ran describes another view.
|
|
504
|
-
s.nrd.resetHistory?.();
|
|
505
|
-
this._applyNRDPreset( preset || 'medium' );
|
|
506
|
-
|
|
507
|
-
}
|
|
485
|
+
}
|
|
508
486
|
|
|
509
|
-
|
|
487
|
+
// NRD reprojects through motion vectors, which mean nothing once every pixel is its own direction.
|
|
488
|
+
if ( strategy === 'nrd' && this._isPanorama() ) {
|
|
510
489
|
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
// stage's per-pixel variance to drive its luminance edge-stop.
|
|
514
|
-
if ( s.variance ) s.variance.enabled = true;
|
|
515
|
-
if ( s.edgeFilter ) s.edgeFilter.setFilteringEnabled( true );
|
|
516
|
-
break;
|
|
490
|
+
this._issues?.record( ISSUE_CODES.DENOISER_UNAVAILABLE, 'NRD cannot run in a panorama — oidn is used', { strategy } );
|
|
491
|
+
strategy = 'oidn';
|
|
517
492
|
|
|
518
493
|
}
|
|
519
494
|
|
|
520
|
-
this.
|
|
521
|
-
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
/**
|
|
525
|
-
* Enables/disables ASVGF denoising with coordination of related stages.
|
|
526
|
-
* @param {boolean} enabled
|
|
527
|
-
* @param {string} [qualityPreset]
|
|
528
|
-
*/
|
|
529
|
-
setASVGFEnabled( enabled, qualityPreset ) {
|
|
495
|
+
this._clearDenoiserTextures();
|
|
530
496
|
|
|
531
|
-
|
|
532
|
-
if ( s.asvgf ) s.asvgf.enabled = enabled;
|
|
533
|
-
if ( s.variance ) s.variance.enabled = enabled;
|
|
534
|
-
if ( s.bilateralFilter ) s.bilateralFilter.enabled = enabled;
|
|
497
|
+
if ( s.nrd ) s.nrd.enabled = strategy === 'nrd';
|
|
535
498
|
|
|
536
|
-
if ( enabled ) {
|
|
499
|
+
if ( s.nrd?.enabled ) {
|
|
537
500
|
|
|
538
|
-
//
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
this._applyASVGFPreset( qualityPreset || 'medium' );
|
|
501
|
+
// Stale history from the last time it ran describes another view.
|
|
502
|
+
s.nrd.resetHistory?.();
|
|
503
|
+
this._applyNRDPreset( preset || 'medium' );
|
|
542
504
|
|
|
543
505
|
}
|
|
544
506
|
|
|
545
|
-
//
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
this.
|
|
549
|
-
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
/**
|
|
553
|
-
* Applies an ASVGF quality preset.
|
|
554
|
-
* @param {string} presetName - 'low' | 'medium' | 'high'
|
|
555
|
-
*/
|
|
556
|
-
applyASVGFPreset( presetName ) {
|
|
557
|
-
|
|
558
|
-
this._applyASVGFPreset( presetName );
|
|
507
|
+
// Which denoiser owns the live view. Deliberately says nothing about the finished image:
|
|
508
|
+
// wanting OIDN on the viewport is not the same as opting into a final pass. Also re-syncs
|
|
509
|
+
// the G-buffer stages, so NRD must already be set.
|
|
510
|
+
this.setContinuousDenoise( strategy === 'oidn' );
|
|
559
511
|
|
|
560
512
|
}
|
|
561
513
|
|
|
@@ -569,6 +521,13 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
569
521
|
|
|
570
522
|
}
|
|
571
523
|
|
|
524
|
+
/** True while a strategy that reprojects through motion vectors is active. */
|
|
525
|
+
get requiresMotionVectors() {
|
|
526
|
+
|
|
527
|
+
return !! this._stages.nrd?.enabled;
|
|
528
|
+
|
|
529
|
+
}
|
|
530
|
+
|
|
572
531
|
/**
|
|
573
532
|
* Gate the G-buffer stages (NormalDepth, MotionVector) on demand: they only
|
|
574
533
|
* need to run when a real-time denoiser consumes their output. Idling them
|
|
@@ -576,17 +535,10 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
576
535
|
* navigation and frees their textures. Call after any consumer toggle.
|
|
577
536
|
*
|
|
578
537
|
* MotionVector requires NormalDepth (reads pathtracer:normalDepth) and its
|
|
579
|
-
*
|
|
580
|
-
*
|
|
581
|
-
*
|
|
538
|
+
* consumer (NRD) also reads NormalDepth, so NormalDepth is always enabled
|
|
539
|
+
* whenever MotionVector is. Adaptive sampling and OIDN's own pass do NOT read
|
|
540
|
+
* these signals; only OIDN's motion history keeps NormalDepth alive.
|
|
582
541
|
*/
|
|
583
|
-
/** True while a strategy that reprojects through motion vectors is active. */
|
|
584
|
-
get requiresMotionVectors() {
|
|
585
|
-
|
|
586
|
-
return !! ( this._stages.asvgf?.enabled || this._stages.nrd?.enabled );
|
|
587
|
-
|
|
588
|
-
}
|
|
589
|
-
|
|
590
542
|
_syncGBufferStages() {
|
|
591
543
|
|
|
592
544
|
const s = this._stages;
|
|
@@ -594,8 +546,8 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
594
546
|
const mv = s.motionVector;
|
|
595
547
|
|
|
596
548
|
const motionNeeded = this.requiresMotionVectors;
|
|
597
|
-
// pathtracer:normalDepth consumed by
|
|
598
|
-
const normalNeeded = motionNeeded || this.historyWanted
|
|
549
|
+
// pathtracer:normalDepth consumed by NRD and the OIDN history
|
|
550
|
+
const normalNeeded = motionNeeded || this.historyWanted;
|
|
599
551
|
if ( ! this.historyWanted ) this._releaseHistory();
|
|
600
552
|
|
|
601
553
|
if ( nd ) {
|
|
@@ -612,21 +564,14 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
612
564
|
|
|
613
565
|
// On re-enable, force a camera-history reseed (matricesInitialized survives
|
|
614
566
|
// normal resets) so the first frame reports zero motion, not a spike.
|
|
615
|
-
if ( motionNeeded && ! mv.enabled )
|
|
616
|
-
|
|
617
|
-
mv.matricesInitialized = false;
|
|
618
|
-
mv.isFirstFrame = true;
|
|
619
|
-
mv.frameCount = 0;
|
|
620
|
-
|
|
621
|
-
}
|
|
567
|
+
if ( motionNeeded && ! mv.enabled ) mv.matricesInitialized = false;
|
|
622
568
|
|
|
623
569
|
mv.enabled = motionNeeded;
|
|
624
570
|
|
|
625
571
|
}
|
|
626
572
|
|
|
627
|
-
// PathTracer's aux MRT (normalDepth + albedo) is consumed by
|
|
628
|
-
//
|
|
629
|
-
// MRT read-targets directly). When none are active the wavefront skips those writes entirely.
|
|
573
|
+
// PathTracer's aux MRT (normalDepth + albedo) is consumed by NRD (albedo, hit distance) and by
|
|
574
|
+
// OIDN (reads the MRT read-targets directly). When neither is active the wavefront skips those writes.
|
|
630
575
|
s.pathTracer?.setAuxGBufferEnabled?.( normalNeeded || !! this.denoiser?.enabled );
|
|
631
576
|
|
|
632
577
|
// Clean-aux normal: temporally accumulate the aux normal only for OIDN clean-aux models
|
|
@@ -641,7 +586,7 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
641
586
|
// disabled (lazily re-created on the next dispatch after re-enable). Every strategy/denoiser
|
|
642
587
|
// toggle funnels through here after the enabled flags above are settled, so this is the one
|
|
643
588
|
// choke point. dispose() is idempotent, so re-running it for an already-released stage is a no-op.
|
|
644
|
-
for ( const stage of [ s.
|
|
589
|
+
for ( const stage of [ s.nrd, nd, mv ] ) {
|
|
645
590
|
|
|
646
591
|
if ( stage && ! stage.enabled ) stage.releaseGPUMemory?.();
|
|
647
592
|
|
|
@@ -849,21 +794,29 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
849
794
|
|
|
850
795
|
this._cadenceSuspended = !! suspended;
|
|
851
796
|
this._historyDirty = true;
|
|
852
|
-
if ( ! this._cadenceSuspended ) return;
|
|
853
797
|
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
798
|
+
if ( this._cadenceSuspended ) {
|
|
799
|
+
|
|
800
|
+
// The accumulation is what a final render shows; a held preview frame would otherwise sit
|
|
801
|
+
// over it until the render finished.
|
|
802
|
+
this.denoiser?.abort();
|
|
803
|
+
this._unpublishOutput();
|
|
804
|
+
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
this._syncGBufferStages();
|
|
858
808
|
|
|
859
809
|
}
|
|
860
810
|
|
|
861
811
|
setContinuousDenoise( enabled ) {
|
|
862
812
|
|
|
813
|
+
// Once nothing else uses OIDN it turns off, and a disabled denoiser can no longer be aborted.
|
|
814
|
+
if ( ! enabled && ! this.finalDenoise ) this.denoiser?.abort();
|
|
863
815
|
this.continuousDenoise = !! enabled;
|
|
864
816
|
this._syncOIDNInUse();
|
|
865
817
|
this._lastCadenceAt = - Infinity;
|
|
866
818
|
this._resetCadence();
|
|
819
|
+
this._syncGBufferStages();
|
|
867
820
|
|
|
868
821
|
}
|
|
869
822
|
|
|
@@ -895,19 +848,24 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
895
848
|
|
|
896
849
|
}
|
|
897
850
|
|
|
898
|
-
// Not at a size proven too slow to denoise while moving
|
|
851
|
+
// Not at a size proven too slow to denoise while moving (the raw render owns the view there), nor
|
|
852
|
+
// through a final render or a panorama, which never reproject it.
|
|
899
853
|
get historyWanted() {
|
|
900
854
|
|
|
901
|
-
return this.temporalHistory && this.continuousDenoise && !! this.denoiser?.enabled && ! this._movingHopeless
|
|
855
|
+
return this.temporalHistory && this.continuousDenoise && !! this.denoiser?.enabled && ! this._movingHopeless
|
|
856
|
+
&& ! this._cadenceSuspended && ! this._isPanorama();
|
|
902
857
|
|
|
903
858
|
}
|
|
904
859
|
|
|
905
860
|
get historyActive() {
|
|
906
861
|
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
862
|
+
return this.historyWanted && !! this._stages.normalDepth?.enabled && ! ( this._stages.pathTracer?.visMode?.value > 0 );
|
|
863
|
+
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
_isPanorama() {
|
|
867
|
+
|
|
868
|
+
return this._stages.pathTracer?.uniforms?.get( 'cameraProjection' )?.value === CAMERA_PROJECTION_IDS.equirectangular;
|
|
911
869
|
|
|
912
870
|
}
|
|
913
871
|
|
|
@@ -1443,7 +1401,9 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
1443
1401
|
// What closes the render, if anything. A full pass at the chosen tier when that switch is
|
|
1444
1402
|
// on; otherwise, if OIDN owns the live view, one last cheap refresh — the cadence's last
|
|
1445
1403
|
// tick lands a few samples short, and the picture should match the render that finished.
|
|
1446
|
-
|
|
1404
|
+
// A final render has no live view to match, so with the switch off it stays undenoised.
|
|
1405
|
+
const live = this.continuousDenoise && ! this._cadenceSuspended;
|
|
1406
|
+
const closing = this.finalDenoise ? 'final' : live ? 'refresh' : null;
|
|
1447
1407
|
|
|
1448
1408
|
// Registered only once the closing denoise has been launched, so the next 'end' is
|
|
1449
1409
|
// unambiguously that one — a cadence run's end can look identical otherwise.
|
|
@@ -1686,53 +1646,6 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
1686
1646
|
// These methods match the DenoisingAPI surface so call sites need
|
|
1687
1647
|
// zero or minimal changes after facade removal.
|
|
1688
1648
|
|
|
1689
|
-
/** Updates ASVGF stage parameters. */
|
|
1690
|
-
setASVGFParams( params ) {
|
|
1691
|
-
|
|
1692
|
-
this._stages.asvgf?.updateParameters( params );
|
|
1693
|
-
|
|
1694
|
-
}
|
|
1695
|
-
|
|
1696
|
-
/**
|
|
1697
|
-
* Toggle the ASVGF heatmap compute pass. When enabled, the stage writes
|
|
1698
|
-
* the heatmap to its public `heatmapTarget` RenderTarget — the host is
|
|
1699
|
-
* responsible for rendering it.
|
|
1700
|
-
*/
|
|
1701
|
-
toggleASVGFHeatmap( enabled ) {
|
|
1702
|
-
|
|
1703
|
-
this._stages.asvgf?.setHeatmapEnabled?.( enabled );
|
|
1704
|
-
|
|
1705
|
-
}
|
|
1706
|
-
|
|
1707
|
-
/**
|
|
1708
|
-
* Configures ASVGF for a specific render mode (multi-stage coordination).
|
|
1709
|
-
* @param {Object} config - { enabled, temporalAlpha, atrousIterations, ... }
|
|
1710
|
-
*/
|
|
1711
|
-
configureASVGFForMode( config ) {
|
|
1712
|
-
|
|
1713
|
-
if ( ! this._stages.asvgf ) return;
|
|
1714
|
-
|
|
1715
|
-
this._stages.asvgf.enabled = config.enabled;
|
|
1716
|
-
if ( this._stages.variance ) this._stages.variance.enabled = config.enabled;
|
|
1717
|
-
if ( this._stages.bilateralFilter ) this._stages.bilateralFilter.enabled = config.enabled;
|
|
1718
|
-
|
|
1719
|
-
if ( config.enabled ) {
|
|
1720
|
-
|
|
1721
|
-
this._stages.asvgf.updateParameters( config );
|
|
1722
|
-
|
|
1723
|
-
}
|
|
1724
|
-
|
|
1725
|
-
this._syncGBufferStages();
|
|
1726
|
-
|
|
1727
|
-
}
|
|
1728
|
-
|
|
1729
|
-
/** Updates edge-aware filtering parameters. */
|
|
1730
|
-
setEdgeAwareParams( params ) {
|
|
1731
|
-
|
|
1732
|
-
this._stages.edgeFilter?.updateUniforms( params );
|
|
1733
|
-
|
|
1734
|
-
}
|
|
1735
|
-
|
|
1736
1649
|
/** Updates auto-exposure stage parameters. */
|
|
1737
1650
|
setAutoExposureParams( params ) {
|
|
1738
1651
|
|
|
@@ -1850,7 +1763,7 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
1850
1763
|
|
|
1851
1764
|
/**
|
|
1852
1765
|
* Switches strategy with automatic reset (convenience wrapper).
|
|
1853
|
-
* @param {'none'|'
|
|
1766
|
+
* @param {'none'|'nrd'|'oidn'} strategy
|
|
1854
1767
|
* @param {string} [preset]
|
|
1855
1768
|
*/
|
|
1856
1769
|
setStrategy( strategy, preset ) {
|
|
@@ -1919,12 +1832,8 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
1919
1832
|
const ctx = this.pipeline?.context;
|
|
1920
1833
|
if ( ! ctx ) return;
|
|
1921
1834
|
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
'variance:output', 'bilateralFiltering:output',
|
|
1925
|
-
'edgeFiltering:output', 'nrd:output', 'oidn:output',
|
|
1926
|
-
];
|
|
1927
|
-
keys.forEach( k => ctx.removeTexture( k ) );
|
|
1835
|
+
ctx.removeTexture( 'nrd:output' );
|
|
1836
|
+
ctx.removeTexture( 'oidn:output' );
|
|
1928
1837
|
|
|
1929
1838
|
}
|
|
1930
1839
|
|
|
@@ -1939,21 +1848,4 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
1939
1848
|
|
|
1940
1849
|
}
|
|
1941
1850
|
|
|
1942
|
-
_applyASVGFPreset( presetName ) {
|
|
1943
|
-
|
|
1944
|
-
const preset = ASVGF_QUALITY_PRESETS[ presetName ];
|
|
1945
|
-
if ( ! preset ) return;
|
|
1946
|
-
// ASVGF consumes temporalAlpha / gradientStrength / maxAccumFrames.
|
|
1947
|
-
// BilateralFilter consumes phi* edge-stopping params and atrousIterations.
|
|
1948
|
-
// Variance consumes varianceBoost. Each stage cherry-picks what it needs.
|
|
1949
|
-
this._stages.asvgf?.updateParameters( preset );
|
|
1950
|
-
this._stages.bilateralFilter?.updateParameters( preset );
|
|
1951
|
-
if ( this._stages.variance && preset.varianceBoost !== undefined ) {
|
|
1952
|
-
|
|
1953
|
-
this._stages.variance.varianceBoost.value = preset.varianceBoost;
|
|
1954
|
-
|
|
1955
|
-
}
|
|
1956
|
-
|
|
1957
|
-
}
|
|
1958
|
-
|
|
1959
1851
|
}
|
|
@@ -704,6 +704,12 @@ export class InteractionManager extends EventDispatcher {
|
|
|
704
704
|
*/
|
|
705
705
|
_intersectScene() {
|
|
706
706
|
|
|
707
|
+
// Nothing in front of an imported camera's clip plane is rendered, so nothing there is picked. An orthographic
|
|
708
|
+
// ray already starts on the near plane, which a switch to such a camera set to its clip start.
|
|
709
|
+
const clipStart = this.camera.userData?.clipStart ?? 0;
|
|
710
|
+
this.raycaster.near = clipStart > 0 && ! this.camera.isOrthographicCamera
|
|
711
|
+
? clipStart / Math.max( this.raycaster.ray.direction.dot( this.camera.getWorldDirection( _viewAxis ) ), 1e-4 )
|
|
712
|
+
: 0;
|
|
707
713
|
return this.isGeometryOnDisk?.() ? [] : this.raycaster.intersectObjects( this.scene.children, true );
|
|
708
714
|
|
|
709
715
|
}
|
|
@@ -23,7 +23,7 @@ const SHADER_NAMES = {
|
|
|
23
23
|
export const LIGHT_FLOATS = Object.freeze( {
|
|
24
24
|
directional: 12, // 8 light fields + gobo { index, signed intensity, scale, pad }
|
|
25
25
|
area: 16, // 13 base + normalize, spread, shape
|
|
26
|
-
point: 9
|
|
26
|
+
point: 10, // 9 light fields + radius
|
|
27
27
|
spot: 20, // 14 light fields + gobo { index, signed intensity } + IES { index, intensity } + 2 reserved
|
|
28
28
|
} );
|
|
29
29
|
|
|
@@ -301,6 +301,8 @@ export class UniformManager {
|
|
|
301
301
|
u( 'cameraProjectionMatrixInverse', new Matrix4(), 'mat4' );
|
|
302
302
|
u( 'cameraViewMatrix', new Matrix4(), 'mat4' );
|
|
303
303
|
u( 'cameraProjectionMatrix', new Matrix4(), 'mat4' );
|
|
304
|
+
// An imported camera's near clipping plane: camera rays start this far in front of it (0 = at the camera).
|
|
305
|
+
u( 'cameraClipStart', 0, 'float' );
|
|
304
306
|
|
|
305
307
|
// Projection: CAMERA_PROJECTION_IDS. Ranges are radians (UI carries degrees).
|
|
306
308
|
const radRange = ( [ min, max ] ) => new Vector2( min, max ).multiplyScalar( MathUtils.DEG2RAD );
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
//#region src/Processor/archiveFormats.js
|
|
2
|
-
var e = Object.freeze({
|
|
3
|
-
zip: {
|
|
4
|
-
type: "archive",
|
|
5
|
-
name: "ZIP Archive"
|
|
6
|
-
},
|
|
7
|
-
gz: {
|
|
8
|
-
type: "archive",
|
|
9
|
-
name: "Gzipped TAR Archive"
|
|
10
|
-
},
|
|
11
|
-
tgz: {
|
|
12
|
-
type: "archive",
|
|
13
|
-
name: "Gzipped TAR Archive"
|
|
14
|
-
},
|
|
15
|
-
tar: {
|
|
16
|
-
type: "archive",
|
|
17
|
-
name: "TAR Archive"
|
|
18
|
-
}
|
|
19
|
-
}), t = (e) => typeof Blob < "u" && e instanceof Blob, n = (e) => !!e && typeof e == "object" && !t(e) && e.files != null, r = (e) => e.startsWith(".") || e === "__MACOSX";
|
|
20
|
-
function i({ name: e = null, files: n }, { isModel: i = () => !1 } = {}) {
|
|
21
|
-
let a = /* @__PURE__ */ new Map();
|
|
22
|
-
for (let e of n) {
|
|
23
|
-
let n = t(e) ? e : e.file, i = t(e) ? e.webkitRelativePath || e.name : e.path, o = String(i ?? "").replace(/\\/g, "/").split("/").filter((e) => e && e !== ".").join("/");
|
|
24
|
-
!o || !n || o.split("/").some(r) || a.set(o, {
|
|
25
|
-
path: o,
|
|
26
|
-
file: n
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
let o = [...a.values()].sort((e, t) => e.path < t.path ? -1 : +(e.path > t.path)), s = o[0]?.path.split("/")[0], c = o.length > 0 && o.every((e) => e.path.startsWith(s + "/")) ? s : null;
|
|
30
|
-
return {
|
|
31
|
-
name: e ?? c ?? (o.find((e) => i(e.path)) ?? o[0])?.path.split("/").pop() ?? "Folder",
|
|
32
|
-
files: o,
|
|
33
|
-
flat: c === null && o.every((e) => !e.path.includes("/"))
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
//#endregion
|
|
37
|
-
//#region src/Processor/SceneMetadata.js
|
|
38
|
-
var a = [
|
|
39
|
-
"sourceFile",
|
|
40
|
-
"url",
|
|
41
|
-
"file"
|
|
42
|
-
];
|
|
43
|
-
function o(e) {
|
|
44
|
-
if (typeof e == "string") try {
|
|
45
|
-
let t = JSON.parse(e);
|
|
46
|
-
return t && typeof t == "object" ? t : null;
|
|
47
|
-
} catch {
|
|
48
|
-
return null;
|
|
49
|
-
}
|
|
50
|
-
return e && typeof e == "object" ? e : null;
|
|
51
|
-
}
|
|
52
|
-
function s(e) {
|
|
53
|
-
let t = typeof e == "string" ? parseFloat(e) : e;
|
|
54
|
-
return Number.isFinite(t) ? t : void 0;
|
|
55
|
-
}
|
|
56
|
-
function c(e) {
|
|
57
|
-
let t = o(e);
|
|
58
|
-
if (!t) return null;
|
|
59
|
-
let n = (e) => e && (e.environment !== void 0 || e.render !== void 0), r = o(t.rayzee);
|
|
60
|
-
return n(r) ? r : n(t) ? t : null;
|
|
61
|
-
}
|
|
62
|
-
function l(e) {
|
|
63
|
-
let t = o(e);
|
|
64
|
-
if (!t) return null;
|
|
65
|
-
let n = a.map((e) => t[e]).find((e) => typeof e == "string" && e.trim());
|
|
66
|
-
if (!n) return null;
|
|
67
|
-
let r = s(t.rotation), i = s(t.intensity), c = { sourceFile: n.trim() };
|
|
68
|
-
return r !== void 0 && (c.rotation = r), i !== void 0 && (c.intensity = Math.max(0, i)), c;
|
|
69
|
-
}
|
|
70
|
-
var u = [
|
|
71
|
-
"maxBounces",
|
|
72
|
-
"samples",
|
|
73
|
-
"width",
|
|
74
|
-
"height"
|
|
75
|
-
];
|
|
76
|
-
function d(e) {
|
|
77
|
-
let t = o(e);
|
|
78
|
-
if (!t) return null;
|
|
79
|
-
let n = {};
|
|
80
|
-
for (let e of u) {
|
|
81
|
-
let r = s(t[e]);
|
|
82
|
-
r !== void 0 && r > 0 && (n[e] = Math.round(r));
|
|
83
|
-
}
|
|
84
|
-
return Object.keys(n).length ? n : null;
|
|
85
|
-
}
|
|
86
|
-
function f(e) {
|
|
87
|
-
let t = c(e);
|
|
88
|
-
if (!t) return null;
|
|
89
|
-
let n = l(t.environment), r = d(t.render);
|
|
90
|
-
return !n && !r ? null : {
|
|
91
|
-
...n ? { environment: n } : {},
|
|
92
|
-
...r ? { render: r } : {}
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
function p(e) {
|
|
96
|
-
if (!e) return null;
|
|
97
|
-
let t = [
|
|
98
|
-
e.userData,
|
|
99
|
-
e.asset?.extras,
|
|
100
|
-
e.scene?.userData
|
|
101
|
-
];
|
|
102
|
-
Array.isArray(e.scenes) && t.push(...e.scenes.map((e) => e?.userData));
|
|
103
|
-
for (let e of t) {
|
|
104
|
-
let t = f(e);
|
|
105
|
-
if (t) return t;
|
|
106
|
-
}
|
|
107
|
-
return null;
|
|
108
|
-
}
|
|
109
|
-
//#endregion
|
|
110
|
-
export { i as a, n as i, f as n, e as r, p as t };
|