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.
Files changed (72) hide show
  1. package/README.md +26 -14
  2. package/dist/{ArchiveImporter-iofnC8zB.js → ArchiveImporter-_sJm5uaK.js} +1923 -1243
  3. package/dist/{BidirectionalIntegrator-CqAilt2I.js → BidirectionalIntegrator-Dzt4Z97x.js} +290 -289
  4. package/dist/{ColorManagement-oeEk7oSu.js → ColorManagement-30MfpHwQ.js} +1 -1
  5. package/dist/{EngineIssues-CIZnXHsF.js → EngineIssues-xljoXM0E.js} +18 -8
  6. package/dist/{NeuralRetouch-DFI4pOjO.js → NeuralRetouch-BKQCsmEs.js} +2 -2
  7. package/dist/{NeuralSuperRes-ChCiiilS.js → NeuralSuperRes-C4ymq68e.js} +2 -2
  8. package/dist/{PathTracer-BX4sJLx7.js → PathTracer-C_to_i40.js} +3158 -3102
  9. package/dist/{PhysicalSky-Biv39eTA.js → PhysicalSky-bMHbm_7H.js} +1 -1
  10. package/dist/{RayzeeRenderer-D8XRKU3A.js → RayzeeRenderer-B_aB6VTJ.js} +370 -372
  11. package/dist/SceneMetadata-CSmlJW4c.js +183 -0
  12. package/dist/{ToneMapGPU-sAs8wdgI.js → ToneMapGPU-4GPwoG_c.js} +13 -6
  13. package/dist/addons/archives.es.js +1 -1
  14. package/dist/addons/bidirectional.es.js +1 -1
  15. package/dist/addons/color.es.js +1 -1
  16. package/dist/addons/physical-sky.es.js +1 -1
  17. package/dist/addons/storage.es.js +1 -1
  18. package/dist/{openStorage-Fe9BoS1_.js → openStorage-B085D9FR.js} +1 -1
  19. package/dist/rayzee-core.es.js +5 -5
  20. package/dist/rayzee.es.js +917 -1624
  21. package/dist/rayzee.umd.js +113 -156
  22. package/dist/{sceneCachePolicy-W5PLbzuR.js → sceneCachePolicy-D_uBSbQF.js} +2 -2
  23. package/package.json +1 -1
  24. package/src/EngineIssues.js +20 -6
  25. package/src/Passes/AIUpscaler.js +4 -0
  26. package/src/Passes/OIDNDenoiser.js +17 -17
  27. package/src/PathTracerApp.js +16 -18
  28. package/src/Pipeline/BindingAudit.js +2 -3
  29. package/src/Pipeline/PipelineContext.js +0 -1
  30. package/src/Pipeline/RenderPipeline.js +1 -2
  31. package/src/Pipeline/RenderStage.js +1 -1
  32. package/src/Processor/ArchiveImporter.js +23 -6
  33. package/src/Processor/AssetLoader.js +15 -0
  34. package/src/Processor/LightSerializer.js +6 -2
  35. package/src/Processor/PBRT/PBRTMaterials.js +2 -1
  36. package/src/Processor/PBRT/PBRTSceneBuilder.js +1 -1
  37. package/src/Processor/PackedRayBuffer.js +2 -2
  38. package/src/Processor/PlatformImageLoader.js +9 -0
  39. package/src/Processor/StorageTexturePool.js +1 -1
  40. package/src/Processor/TextureCreator.js +44 -4
  41. package/src/Processor/ToneMapCPU.js +34 -5
  42. package/src/Processor/ToneMapGPU.js +15 -9
  43. package/src/Processor/USD/USDScene.js +981 -17
  44. package/src/RayzeeRenderer.js +82 -27
  45. package/src/Stages/AutoExposure.js +21 -8
  46. package/src/Stages/Compositor.js +39 -1
  47. package/src/Stages/DenoiserSettings.js +5 -81
  48. package/src/Stages/LocalExposure.js +44 -18
  49. package/src/Stages/MotionVector.js +21 -215
  50. package/src/Stages/NormalDepth.js +12 -8
  51. package/src/Stages/PathTracer.js +26 -2
  52. package/src/Stages/PathTracerStage.js +13 -18
  53. package/src/TSL/CameraRay.js +12 -1
  54. package/src/TSL/DebugKernel.js +3 -2
  55. package/src/TSL/FinalWriteKernel.js +6 -9
  56. package/src/TSL/GenerateKernel.js +6 -2
  57. package/src/TSL/LightSplatKernel.js +7 -4
  58. package/src/TSL/LightsCore.js +6 -2
  59. package/src/TSL/LightsSampling.js +45 -12
  60. package/src/TSL/SceneResources.js +11 -0
  61. package/src/TSL/ShadeKernel.js +4 -5
  62. package/src/index.js +1 -1
  63. package/src/integrators/BidirectionalIntegrator.js +1 -0
  64. package/src/managers/CameraManager.js +9 -0
  65. package/src/managers/DenoisingManager.js +79 -187
  66. package/src/managers/InteractionManager.js +6 -0
  67. package/src/managers/UniformManager.js +3 -1
  68. package/dist/SceneMetadata-D2Sh-0e-.js +0 -110
  69. package/src/Stages/ASVGF.js +0 -932
  70. package/src/Stages/BilateralFilter.js +0 -486
  71. package/src/Stages/EdgeFilter.js +0 -545
  72. 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, ASVGF_QUALITY_PRESETS, NRD_DEFAULTS, NRD_QUALITY_PRESETS, NRD_PRESET_KEYS,
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 (ASVGF / NRD / EdgeAware / None)
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, asvgf, nrd, variance, bilateralFilter, edgeFilter, autoExposure, compositor }
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
- if ( this.denoiser?.hasOutput ) this._publishOutput();
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
- * setDenoiserStrategy / setASVGFEnabled.
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 - 'none' | 'asvgf' | 'nrd' | 'edgeaware'
470
- * @param {string} [preset] - quality preset for 'asvgf' (ASVGF_QUALITY_PRESETS) or 'nrd' (NRD_QUALITY_PRESETS)
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
- // Disable all real-time denoisers first
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
- this._clearDenoiserTextures();
484
-
485
- // Which denoiser owns the live view. Deliberately says nothing about the finished image:
486
- // wanting OIDN on the viewport is not the same as opting into a final pass.
487
- this.setContinuousDenoise( strategy === 'oidn' );
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
- case 'nrd':
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
- break;
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
- case 'edgeaware':
512
- // EdgeAware is a spatial-only SVGF à-trous — it consumes the Variance
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._syncGBufferStages();
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
- const s = this._stages;
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
- // One real-time denoiser at a time.
539
- if ( s.nrd ) s.nrd.enabled = false;
540
- s.asvgf?.setTemporalEnabled?.( true );
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
- // Coordinate with EdgeAware filtering
546
- if ( s.edgeFilter ) s.edgeFilter.setFilteringEnabled( ! enabled );
547
-
548
- this._syncGBufferStages();
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
- * consumers (ASVGF, NRD) are a subset of NormalDepth's, so NormalDepth is
580
- * always enabled whenever MotionVector is. Adaptive sampling / Variance / OIDN
581
- * do NOT read these signals, so they don't keep the G-buffer alive.
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 ASVGF, NRD, EdgeFilter, BilateralFilter, the OIDN history
598
- const normalNeeded = motionNeeded || this.historyWanted || !! ( s.edgeFilter?.enabled || s.bilateralFilter?.enabled );
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 the real-time denoisers (ASVGF/
628
- // BilateralFilter read albedo; ASVGF/EdgeFilter read normalDepth) and by OIDN (reads the
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.asvgf, s.nrd, s.variance, s.bilateralFilter, s.edgeFilter, nd, mv ] ) {
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
- // The accumulation is what a final render shows; a held preview frame would otherwise sit
855
- // over it until the render finished.
856
- this.denoiser?.abort();
857
- this._unpublishOutput();
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: the raw render owns the view there.
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
- const pt = this._stages.pathTracer;
908
- return this.historyWanted && ! this._cadenceSuspended && !! this._stages.normalDepth?.enabled
909
- && pt?.uniforms?.get( 'cameraProjection' )?.value !== CAMERA_PROJECTION_IDS.equirectangular
910
- && ! ( pt?.visMode?.value > 0 );
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
- const closing = this.finalDenoise ? 'final' : this.continuousDenoise ? 'refresh' : null;
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'|'asvgf'|'nrd'|'edgeaware'} strategy
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
- const keys = [
1923
- 'asvgf:output', 'asvgf:demodulated', 'asvgf:gradient',
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 };