rayzee 4.8.14 → 5.0.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 +84 -97
- package/dist/rayzee.es.js +1915 -2185
- package/dist/rayzee.es.js.map +1 -1
- package/dist/rayzee.umd.js +56 -56
- package/dist/rayzee.umd.js.map +1 -1
- package/package.json +1 -1
- package/src/PathTracerApp.js +402 -1567
- package/src/Pipeline/CompletionTracker.js +89 -0
- package/src/Processor/AssetLoader.js +26 -2
- package/src/Processor/SceneProcessor.js +146 -0
- package/src/Processor/TLASBuilder.js +61 -30
- package/src/RenderSettings.js +82 -4
- package/src/TSL/LightsSampling.js +6 -7
- package/src/index.js +2 -12
- package/src/managers/AnimationManager.js +18 -6
- package/src/managers/CameraManager.js +133 -15
- package/src/managers/DenoisingManager.js +289 -3
- package/src/managers/EnvironmentManager.js +94 -1
- package/src/managers/InteractionManager.js +142 -0
- package/src/managers/LightManager.js +51 -1
- package/src/managers/OverlayManager.js +97 -0
- package/src/managers/TransformManager.js +1 -0
- package/src/managers/VideoRenderManager.js +6 -6
- package/src/managers/helpers/StatsHelper.js +45 -0
- package/src/api/AnimationAPI.js +0 -87
- package/src/api/CameraAPI.js +0 -109
- package/src/api/DenoisingAPI.js +0 -243
- package/src/api/EnvironmentAPI.js +0 -106
- package/src/api/LightsAPI.js +0 -80
- package/src/api/MaterialsAPI.js +0 -73
- package/src/api/OutputAPI.js +0 -90
- package/src/api/SelectionAPI.js +0 -89
- package/src/api/TransformAPI.js +0 -49
- package/src/api/index.js +0 -16
|
@@ -1,30 +1,38 @@
|
|
|
1
|
-
import { EventDispatcher, Vector3 } from 'three';
|
|
1
|
+
import { EventDispatcher, PerspectiveCamera, Vector3 } from 'three';
|
|
2
|
+
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
|
|
2
3
|
import { EngineEvents, } from '../EngineEvents.js';
|
|
3
4
|
import { AF_DEFAULTS } from '../EngineDefaults.js';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
|
-
* Manages camera switching, auto-focus, and AF point placement.
|
|
7
|
+
* Manages camera creation, switching, auto-focus, and AF point placement.
|
|
7
8
|
*
|
|
8
|
-
*
|
|
9
|
+
* Owns the PerspectiveCamera and OrbitControls instances.
|
|
9
10
|
* Dispatches events that PathTracerApp relays to external consumers.
|
|
10
11
|
*/
|
|
11
12
|
export class CameraManager extends EventDispatcher {
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
|
-
* @param {
|
|
15
|
-
* @param {import('three/addons/controls/OrbitControls.js').OrbitControls} controls
|
|
16
|
-
* @param {import('./InteractionManager.js').InteractionManager} interactionManager
|
|
15
|
+
* @param {HTMLCanvasElement} canvas - Canvas element for orbit controls
|
|
17
16
|
*/
|
|
18
|
-
constructor(
|
|
17
|
+
constructor( canvas ) {
|
|
19
18
|
|
|
20
19
|
super();
|
|
21
20
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
const width = canvas.clientWidth;
|
|
22
|
+
const height = canvas.clientHeight;
|
|
23
|
+
|
|
24
|
+
this.camera = new PerspectiveCamera( 60, width / height || 1, 0.01, 1000 );
|
|
25
|
+
this.camera.position.set( 0, 0, 5 );
|
|
26
|
+
|
|
27
|
+
this.controls = new OrbitControls( this.camera, canvas );
|
|
28
|
+
this.controls.screenSpacePanning = true;
|
|
29
|
+
this.controls.zoomToCursor = true;
|
|
30
|
+
this.controls.saveState();
|
|
31
|
+
|
|
32
|
+
this.interactionManager = null;
|
|
25
33
|
|
|
26
34
|
/** @type {import('three').PerspectiveCamera[]} */
|
|
27
|
-
this.cameras = [ camera ];
|
|
35
|
+
this.cameras = [ this.camera ];
|
|
28
36
|
this.currentCameraIndex = 0;
|
|
29
37
|
|
|
30
38
|
// Auto-focus state
|
|
@@ -38,6 +46,11 @@ export class CameraManager extends EventDispatcher {
|
|
|
38
46
|
// Saved state for default camera when switching to model cameras
|
|
39
47
|
this._defaultCameraState = null;
|
|
40
48
|
|
|
49
|
+
// Callbacks injected by PathTracerApp
|
|
50
|
+
this._onResize = null;
|
|
51
|
+
this._onReset = null;
|
|
52
|
+
this._getSettings = null;
|
|
53
|
+
|
|
41
54
|
}
|
|
42
55
|
|
|
43
56
|
/**
|
|
@@ -67,15 +80,38 @@ export class CameraManager extends EventDispatcher {
|
|
|
67
80
|
|
|
68
81
|
}
|
|
69
82
|
|
|
83
|
+
/**
|
|
84
|
+
* Stores callbacks for camera operations (resize, reset, settings access).
|
|
85
|
+
* Call once after all managers are ready.
|
|
86
|
+
*
|
|
87
|
+
* @param {Object} callbacks
|
|
88
|
+
* @param {Function} callbacks.onResize - Trigger viewport resize
|
|
89
|
+
* @param {Function} callbacks.onReset - Trigger accumulation reset
|
|
90
|
+
* @param {Function} callbacks.getSettings - (key) => value
|
|
91
|
+
*/
|
|
92
|
+
initCallbacks( { onResize, onReset, getSettings } ) {
|
|
93
|
+
|
|
94
|
+
this._onResize = onResize;
|
|
95
|
+
this._onReset = onReset;
|
|
96
|
+
this._getSettings = getSettings;
|
|
97
|
+
|
|
98
|
+
}
|
|
99
|
+
|
|
70
100
|
/**
|
|
71
101
|
* Switches the active camera by index.
|
|
102
|
+
* Uses stored callbacks from initCallbacks() for resize/reset.
|
|
72
103
|
* @param {number} index
|
|
73
|
-
* @param {number} focusDistance -
|
|
74
|
-
* @param {Function} onResize -
|
|
75
|
-
* @param {Function} onReset -
|
|
104
|
+
* @param {number} [focusDistance] - Override focus distance (falls back to settings)
|
|
105
|
+
* @param {Function} [onResize] - Override resize callback
|
|
106
|
+
* @param {Function} [onReset] - Override reset callback
|
|
76
107
|
*/
|
|
77
108
|
switchCamera( index, focusDistance, onResize, onReset ) {
|
|
78
109
|
|
|
110
|
+
// Use stored callbacks if not provided (backward-compatible signature)
|
|
111
|
+
focusDistance = focusDistance ?? this._getSettings?.( 'focusDistance' );
|
|
112
|
+
onResize = onResize ?? this._onResize;
|
|
113
|
+
onReset = onReset ?? this._onReset;
|
|
114
|
+
|
|
79
115
|
if ( ! this.cameras || this.cameras.length === 0 ) return;
|
|
80
116
|
|
|
81
117
|
if ( index < 0 || index >= this.cameras.length ) {
|
|
@@ -150,6 +186,35 @@ export class CameraManager extends EventDispatcher {
|
|
|
150
186
|
|
|
151
187
|
}
|
|
152
188
|
|
|
189
|
+
/**
|
|
190
|
+
* Focuses the orbit camera on a world-space point.
|
|
191
|
+
* @param {import('three').Vector3} center
|
|
192
|
+
*/
|
|
193
|
+
focusOn( center ) {
|
|
194
|
+
|
|
195
|
+
if ( ! center || ! this.controls ) return;
|
|
196
|
+
this.controls.target.copy( center );
|
|
197
|
+
this.controls.update();
|
|
198
|
+
this._onReset?.();
|
|
199
|
+
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// ── Aliases (match Sub-API surface) ───────────────────────────
|
|
203
|
+
|
|
204
|
+
/** The active Three.js PerspectiveCamera. */
|
|
205
|
+
get active() {
|
|
206
|
+
|
|
207
|
+
return this.camera;
|
|
208
|
+
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/** @see getCameraNames */
|
|
212
|
+
getNames() {
|
|
213
|
+
|
|
214
|
+
return this.getCameraNames();
|
|
215
|
+
|
|
216
|
+
}
|
|
217
|
+
|
|
153
218
|
// ── Auto-Focus ────────────────────────────────────────────────
|
|
154
219
|
|
|
155
220
|
setAutoFocusMode( mode ) {
|
|
@@ -201,7 +266,10 @@ export class CameraManager extends EventDispatcher {
|
|
|
201
266
|
* @param {Function} params.softReset - Callback for soft accumulation reset
|
|
202
267
|
* @param {Function} params.hardReset - Callback for hard accumulation reset
|
|
203
268
|
*/
|
|
204
|
-
updateAutoFocus(
|
|
269
|
+
updateAutoFocus( ctx ) {
|
|
270
|
+
|
|
271
|
+
const { meshScene, assetLoader, floorPlane, currentFocusDistance, pathTracer, setFocusDistance, softReset, hardReset } = ctx || this._afContext || {};
|
|
272
|
+
if ( ! meshScene ) return;
|
|
205
273
|
|
|
206
274
|
if ( this.autoFocusMode === 'manual' ) return;
|
|
207
275
|
|
|
@@ -303,4 +371,54 @@ export class CameraManager extends EventDispatcher {
|
|
|
303
371
|
|
|
304
372
|
}
|
|
305
373
|
|
|
374
|
+
/**
|
|
375
|
+
* Deferred dependency injection — InteractionManager needs the camera
|
|
376
|
+
* in its constructor, so it can't be passed during CameraManager creation.
|
|
377
|
+
* @param {import('./InteractionManager.js').InteractionManager} interactionManager
|
|
378
|
+
*/
|
|
379
|
+
setInteractionManager( interactionManager ) {
|
|
380
|
+
|
|
381
|
+
this.interactionManager = interactionManager;
|
|
382
|
+
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* Initialises the stable auto-focus context. Call once after all
|
|
387
|
+
* managers and stages are ready. CameraManager stores the context
|
|
388
|
+
* and `updateAutoFocus()` reads from it each frame — no per-frame allocation.
|
|
389
|
+
*
|
|
390
|
+
* @param {Object} deps
|
|
391
|
+
* @param {import('three').Scene} deps.meshScene
|
|
392
|
+
* @param {import('../Processor/AssetLoader.js').AssetLoader} deps.assetLoader
|
|
393
|
+
* @param {import('three').Mesh} deps.floorPlane
|
|
394
|
+
* @param {import('../Stages/PathTracer.js').PathTracer} deps.pathTracer
|
|
395
|
+
* @param {import('../RenderSettings.js').RenderSettings} deps.settings
|
|
396
|
+
* @param {Function} deps.softReset
|
|
397
|
+
* @param {Function} deps.hardReset
|
|
398
|
+
*/
|
|
399
|
+
initAutoFocus( { meshScene, assetLoader, floorPlane, pathTracer, settings, softReset, hardReset } ) {
|
|
400
|
+
|
|
401
|
+
this._afContext = {
|
|
402
|
+
meshScene,
|
|
403
|
+
assetLoader,
|
|
404
|
+
floorPlane,
|
|
405
|
+
pathTracer,
|
|
406
|
+
setFocusDistance: ( d ) => settings.set( 'focusDistance', d, { silent: true } ),
|
|
407
|
+
softReset,
|
|
408
|
+
hardReset,
|
|
409
|
+
};
|
|
410
|
+
|
|
411
|
+
// Live getter — reads current value without allocation
|
|
412
|
+
Object.defineProperty( this._afContext, 'currentFocusDistance', {
|
|
413
|
+
get: () => settings.get( 'focusDistance' ),
|
|
414
|
+
} );
|
|
415
|
+
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
dispose() {
|
|
419
|
+
|
|
420
|
+
this.controls?.dispose();
|
|
421
|
+
|
|
422
|
+
}
|
|
423
|
+
|
|
306
424
|
}
|
|
@@ -20,7 +20,7 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
20
20
|
/**
|
|
21
21
|
* @param {Object} params
|
|
22
22
|
* @param {import('three/webgpu').WebGPURenderer} params.renderer
|
|
23
|
-
* @param {HTMLCanvasElement
|
|
23
|
+
* @param {HTMLCanvasElement} params.mainCanvas - The primary rendering canvas
|
|
24
24
|
* @param {import('three').Scene} params.scene
|
|
25
25
|
* @param {import('three').PerspectiveCamera} params.camera
|
|
26
26
|
* @param {Object} params.stages - Named references to pipeline stages
|
|
@@ -29,12 +29,13 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
29
29
|
* @param {Function} params.getSaturation - () => current saturation value
|
|
30
30
|
* @param {Function} params.getTransparentBg - () => boolean
|
|
31
31
|
*/
|
|
32
|
-
constructor( { renderer,
|
|
32
|
+
constructor( { renderer, mainCanvas, scene, camera, stages, pipeline, getExposure, getSaturation, getTransparentBg } ) {
|
|
33
33
|
|
|
34
34
|
super();
|
|
35
35
|
|
|
36
36
|
this.renderer = renderer;
|
|
37
|
-
this.
|
|
37
|
+
this.mainCanvas = mainCanvas;
|
|
38
|
+
this.denoiserCanvas = this._createDenoiserCanvas( mainCanvas );
|
|
38
39
|
this.scene = scene;
|
|
39
40
|
this.camera = camera;
|
|
40
41
|
this.pipeline = pipeline;
|
|
@@ -49,6 +50,74 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
49
50
|
this.denoiser = null;
|
|
50
51
|
this.upscaler = null;
|
|
51
52
|
|
|
53
|
+
// Resolution tracking — used for canvas restoration on reset
|
|
54
|
+
this._lastRenderWidth = 0;
|
|
55
|
+
this._lastRenderHeight = 0;
|
|
56
|
+
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
_createDenoiserCanvas( mainCanvas ) {
|
|
60
|
+
|
|
61
|
+
const parent = mainCanvas.parentNode;
|
|
62
|
+
if ( ! parent ) return null;
|
|
63
|
+
|
|
64
|
+
const dc = document.createElement( 'canvas' );
|
|
65
|
+
dc.width = mainCanvas.width;
|
|
66
|
+
dc.height = mainCanvas.height;
|
|
67
|
+
dc.style.width = `${mainCanvas.clientWidth}px`;
|
|
68
|
+
dc.style.height = `${mainCanvas.clientHeight}px`;
|
|
69
|
+
|
|
70
|
+
parent.insertBefore( dc, mainCanvas );
|
|
71
|
+
return dc;
|
|
72
|
+
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Updates the render resolution and propagates to denoiser/upscaler.
|
|
77
|
+
* @param {number} width
|
|
78
|
+
* @param {number} height
|
|
79
|
+
*/
|
|
80
|
+
setRenderSize( width, height ) {
|
|
81
|
+
|
|
82
|
+
this._lastRenderWidth = width;
|
|
83
|
+
this._lastRenderHeight = height;
|
|
84
|
+
this.denoiser?.setSize( width, height );
|
|
85
|
+
this.upscaler?.setBaseSize( width, height );
|
|
86
|
+
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Syncs the denoiser canvas CSS dimensions to match display size.
|
|
91
|
+
* @param {number} width
|
|
92
|
+
* @param {number} height
|
|
93
|
+
*/
|
|
94
|
+
syncCanvasStyle( width, height ) {
|
|
95
|
+
|
|
96
|
+
if ( this.denoiserCanvas ) {
|
|
97
|
+
|
|
98
|
+
this.denoiserCanvas.style.width = `${width}px`;
|
|
99
|
+
this.denoiserCanvas.style.height = `${height}px`;
|
|
100
|
+
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Restores the denoiser canvas to base render resolution after upscaling.
|
|
107
|
+
* @returns {boolean} true if the canvas was resized
|
|
108
|
+
*/
|
|
109
|
+
restoreBaseResolution() {
|
|
110
|
+
|
|
111
|
+
if ( ! this.denoiserCanvas || ! this._lastRenderWidth || ! this._lastRenderHeight ) return false;
|
|
112
|
+
|
|
113
|
+
const wasResized = this.denoiserCanvas.width !== this._lastRenderWidth
|
|
114
|
+
|| this.denoiserCanvas.height !== this._lastRenderHeight;
|
|
115
|
+
|
|
116
|
+
this.denoiserCanvas.width = this._lastRenderWidth;
|
|
117
|
+
this.denoiserCanvas.height = this._lastRenderHeight;
|
|
118
|
+
|
|
119
|
+
return wasResized;
|
|
120
|
+
|
|
52
121
|
}
|
|
53
122
|
|
|
54
123
|
/**
|
|
@@ -374,10 +443,227 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
374
443
|
|
|
375
444
|
}
|
|
376
445
|
|
|
446
|
+
if ( this.denoiserCanvas?.parentNode ) {
|
|
447
|
+
|
|
448
|
+
this.denoiserCanvas.parentNode.removeChild( this.denoiserCanvas );
|
|
449
|
+
this.denoiserCanvas = null;
|
|
450
|
+
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
// ── Injected Dependencies (set after construction) ───────────
|
|
456
|
+
|
|
457
|
+
/** @param {import('./OverlayManager.js').OverlayManager} overlayManager */
|
|
458
|
+
setOverlayManager( overlayManager ) {
|
|
459
|
+
|
|
460
|
+
this._overlayManager = overlayManager;
|
|
461
|
+
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
/** @param {Function} fn - () => void, triggers accumulation reset */
|
|
465
|
+
setResetCallback( fn ) {
|
|
466
|
+
|
|
467
|
+
this._onReset = fn;
|
|
468
|
+
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/** @param {import('../RenderSettings.js').RenderSettings} settings */
|
|
472
|
+
setSettings( settings ) {
|
|
473
|
+
|
|
474
|
+
this._settings = settings;
|
|
475
|
+
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
// ── Stage Parameter Forwarding ───────────────────────────────
|
|
479
|
+
// These methods match the DenoisingAPI surface so call sites need
|
|
480
|
+
// zero or minimal changes after facade removal.
|
|
481
|
+
|
|
482
|
+
/** Updates ASVGF stage parameters. */
|
|
483
|
+
setASVGFParams( params ) {
|
|
484
|
+
|
|
485
|
+
this._stages.asvgf?.updateParameters( params );
|
|
486
|
+
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
/** Toggles the ASVGF heatmap debug overlay. */
|
|
490
|
+
toggleASVGFHeatmap( enabled ) {
|
|
491
|
+
|
|
492
|
+
this._stages.asvgf?.toggleHeatmap?.( enabled );
|
|
493
|
+
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
/**
|
|
497
|
+
* Configures ASVGF for a specific render mode (multi-stage coordination).
|
|
498
|
+
* @param {Object} config - { enabled, temporalAlpha, atrousIterations, ... }
|
|
499
|
+
*/
|
|
500
|
+
configureASVGFForMode( config ) {
|
|
501
|
+
|
|
502
|
+
if ( ! this._stages.asvgf ) return;
|
|
503
|
+
|
|
504
|
+
this._stages.asvgf.enabled = config.enabled;
|
|
505
|
+
if ( this._stages.variance ) this._stages.variance.enabled = config.enabled;
|
|
506
|
+
if ( this._stages.bilateralFilter ) this._stages.bilateralFilter.enabled = config.enabled;
|
|
507
|
+
|
|
508
|
+
if ( config.enabled ) {
|
|
509
|
+
|
|
510
|
+
this._stages.asvgf.updateParameters( config );
|
|
511
|
+
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
/** Updates SSRC stage parameters. */
|
|
517
|
+
setSSRCParams( params ) {
|
|
518
|
+
|
|
519
|
+
this._stages.ssrc?.updateParameters( params );
|
|
520
|
+
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
/** Updates edge-aware filtering parameters. */
|
|
524
|
+
setEdgeAwareParams( params ) {
|
|
525
|
+
|
|
526
|
+
this._stages.edgeFilter?.updateUniforms( params );
|
|
527
|
+
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
/** Updates auto-exposure stage parameters. */
|
|
531
|
+
setAutoExposureParams( params ) {
|
|
532
|
+
|
|
533
|
+
this._stages.autoExposure?.updateParameters( params );
|
|
534
|
+
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
/**
|
|
538
|
+
* Updates adaptive sampling parameters (with settings bridge).
|
|
539
|
+
* @param {Object} params
|
|
540
|
+
*/
|
|
541
|
+
setAdaptiveSamplingParams( params ) {
|
|
542
|
+
|
|
543
|
+
if ( params.min !== undefined ) this._stages.pathTracer?.setAdaptiveSamplingMin( params.min );
|
|
544
|
+
if ( params.adaptiveSamplingMax !== undefined ) this._settings?.set( 'adaptiveSamplingMax', params.adaptiveSamplingMax );
|
|
545
|
+
this._stages.adaptiveSampling?.setAdaptiveSamplingParameters( params );
|
|
546
|
+
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
/** Toggles the adaptive sampling debug helper. */
|
|
550
|
+
toggleAdaptiveSamplingHelper( enabled ) {
|
|
551
|
+
|
|
552
|
+
this._stages.adaptiveSampling?.toggleHelper( enabled );
|
|
553
|
+
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
// ── OIDN ─────────────────────────────────────────────────────
|
|
557
|
+
|
|
558
|
+
/** Enables or disables Intel OIDN denoiser. */
|
|
559
|
+
setOIDNEnabled( enabled ) {
|
|
560
|
+
|
|
561
|
+
if ( this.denoiser ) this.denoiser.enabled = enabled;
|
|
562
|
+
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
/** Sets OIDN denoiser quality. */
|
|
566
|
+
setOIDNQuality( quality ) {
|
|
567
|
+
|
|
568
|
+
this.denoiser?.updateQuality( quality );
|
|
569
|
+
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
/** Enables or disables the OIDN tile helper overlay. */
|
|
573
|
+
setOIDNTileHelper( enabled ) {
|
|
574
|
+
|
|
575
|
+
this._setTileHelper( enabled );
|
|
576
|
+
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
/** Enables or disables the tile helper overlay. */
|
|
580
|
+
setTileHelperEnabled( enabled ) {
|
|
581
|
+
|
|
582
|
+
this._setTileHelper( enabled );
|
|
583
|
+
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
/** Enables or disables tile highlight. */
|
|
587
|
+
setTileHighlightEnabled( enabled ) {
|
|
588
|
+
|
|
589
|
+
this._setTileHelper( enabled );
|
|
590
|
+
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
// ── AI Upscaler ──────────────────────────────────────────────
|
|
594
|
+
|
|
595
|
+
/** Enables or disables the AI upscaler. */
|
|
596
|
+
setUpscalerEnabled( enabled ) {
|
|
597
|
+
|
|
598
|
+
if ( this.upscaler ) this.upscaler.enabled = enabled;
|
|
599
|
+
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
/** Sets the upscaler scale factor. */
|
|
603
|
+
setUpscalerScaleFactor( factor ) {
|
|
604
|
+
|
|
605
|
+
this.upscaler?.setScaleFactor( factor );
|
|
606
|
+
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
/** Sets the upscaler quality level. */
|
|
610
|
+
setUpscalerQuality( quality ) {
|
|
611
|
+
|
|
612
|
+
this.upscaler?.setQuality( quality );
|
|
613
|
+
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
// ── Convenience (match DenoisingAPI names with reset) ────────
|
|
617
|
+
|
|
618
|
+
/**
|
|
619
|
+
* Enables or disables auto-exposure (convenience wrapper).
|
|
620
|
+
* @param {boolean} enabled
|
|
621
|
+
*/
|
|
622
|
+
setAutoExposure( enabled ) {
|
|
623
|
+
|
|
624
|
+
this.setAutoExposureEnabled( enabled, this._getExposure() );
|
|
625
|
+
this._onReset?.();
|
|
626
|
+
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
/**
|
|
630
|
+
* Enables or disables adaptive sampling (convenience wrapper with settings bridge).
|
|
631
|
+
* @param {boolean} enabled
|
|
632
|
+
*/
|
|
633
|
+
setAdaptiveSampling( enabled ) {
|
|
634
|
+
|
|
635
|
+
this._settings?.set( 'useAdaptiveSampling', enabled );
|
|
636
|
+
this.setAdaptiveSamplingEnabled( enabled );
|
|
637
|
+
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
/**
|
|
641
|
+
* Switches strategy with automatic reset (convenience wrapper).
|
|
642
|
+
* @param {'none'|'asvgf'|'ssrc'|'edgeaware'} strategy
|
|
643
|
+
* @param {string} [asvgfPreset]
|
|
644
|
+
*/
|
|
645
|
+
setStrategy( strategy, asvgfPreset ) {
|
|
646
|
+
|
|
647
|
+
this.setDenoiserStrategy( strategy, asvgfPreset );
|
|
648
|
+
this._onReset?.();
|
|
649
|
+
|
|
377
650
|
}
|
|
378
651
|
|
|
379
652
|
// ── Private ───────────────────────────────────────────────────
|
|
380
653
|
|
|
654
|
+
_setTileHelper( enabled ) {
|
|
655
|
+
|
|
656
|
+
const tileHelper = this._overlayManager?.getHelper( 'tiles' );
|
|
657
|
+
if ( tileHelper ) {
|
|
658
|
+
|
|
659
|
+
tileHelper.enabled = enabled;
|
|
660
|
+
if ( ! enabled ) tileHelper.hide();
|
|
661
|
+
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
|
|
381
667
|
_getEffectiveExposure() {
|
|
382
668
|
|
|
383
669
|
return this._stages.autoExposure?.enabled
|
|
@@ -78,10 +78,103 @@ export class EnvironmentManager {
|
|
|
78
78
|
|
|
79
79
|
/**
|
|
80
80
|
* Optional callbacks set by the owning stage.
|
|
81
|
-
* @type {{ onReset?: Function, getSceneTextureNodes?: Function }}
|
|
81
|
+
* @type {{ onReset?: Function, onAutoExposureReset?: Function, getSceneTextureNodes?: Function }}
|
|
82
82
|
*/
|
|
83
83
|
this.callbacks = {};
|
|
84
84
|
|
|
85
|
+
// Mode state machine (absorbed from EnvironmentAPI)
|
|
86
|
+
this._previousHDRI = null;
|
|
87
|
+
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// ===== MODE STATE MACHINE =====
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Switches the environment mode (hdri, gradient, color, procedural).
|
|
94
|
+
* Preserves the HDRI texture when switching away, restores when switching back.
|
|
95
|
+
* @param {'hdri'|'gradient'|'color'|'procedural'} mode
|
|
96
|
+
*/
|
|
97
|
+
async setMode( mode ) {
|
|
98
|
+
|
|
99
|
+
const prev = this.envParams.mode;
|
|
100
|
+
this.envParams.mode = mode;
|
|
101
|
+
|
|
102
|
+
// Cache HDRI texture when leaving HDRI mode
|
|
103
|
+
if ( mode !== 'hdri' && prev === 'hdri' ) {
|
|
104
|
+
|
|
105
|
+
this._previousHDRI = this.environmentTexture;
|
|
106
|
+
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if ( mode === 'gradient' ) {
|
|
110
|
+
|
|
111
|
+
await this.generateGradientTexture();
|
|
112
|
+
|
|
113
|
+
} else if ( mode === 'color' ) {
|
|
114
|
+
|
|
115
|
+
await this.generateSolidColorTexture();
|
|
116
|
+
|
|
117
|
+
} else if ( mode === 'procedural' ) {
|
|
118
|
+
|
|
119
|
+
await this.generateProceduralSkyTexture();
|
|
120
|
+
|
|
121
|
+
} else if ( mode === 'hdri' && this._previousHDRI ) {
|
|
122
|
+
|
|
123
|
+
await this.setEnvironmentMap( this._previousHDRI );
|
|
124
|
+
this._previousHDRI = null;
|
|
125
|
+
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
this.markDirty();
|
|
129
|
+
this.callbacks.onAutoExposureReset?.();
|
|
130
|
+
this._notifyReset();
|
|
131
|
+
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Marks the environment texture as needing GPU re-upload on the next frame.
|
|
136
|
+
*/
|
|
137
|
+
markDirty() {
|
|
138
|
+
|
|
139
|
+
if ( this.environmentTexture ) this.environmentTexture.needsUpdate = true;
|
|
140
|
+
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// ===== Aliases (match Sub-API surface for zero-churn migration) =====
|
|
144
|
+
|
|
145
|
+
/** @see envParams */
|
|
146
|
+
get params() {
|
|
147
|
+
|
|
148
|
+
return this.envParams;
|
|
149
|
+
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/** @see environmentTexture */
|
|
153
|
+
get texture() {
|
|
154
|
+
|
|
155
|
+
return this.environmentTexture;
|
|
156
|
+
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/** @see generateGradientTexture */
|
|
160
|
+
generateGradient() {
|
|
161
|
+
|
|
162
|
+
return this.generateGradientTexture();
|
|
163
|
+
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/** @see generateSolidColorTexture */
|
|
167
|
+
generateSolid() {
|
|
168
|
+
|
|
169
|
+
return this.generateSolidColorTexture();
|
|
170
|
+
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/** @see generateProceduralSkyTexture */
|
|
174
|
+
generateProcedural() {
|
|
175
|
+
|
|
176
|
+
return this.generateProceduralSkyTexture();
|
|
177
|
+
|
|
85
178
|
}
|
|
86
179
|
|
|
87
180
|
// ===== CDF STORAGE BUFFERS =====
|