rayzee 4.8.15 → 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 +1910 -2175
- 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 +25 -1
- package/src/Processor/SceneProcessor.js +146 -0
- package/src/Processor/TLASBuilder.js +61 -30
- package/src/RenderSettings.js +82 -4
- 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
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
Mesh,
|
|
6
6
|
MeshBasicMaterial
|
|
7
7
|
} from 'three';
|
|
8
|
+
import { EngineEvents } from '../EngineEvents.js';
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* InteractionManager
|
|
@@ -65,6 +66,91 @@ export class InteractionManager extends EventDispatcher {
|
|
|
65
66
|
this.canvas.addEventListener( 'pointerup', this.handleContextPointerUp );
|
|
66
67
|
this.canvas.addEventListener( 'contextmenu', this.handleContextMenu );
|
|
67
68
|
|
|
69
|
+
// Cross-manager dependencies (injected after init via setDependencies)
|
|
70
|
+
this._overlayManager = null;
|
|
71
|
+
this._transformManager = null;
|
|
72
|
+
this._appDispatch = null;
|
|
73
|
+
this._orbitControls = null;
|
|
74
|
+
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// ==================== CROSS-MANAGER COORDINATION ====================
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Inject dependencies needed for select/deselect coordination.
|
|
81
|
+
* Call once after all managers are created.
|
|
82
|
+
*
|
|
83
|
+
* @param {Object} deps
|
|
84
|
+
* @param {import('./OverlayManager.js').OverlayManager} deps.overlayManager
|
|
85
|
+
* @param {import('./TransformManager.js').TransformManager} deps.transformManager
|
|
86
|
+
* @param {Function} deps.appDispatch - (event) => dispatches on PathTracerApp
|
|
87
|
+
* @param {import('three/addons/controls/OrbitControls.js').OrbitControls} [deps.orbitControls]
|
|
88
|
+
*/
|
|
89
|
+
setDependencies( { overlayManager, transformManager, appDispatch, orbitControls } ) {
|
|
90
|
+
|
|
91
|
+
this._overlayManager = overlayManager || null;
|
|
92
|
+
this._transformManager = transformManager || null;
|
|
93
|
+
this._appDispatch = appDispatch || null;
|
|
94
|
+
this._orbitControls = orbitControls || null;
|
|
95
|
+
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Programmatically selects an object (or deselects if null).
|
|
100
|
+
* Coordinates: outline helper, internal state, transform gizmo, and event dispatch.
|
|
101
|
+
* @param {import('three').Object3D|null} object
|
|
102
|
+
*/
|
|
103
|
+
select( object ) {
|
|
104
|
+
|
|
105
|
+
const outline = this._overlayManager?.getHelper( 'outline' );
|
|
106
|
+
if ( outline ) outline.setSelectedObjects( object ? [ object ] : [] );
|
|
107
|
+
|
|
108
|
+
this.selectedObject = object || null;
|
|
109
|
+
|
|
110
|
+
if ( object ) {
|
|
111
|
+
|
|
112
|
+
this._transformManager?.attach( object );
|
|
113
|
+
|
|
114
|
+
} else {
|
|
115
|
+
|
|
116
|
+
this._transformManager?.detach();
|
|
117
|
+
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
this._appDispatch?.( { type: EngineEvents.OBJECT_SELECTED, object: object || null } );
|
|
121
|
+
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Deselects the current object.
|
|
126
|
+
*/
|
|
127
|
+
deselect() {
|
|
128
|
+
|
|
129
|
+
this.select( null );
|
|
130
|
+
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Disables selection mode and detaches the transform gizmo.
|
|
135
|
+
*/
|
|
136
|
+
disableMode() {
|
|
137
|
+
|
|
138
|
+
this.disableSelectMode();
|
|
139
|
+
this._transformManager?.detach();
|
|
140
|
+
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Subscribes to an interaction event.
|
|
145
|
+
* @param {string} type - Event type
|
|
146
|
+
* @param {Function} handler - Event handler
|
|
147
|
+
* @returns {Function} Unsubscribe function
|
|
148
|
+
*/
|
|
149
|
+
on( type, handler ) {
|
|
150
|
+
|
|
151
|
+
this.addEventListener( type, handler );
|
|
152
|
+
return () => this.removeEventListener( type, handler );
|
|
153
|
+
|
|
68
154
|
}
|
|
69
155
|
|
|
70
156
|
// ==================== FOCUS MODE ====================
|
|
@@ -91,6 +177,9 @@ export class InteractionManager extends EventDispatcher {
|
|
|
91
177
|
|
|
92
178
|
}
|
|
93
179
|
|
|
180
|
+
// Disable orbit controls when focus mode is active
|
|
181
|
+
if ( this._orbitControls ) this._orbitControls.enabled = ! this.focusMode;
|
|
182
|
+
|
|
94
183
|
// Emit event for external listeners
|
|
95
184
|
this.dispatchEvent( {
|
|
96
185
|
type: 'focusModeChanged',
|
|
@@ -598,6 +687,59 @@ export class InteractionManager extends EventDispatcher {
|
|
|
598
687
|
|
|
599
688
|
// ==================== LIFECYCLE ====================
|
|
600
689
|
|
|
690
|
+
/**
|
|
691
|
+
* Wires interaction events to app-level dispatches and side-effects.
|
|
692
|
+
* Call once during init after selection sub-API is available on the app.
|
|
693
|
+
*
|
|
694
|
+
* @param {import('../PathTracerApp.js').PathTracerApp} app
|
|
695
|
+
*/
|
|
696
|
+
wireAppEvents( app ) {
|
|
697
|
+
|
|
698
|
+
this.addEventListener( 'objectSelected', ( event ) => {
|
|
699
|
+
|
|
700
|
+
this.select( event.object );
|
|
701
|
+
app.refreshFrame();
|
|
702
|
+
app.dispatchEvent( { type: 'objectSelected', object: event.object, uuid: event.uuid } );
|
|
703
|
+
|
|
704
|
+
} );
|
|
705
|
+
|
|
706
|
+
this.addEventListener( 'objectDeselected', ( event ) => {
|
|
707
|
+
|
|
708
|
+
this.select( null );
|
|
709
|
+
app.refreshFrame();
|
|
710
|
+
app.dispatchEvent( { type: 'objectDeselected', object: event.object, uuid: event.uuid } );
|
|
711
|
+
|
|
712
|
+
} );
|
|
713
|
+
|
|
714
|
+
this.addEventListener( 'selectModeChanged', ( event ) => {
|
|
715
|
+
|
|
716
|
+
app.dispatchEvent( { type: EngineEvents.SELECT_MODE_CHANGED, enabled: event.enabled } );
|
|
717
|
+
|
|
718
|
+
} );
|
|
719
|
+
|
|
720
|
+
this.addEventListener( 'objectDoubleClicked', ( event ) => {
|
|
721
|
+
|
|
722
|
+
this.select( event.object );
|
|
723
|
+
app.refreshFrame();
|
|
724
|
+
app.dispatchEvent( { type: EngineEvents.OBJECT_DOUBLE_CLICKED, object: event.object, uuid: event.uuid } );
|
|
725
|
+
|
|
726
|
+
} );
|
|
727
|
+
|
|
728
|
+
this.addEventListener( 'focusChanged', ( event ) => {
|
|
729
|
+
|
|
730
|
+
app.settings.set( 'focusDistance', event.worldDistance );
|
|
731
|
+
app.dispatchEvent( { type: 'focusChanged', distance: event.distance } );
|
|
732
|
+
|
|
733
|
+
} );
|
|
734
|
+
|
|
735
|
+
this.addEventListener( 'afPointPlaced', ( event ) => {
|
|
736
|
+
|
|
737
|
+
app.dispatchEvent( { type: EngineEvents.AF_POINT_PLACED, point: event.point } );
|
|
738
|
+
|
|
739
|
+
} );
|
|
740
|
+
|
|
741
|
+
}
|
|
742
|
+
|
|
601
743
|
/**
|
|
602
744
|
* Clean up all event listeners and state
|
|
603
745
|
*/
|
|
@@ -15,14 +15,17 @@ export class LightManager extends EventDispatcher {
|
|
|
15
15
|
* @param {import('three').Scene} scene - WebGPU light scene
|
|
16
16
|
* @param {import('../SceneHelpers.js').SceneHelpers} sceneHelpers
|
|
17
17
|
* @param {import('../Stages/PathTracer.js').PathTracer} pathTracer
|
|
18
|
+
* @param {Object} [options]
|
|
19
|
+
* @param {Function} [options.onReset] - Callback to reset accumulation after light changes
|
|
18
20
|
*/
|
|
19
|
-
constructor( scene, sceneHelpers, pathTracer ) {
|
|
21
|
+
constructor( scene, sceneHelpers, pathTracer, options = {} ) {
|
|
20
22
|
|
|
21
23
|
super();
|
|
22
24
|
|
|
23
25
|
this.scene = scene;
|
|
24
26
|
this.sceneHelpers = sceneHelpers;
|
|
25
27
|
this.pathTracer = pathTracer;
|
|
28
|
+
this._onReset = options.onReset || null;
|
|
26
29
|
|
|
27
30
|
}
|
|
28
31
|
|
|
@@ -78,6 +81,7 @@ export class LightManager extends EventDispatcher {
|
|
|
78
81
|
this.scene.add( light );
|
|
79
82
|
this.updateLights();
|
|
80
83
|
this._syncHelpers();
|
|
84
|
+
this._onReset?.();
|
|
81
85
|
|
|
82
86
|
return this._buildDescriptor( light );
|
|
83
87
|
|
|
@@ -97,6 +101,7 @@ export class LightManager extends EventDispatcher {
|
|
|
97
101
|
if ( light.target ) light.target.removeFromParent();
|
|
98
102
|
light.removeFromParent();
|
|
99
103
|
this.updateLights();
|
|
104
|
+
this._onReset?.();
|
|
100
105
|
return true;
|
|
101
106
|
|
|
102
107
|
}
|
|
@@ -109,6 +114,7 @@ export class LightManager extends EventDispatcher {
|
|
|
109
114
|
this.sceneHelpers.clear();
|
|
110
115
|
this._removeAllLights();
|
|
111
116
|
this.updateLights();
|
|
117
|
+
this._onReset?.();
|
|
112
118
|
|
|
113
119
|
}
|
|
114
120
|
|
|
@@ -205,6 +211,50 @@ export class LightManager extends EventDispatcher {
|
|
|
205
211
|
|
|
206
212
|
}
|
|
207
213
|
|
|
214
|
+
// ── Aliases (match Sub-API surface for zero-churn migration) ──
|
|
215
|
+
|
|
216
|
+
/** @see addLight */
|
|
217
|
+
add( type ) {
|
|
218
|
+
|
|
219
|
+
return this.addLight( type );
|
|
220
|
+
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/** @see removeLight */
|
|
224
|
+
remove( uuid ) {
|
|
225
|
+
|
|
226
|
+
return this.removeLight( uuid );
|
|
227
|
+
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/** @see clearLights */
|
|
231
|
+
clear() {
|
|
232
|
+
|
|
233
|
+
this.clearLights();
|
|
234
|
+
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/** @see getLights */
|
|
238
|
+
getAll() {
|
|
239
|
+
|
|
240
|
+
return this.getLights();
|
|
241
|
+
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/** @see updateLights */
|
|
245
|
+
sync() {
|
|
246
|
+
|
|
247
|
+
this.updateLights();
|
|
248
|
+
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/** @see setShowLightHelper */
|
|
252
|
+
showHelpers( show ) {
|
|
253
|
+
|
|
254
|
+
this.setShowLightHelper( show );
|
|
255
|
+
|
|
256
|
+
}
|
|
257
|
+
|
|
208
258
|
// ── Private ───────────────────────────────────────────────────
|
|
209
259
|
|
|
210
260
|
/** Syncs helpers in sceneHelpers with current scene lights. */
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import { TileHelper } from './helpers/TileHelper.js';
|
|
2
|
+
import { OutlineHelper } from './helpers/OutlineHelper.js';
|
|
3
|
+
import { EngineEvents } from '../EngineEvents.js';
|
|
4
|
+
|
|
1
5
|
/**
|
|
2
6
|
* OverlayManager — Unified overlay system for visual helpers.
|
|
3
7
|
*
|
|
@@ -63,6 +67,99 @@ export class OverlayManager {
|
|
|
63
67
|
|
|
64
68
|
}
|
|
65
69
|
|
|
70
|
+
// ═══════════════════════════════════════════════════════════════
|
|
71
|
+
// Default helpers setup
|
|
72
|
+
// ═══════════════════════════════════════════════════════════════
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Creates and wires the default overlay helpers (tile progress, outline).
|
|
76
|
+
* Call once during app init after pipeline and managers are ready.
|
|
77
|
+
*
|
|
78
|
+
* @param {Object} config
|
|
79
|
+
* @param {import('../SceneHelpers.js').SceneHelpers} config.helperScene
|
|
80
|
+
* @param {import('three').Scene} config.meshScene
|
|
81
|
+
* @param {import('../Pipeline/RenderPipeline.js').RenderPipeline} config.pipeline
|
|
82
|
+
* @param {import('./DenoisingManager.js').DenoisingManager} config.denoisingManager
|
|
83
|
+
* @param {import('three').EventDispatcher} config.app - App instance for resize/render-complete events
|
|
84
|
+
* @param {number} config.renderWidth
|
|
85
|
+
* @param {number} config.renderHeight
|
|
86
|
+
*/
|
|
87
|
+
setupDefaultHelpers( { helperScene, meshScene, pipeline, denoisingManager, app, renderWidth, renderHeight } ) {
|
|
88
|
+
|
|
89
|
+
this.setHelperScene( helperScene );
|
|
90
|
+
|
|
91
|
+
// ── Tile helper (shared across path tracer, OIDN, upscaler) ──
|
|
92
|
+
const tileHelper = new TileHelper();
|
|
93
|
+
this.register( 'tiles', tileHelper );
|
|
94
|
+
|
|
95
|
+
tileHelper.setRenderSize( renderWidth || 1, renderHeight || 1 );
|
|
96
|
+
|
|
97
|
+
app.addEventListener( 'resolution_changed', ( e ) => {
|
|
98
|
+
|
|
99
|
+
tileHelper.setRenderSize( e.width, e.height );
|
|
100
|
+
|
|
101
|
+
} );
|
|
102
|
+
|
|
103
|
+
// Path tracer tile events
|
|
104
|
+
pipeline.eventBus.on( 'tile:changed', ( e ) => {
|
|
105
|
+
|
|
106
|
+
if ( e.renderMode === 1 && e.tileBounds ) {
|
|
107
|
+
|
|
108
|
+
tileHelper.setActiveTile( e.tileBounds );
|
|
109
|
+
tileHelper.show();
|
|
110
|
+
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
} );
|
|
114
|
+
|
|
115
|
+
pipeline.eventBus.on( 'pipeline:reset', () => tileHelper.hide() );
|
|
116
|
+
app.addEventListener( EngineEvents.RENDER_COMPLETE, () => tileHelper.hide() );
|
|
117
|
+
|
|
118
|
+
// OIDN/upscaler tile events
|
|
119
|
+
this._wireDenoiserTileEvents( tileHelper, denoisingManager );
|
|
120
|
+
|
|
121
|
+
// ── Outline helper ──
|
|
122
|
+
const outlineHelper = new OutlineHelper( this.renderer, meshScene, this.camera );
|
|
123
|
+
this.register( 'outline', outlineHelper );
|
|
124
|
+
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Wires denoiser/upscaler tile progress events to the tile helper.
|
|
129
|
+
* These fire while the animation loop is stopped, so we trigger manual HUD redraws.
|
|
130
|
+
*/
|
|
131
|
+
_wireDenoiserTileEvents( tileHelper, denoisingManager ) {
|
|
132
|
+
|
|
133
|
+
const sources = [ denoisingManager?.denoiser, denoisingManager?.upscaler ];
|
|
134
|
+
|
|
135
|
+
for ( const source of sources ) {
|
|
136
|
+
|
|
137
|
+
if ( ! source ) continue;
|
|
138
|
+
|
|
139
|
+
source.addEventListener( 'tileProgress', ( e ) => {
|
|
140
|
+
|
|
141
|
+
if ( e.tile ) {
|
|
142
|
+
|
|
143
|
+
tileHelper.setRenderSize( e.imageWidth, e.imageHeight );
|
|
144
|
+
tileHelper.setActiveTile( e.tile );
|
|
145
|
+
tileHelper.show();
|
|
146
|
+
this.refreshHUD();
|
|
147
|
+
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
} );
|
|
151
|
+
|
|
152
|
+
source.addEventListener( 'end', () => {
|
|
153
|
+
|
|
154
|
+
tileHelper.hide();
|
|
155
|
+
this.refreshHUD();
|
|
156
|
+
|
|
157
|
+
} );
|
|
158
|
+
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
}
|
|
162
|
+
|
|
66
163
|
// ═══════════════════════════════════════════════════════════════
|
|
67
164
|
// Helper registration
|
|
68
165
|
// ═══════════════════════════════════════════════════════════════
|
|
@@ -87,7 +87,7 @@ export class VideoRenderManager {
|
|
|
87
87
|
app.stages.pathTracer?.updateCompletionThreshold?.();
|
|
88
88
|
|
|
89
89
|
// Disable camera controls during render
|
|
90
|
-
if ( app.
|
|
90
|
+
if ( app.cameraManager.controls ) app.cameraManager.controls.enabled = false;
|
|
91
91
|
|
|
92
92
|
try {
|
|
93
93
|
|
|
@@ -132,7 +132,7 @@ export class VideoRenderManager {
|
|
|
132
132
|
if ( this._cancelled ) break;
|
|
133
133
|
|
|
134
134
|
// 5. Capture frame from output canvas
|
|
135
|
-
const canvas = app.
|
|
135
|
+
const canvas = app.getCanvas();
|
|
136
136
|
if ( canvas && onFrame ) {
|
|
137
137
|
|
|
138
138
|
const bitmap = await createImageBitmap( canvas );
|
|
@@ -205,7 +205,7 @@ export class VideoRenderManager {
|
|
|
205
205
|
|
|
206
206
|
while ( ! pathTracer.isComplete && ! this._cancelled ) {
|
|
207
207
|
|
|
208
|
-
app.
|
|
208
|
+
app.cameraManager.camera.updateMatrixWorld();
|
|
209
209
|
app.pipeline.render();
|
|
210
210
|
|
|
211
211
|
// Yield every 4 passes to keep UI responsive and update stats
|
|
@@ -280,7 +280,7 @@ export class VideoRenderManager {
|
|
|
280
280
|
samplesPerPixel: app.settings.get( 'samplesPerPixel' ),
|
|
281
281
|
transmissiveBounces: app.settings.get( 'transmissiveBounces' ),
|
|
282
282
|
renderMode: app.stages.pathTracer?.renderMode?.value,
|
|
283
|
-
controlsEnabled: app.
|
|
283
|
+
controlsEnabled: app.cameraManager.controls?.enabled,
|
|
284
284
|
oidnEnabled: app.denoisingManager?.denoiser?.enabled,
|
|
285
285
|
oidnQuality: app.denoisingManager?.denoiser?.quality,
|
|
286
286
|
wasPlaying: app.animationManager?.isPlaying,
|
|
@@ -306,13 +306,13 @@ export class VideoRenderManager {
|
|
|
306
306
|
|
|
307
307
|
if ( app.stages.pathTracer && state.renderMode !== undefined ) {
|
|
308
308
|
|
|
309
|
-
app.
|
|
309
|
+
app.stages.pathTracer?.setUniform( 'renderMode', parseInt( state.renderMode ) );
|
|
310
310
|
|
|
311
311
|
}
|
|
312
312
|
|
|
313
313
|
app.stages.pathTracer?.updateCompletionThreshold?.();
|
|
314
314
|
|
|
315
|
-
if ( app.
|
|
315
|
+
if ( app.cameraManager.controls ) app.cameraManager.controls.enabled = state.controlsEnabled ?? true;
|
|
316
316
|
|
|
317
317
|
if ( app.denoisingManager?.denoiser ) {
|
|
318
318
|
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import Stats from 'stats-gl';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Creates and configures a stats-gl performance panel.
|
|
5
|
+
*
|
|
6
|
+
* @param {import('three/webgpu').WebGPURenderer} renderer
|
|
7
|
+
* @param {HTMLElement} [container=document.body] - DOM element to mount the stats panel
|
|
8
|
+
* @returns {Stats}
|
|
9
|
+
*/
|
|
10
|
+
export function createStats( renderer, container ) {
|
|
11
|
+
|
|
12
|
+
const stats = new Stats( { horizontal: true, trackGPU: true } );
|
|
13
|
+
stats.dom.style.position = 'absolute';
|
|
14
|
+
stats.dom.style.top = 'unset';
|
|
15
|
+
stats.dom.style.bottom = '48px';
|
|
16
|
+
|
|
17
|
+
stats.init( renderer );
|
|
18
|
+
( container || document.body ).appendChild( stats.dom );
|
|
19
|
+
|
|
20
|
+
const foregroundColor = '#ffffff';
|
|
21
|
+
const backgroundColor = '#1e293b';
|
|
22
|
+
|
|
23
|
+
const gradient = stats.fpsPanel.context.createLinearGradient(
|
|
24
|
+
0, stats.fpsPanel.GRAPH_Y,
|
|
25
|
+
0, stats.fpsPanel.GRAPH_Y + stats.fpsPanel.GRAPH_HEIGHT
|
|
26
|
+
);
|
|
27
|
+
gradient.addColorStop( 0, foregroundColor );
|
|
28
|
+
|
|
29
|
+
stats.fpsPanel.fg = stats.msPanel.fg = foregroundColor;
|
|
30
|
+
stats.fpsPanel.bg = stats.msPanel.bg = backgroundColor;
|
|
31
|
+
stats.fpsPanel.gradient = stats.msPanel.gradient = gradient;
|
|
32
|
+
|
|
33
|
+
if ( stats.gpuPanel ) {
|
|
34
|
+
|
|
35
|
+
stats.gpuPanel.fg = foregroundColor;
|
|
36
|
+
stats.gpuPanel.bg = backgroundColor;
|
|
37
|
+
stats.gpuPanel.gradient = gradient;
|
|
38
|
+
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
stats.dom.style.display = '';
|
|
42
|
+
|
|
43
|
+
return stats;
|
|
44
|
+
|
|
45
|
+
}
|
package/src/api/AnimationAPI.js
DELETED
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Animation sub-API — playback controls for GLTF animation clips.
|
|
3
|
-
*
|
|
4
|
-
* Access via `engine.animation`.
|
|
5
|
-
*
|
|
6
|
-
* @example
|
|
7
|
-
* engine.animation.play(0);
|
|
8
|
-
* engine.animation.setSpeed(2);
|
|
9
|
-
* console.log(engine.animation.clips);
|
|
10
|
-
*/
|
|
11
|
-
export class AnimationAPI {
|
|
12
|
-
|
|
13
|
-
/** @param {import('../PathTracerApp.js').PathTracerApp} app */
|
|
14
|
-
constructor( app ) {
|
|
15
|
-
|
|
16
|
-
this._app = app;
|
|
17
|
-
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Plays an animation clip by index.
|
|
22
|
-
* @param {number} [clipIndex=0]
|
|
23
|
-
*/
|
|
24
|
-
play( clipIndex = 0 ) {
|
|
25
|
-
|
|
26
|
-
this._app.playAnimation( clipIndex );
|
|
27
|
-
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Pauses animation, preserving current time position.
|
|
32
|
-
*/
|
|
33
|
-
pause() {
|
|
34
|
-
|
|
35
|
-
this._app.pauseAnimation();
|
|
36
|
-
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Resumes animation from paused state.
|
|
41
|
-
*/
|
|
42
|
-
resume() {
|
|
43
|
-
|
|
44
|
-
this._app.resumeAnimation();
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Stops animation and resets to beginning.
|
|
50
|
-
*/
|
|
51
|
-
stop() {
|
|
52
|
-
|
|
53
|
-
this._app.stopAnimationPlayback();
|
|
54
|
-
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Sets playback speed multiplier.
|
|
59
|
-
* @param {number} speed - 1.0 = normal speed
|
|
60
|
-
*/
|
|
61
|
-
setSpeed( speed ) {
|
|
62
|
-
|
|
63
|
-
this._app.setAnimationSpeed( speed );
|
|
64
|
-
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Sets loop mode for animation playback.
|
|
69
|
-
* @param {boolean} loop - true for repeat, false for play-once
|
|
70
|
-
*/
|
|
71
|
-
setLoop( loop ) {
|
|
72
|
-
|
|
73
|
-
this._app.setAnimationLoop( loop );
|
|
74
|
-
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Available animation clips.
|
|
79
|
-
* @returns {{ index: number, name: string, duration: number }[]}
|
|
80
|
-
*/
|
|
81
|
-
get clips() {
|
|
82
|
-
|
|
83
|
-
return this._app.animationClips;
|
|
84
|
-
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
}
|
package/src/api/CameraAPI.js
DELETED
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Camera sub-API — camera switching, auto-focus, DOF, and raw Three.js access.
|
|
3
|
-
*
|
|
4
|
-
* Access via `engine.camera`.
|
|
5
|
-
*
|
|
6
|
-
* @example
|
|
7
|
-
* engine.camera.switch(1);
|
|
8
|
-
* engine.camera.active.fov = 60;
|
|
9
|
-
* engine.camera.controls.target.set(0, 1, 0);
|
|
10
|
-
*/
|
|
11
|
-
export class CameraAPI {
|
|
12
|
-
|
|
13
|
-
/** @param {import('../PathTracerApp.js').PathTracerApp} app */
|
|
14
|
-
constructor( app ) {
|
|
15
|
-
|
|
16
|
-
this._app = app;
|
|
17
|
-
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* The active Three.js PerspectiveCamera.
|
|
22
|
-
* @returns {import('three').PerspectiveCamera}
|
|
23
|
-
*/
|
|
24
|
-
get active() {
|
|
25
|
-
|
|
26
|
-
return this._app.cameraManager?.camera ?? this._app._camera;
|
|
27
|
-
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* The OrbitControls instance.
|
|
32
|
-
* @returns {import('three/addons/controls/OrbitControls.js').OrbitControls}
|
|
33
|
-
*/
|
|
34
|
-
get controls() {
|
|
35
|
-
|
|
36
|
-
return this._app.cameraManager?.controls ?? this._app._controls;
|
|
37
|
-
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Switches the active camera by index.
|
|
42
|
-
* @param {number} index
|
|
43
|
-
*/
|
|
44
|
-
switch( index ) {
|
|
45
|
-
|
|
46
|
-
this._app.switchCamera( index );
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Returns display names for all available cameras.
|
|
52
|
-
* @returns {string[]}
|
|
53
|
-
*/
|
|
54
|
-
getNames() {
|
|
55
|
-
|
|
56
|
-
return this._app.getCameraNames();
|
|
57
|
-
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Focuses the orbit camera on a world-space point.
|
|
62
|
-
* @param {import('three').Vector3} center
|
|
63
|
-
*/
|
|
64
|
-
focusOn( center ) {
|
|
65
|
-
|
|
66
|
-
this._app.focusOnPoint( center );
|
|
67
|
-
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Sets the auto-focus mode.
|
|
72
|
-
* @param {'auto'|'manual'} mode
|
|
73
|
-
*/
|
|
74
|
-
setAutoFocusMode( mode ) {
|
|
75
|
-
|
|
76
|
-
this._app.cameraManager?.setAutoFocusMode( mode );
|
|
77
|
-
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Sets the normalized AF screen point (0-1 range).
|
|
82
|
-
* @param {number} x
|
|
83
|
-
* @param {number} y
|
|
84
|
-
*/
|
|
85
|
-
setAFScreenPoint( x, y ) {
|
|
86
|
-
|
|
87
|
-
this._app.cameraManager?.setAFScreenPoint( x, y );
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Enters AF point placement interaction mode.
|
|
93
|
-
*/
|
|
94
|
-
enterAFPointPlacementMode() {
|
|
95
|
-
|
|
96
|
-
this._app.cameraManager?.enterAFPointPlacementMode();
|
|
97
|
-
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Exits AF point placement interaction mode.
|
|
102
|
-
*/
|
|
103
|
-
exitAFPointPlacementMode() {
|
|
104
|
-
|
|
105
|
-
this._app.cameraManager?.exitAFPointPlacementMode();
|
|
106
|
-
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
}
|