rayzee 7.15.1 → 7.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/rayzee.es.js +219 -122
- package/dist/rayzee.es.js.map +1 -1
- package/dist/rayzee.umd.js +5 -5
- package/dist/rayzee.umd.js.map +1 -1
- package/package.json +1 -1
- package/src/PathTracerApp.js +113 -20
- package/src/Processor/EmissiveTriangleBuilder.js +74 -20
- package/src/Processor/SceneProcessor.js +35 -5
- package/src/RenderSettings.js +4 -2
- package/src/Stages/PathTracer.js +14 -0
- package/src/Stages/PathTracerStage.js +36 -8
- package/src/TSL/EmissiveSampling.js +11 -2
- package/src/managers/CameraManager.js +160 -9
|
@@ -35,6 +35,9 @@ export class CameraManager extends EventDispatcher {
|
|
|
35
35
|
this.cameras = [ this.camera ];
|
|
36
36
|
this.currentCameraIndex = 0;
|
|
37
37
|
|
|
38
|
+
// Monotonic counter for naming user-added cameras (reset when the list is replaced).
|
|
39
|
+
this._userCameraCounter = 0;
|
|
40
|
+
|
|
38
41
|
// Auto-focus state
|
|
39
42
|
this.autoFocusMode = AF_DEFAULTS.SMOOTHING_FACTOR ? 'auto' : 'manual';
|
|
40
43
|
this.afScreenPoint = { x: 0.5, y: 0.5 };
|
|
@@ -51,6 +54,7 @@ export class CameraManager extends EventDispatcher {
|
|
|
51
54
|
this._onResize = null;
|
|
52
55
|
this._onReset = null;
|
|
53
56
|
this._getSettings = null;
|
|
57
|
+
this._applySettings = null;
|
|
54
58
|
|
|
55
59
|
}
|
|
56
60
|
|
|
@@ -61,6 +65,70 @@ export class CameraManager extends EventDispatcher {
|
|
|
61
65
|
setCameras( cameras ) {
|
|
62
66
|
|
|
63
67
|
this.cameras = cameras;
|
|
68
|
+
this._userCameraCounter = 0;
|
|
69
|
+
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Adds a new user camera that snapshots the current render camera's pose,
|
|
74
|
+
* FOV, clip planes, and orbit target. The snapshot is a standalone template
|
|
75
|
+
* appended to the list; switching to it restores this exact framing.
|
|
76
|
+
*
|
|
77
|
+
* @param {string} [name] - Optional display name (auto-generated otherwise).
|
|
78
|
+
* @returns {number} The index of the newly added camera.
|
|
79
|
+
*/
|
|
80
|
+
addCameraFromView( name ) {
|
|
81
|
+
|
|
82
|
+
const src = this.camera;
|
|
83
|
+
const cam = new PerspectiveCamera( src.fov, src.aspect, src.near, src.far );
|
|
84
|
+
cam.position.copy( src.position );
|
|
85
|
+
cam.quaternion.copy( src.quaternion );
|
|
86
|
+
cam.updateMatrixWorld( true );
|
|
87
|
+
|
|
88
|
+
cam.userData.__rayzeeUserCamera = true;
|
|
89
|
+
cam.userData.__rayzeeEffects = this._captureEffects();
|
|
90
|
+
if ( this.controls ) cam.userData.__rayzeeOrbitTarget = this.controls.target.clone();
|
|
91
|
+
|
|
92
|
+
this._userCameraCounter += 1;
|
|
93
|
+
cam.name = name || `View Camera ${this._userCameraCounter}`;
|
|
94
|
+
|
|
95
|
+
this.cameras.push( cam );
|
|
96
|
+
return this.cameras.length - 1;
|
|
97
|
+
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Removes a user-added camera by index. Built-in (index 0) and
|
|
102
|
+
* model-embedded cameras are protected and cannot be removed.
|
|
103
|
+
* If the active camera is removed, falls back to the default camera.
|
|
104
|
+
*
|
|
105
|
+
* @param {number} index
|
|
106
|
+
* @returns {boolean} true if a camera was removed.
|
|
107
|
+
*/
|
|
108
|
+
removeCamera( index ) {
|
|
109
|
+
|
|
110
|
+
if ( ! Number.isInteger( index ) || index <= 0 || index >= this.cameras.length ) return false;
|
|
111
|
+
if ( ! this.cameras[ index ]?.userData?.__rayzeeUserCamera ) return false;
|
|
112
|
+
|
|
113
|
+
const wasActive = this.currentCameraIndex === index;
|
|
114
|
+
this.cameras.splice( index, 1 );
|
|
115
|
+
|
|
116
|
+
if ( wasActive ) {
|
|
117
|
+
|
|
118
|
+
// The active camera is gone. Invalidate currentCameraIndex before falling
|
|
119
|
+
// back so switchCamera(0) skips both the (deleted) outgoing-effects save and
|
|
120
|
+
// the default-state save, and runs the restore path instead.
|
|
121
|
+
this.currentCameraIndex = - 1;
|
|
122
|
+
this.switchCamera( 0 );
|
|
123
|
+
|
|
124
|
+
} else if ( this.currentCameraIndex > index ) {
|
|
125
|
+
|
|
126
|
+
// Indices after the removed slot shift down by one.
|
|
127
|
+
this.currentCameraIndex -= 1;
|
|
128
|
+
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return true;
|
|
64
132
|
|
|
65
133
|
}
|
|
66
134
|
|
|
@@ -86,15 +154,74 @@ export class CameraManager extends EventDispatcher {
|
|
|
86
154
|
* Call once after all managers are ready.
|
|
87
155
|
*
|
|
88
156
|
* @param {Object} callbacks
|
|
89
|
-
* @param {Function} callbacks.onResize
|
|
90
|
-
* @param {Function} callbacks.onReset
|
|
91
|
-
* @param {Function} callbacks.getSettings
|
|
157
|
+
* @param {Function} callbacks.onResize - Trigger viewport resize
|
|
158
|
+
* @param {Function} callbacks.onReset - Trigger accumulation reset
|
|
159
|
+
* @param {Function} callbacks.getSettings - (key) => value
|
|
160
|
+
* @param {Function} callbacks.applySettings - (updates) => void, batch-writes render settings
|
|
92
161
|
*/
|
|
93
|
-
initCallbacks( { onResize, onReset, getSettings } ) {
|
|
162
|
+
initCallbacks( { onResize, onReset, getSettings, applySettings } ) {
|
|
94
163
|
|
|
95
164
|
this._onResize = onResize;
|
|
96
165
|
this._onReset = onReset;
|
|
97
166
|
this._getSettings = getSettings;
|
|
167
|
+
this._applySettings = applySettings;
|
|
168
|
+
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// ── Per-camera effects (DOF / focus) ──────────────────────────
|
|
172
|
+
// Each camera keeps its own depth-of-field + focus configuration so effects
|
|
173
|
+
// defined on one camera don't leak to another. State is stored on the camera
|
|
174
|
+
// object's userData and swapped in/out on switchCamera().
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Snapshot the current global DOF/focus settings into a plain object.
|
|
178
|
+
* focusDistance is stored scaled (as held in RenderSettings).
|
|
179
|
+
* @returns {Object|null}
|
|
180
|
+
*/
|
|
181
|
+
_captureEffects() {
|
|
182
|
+
|
|
183
|
+
const get = this._getSettings;
|
|
184
|
+
if ( ! get ) return null;
|
|
185
|
+
|
|
186
|
+
return {
|
|
187
|
+
enableDOF: get( 'enableDOF' ),
|
|
188
|
+
focusDistance: get( 'focusDistance' ),
|
|
189
|
+
aperture: get( 'aperture' ),
|
|
190
|
+
focalLength: get( 'focalLength' ),
|
|
191
|
+
apertureScale: get( 'apertureScale' ),
|
|
192
|
+
anamorphicRatio: get( 'anamorphicRatio' ),
|
|
193
|
+
autoFocusMode: this.autoFocusMode,
|
|
194
|
+
afScreenPoint: { ...this.afScreenPoint },
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Apply a previously-captured effects object to the global settings + focus state.
|
|
201
|
+
* @param {Object} [eff]
|
|
202
|
+
*/
|
|
203
|
+
_applyEffects( eff ) {
|
|
204
|
+
|
|
205
|
+
if ( ! eff ) return;
|
|
206
|
+
|
|
207
|
+
this._applySettings?.( {
|
|
208
|
+
enableDOF: eff.enableDOF,
|
|
209
|
+
focusDistance: eff.focusDistance,
|
|
210
|
+
aperture: eff.aperture,
|
|
211
|
+
focalLength: eff.focalLength,
|
|
212
|
+
apertureScale: eff.apertureScale,
|
|
213
|
+
anamorphicRatio: eff.anamorphicRatio,
|
|
214
|
+
} );
|
|
215
|
+
|
|
216
|
+
if ( eff.autoFocusMode !== undefined ) this.setAutoFocusMode( eff.autoFocusMode );
|
|
217
|
+
if ( eff.afScreenPoint ) this.setAFScreenPoint( eff.afScreenPoint.x, eff.afScreenPoint.y );
|
|
218
|
+
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/** Scene scale used to convert scaled focusDistance to UI-facing units. */
|
|
222
|
+
_getSceneScale() {
|
|
223
|
+
|
|
224
|
+
return this._afContext?.assetLoader?.getSceneScale?.() || 1;
|
|
98
225
|
|
|
99
226
|
}
|
|
100
227
|
|
|
@@ -122,6 +249,10 @@ export class CameraManager extends EventDispatcher {
|
|
|
122
249
|
|
|
123
250
|
}
|
|
124
251
|
|
|
252
|
+
// Save the outgoing camera's DOF/focus effects so they can be restored later.
|
|
253
|
+
const outgoing = this.cameras[ this.currentCameraIndex ];
|
|
254
|
+
if ( outgoing ) outgoing.userData.__rayzeeEffects = this._captureEffects();
|
|
255
|
+
|
|
125
256
|
// Save default camera state before switching away from it
|
|
126
257
|
if ( this.currentCameraIndex === 0 && index !== 0 ) {
|
|
127
258
|
|
|
@@ -169,21 +300,41 @@ export class CameraManager extends EventDispatcher {
|
|
|
169
300
|
this.camera.updateProjectionMatrix();
|
|
170
301
|
this.camera.updateMatrixWorld( true );
|
|
171
302
|
|
|
172
|
-
//
|
|
303
|
+
// Restore the saved orbit target for user cameras; otherwise place it
|
|
304
|
+
// along the forward direction at the focus distance.
|
|
173
305
|
if ( this.controls ) {
|
|
174
306
|
|
|
175
|
-
const
|
|
176
|
-
|
|
177
|
-
|
|
307
|
+
const savedTarget = sourceCamera.userData?.__rayzeeOrbitTarget;
|
|
308
|
+
if ( savedTarget ) {
|
|
309
|
+
|
|
310
|
+
this.controls.target.copy( savedTarget );
|
|
311
|
+
|
|
312
|
+
} else {
|
|
313
|
+
|
|
314
|
+
const forward = new Vector3( 0, 0, - 1 ).applyQuaternion( sourceCamera.quaternion );
|
|
315
|
+
const focusDist = focusDistance || 5.0;
|
|
316
|
+
this.controls.target.copy( this.camera.position ).addScaledVector( forward, focusDist );
|
|
317
|
+
|
|
318
|
+
}
|
|
319
|
+
|
|
178
320
|
this.controls.update();
|
|
179
321
|
|
|
180
322
|
}
|
|
181
323
|
|
|
182
324
|
}
|
|
183
325
|
|
|
326
|
+
// Restore the incoming camera's own DOF/focus effects (if it has any saved;
|
|
327
|
+
// otherwise it inherits the current global config).
|
|
328
|
+
this._applyEffects( this.cameras[ index ]?.userData?.__rayzeeEffects );
|
|
329
|
+
|
|
184
330
|
onResize?.();
|
|
185
331
|
onReset?.();
|
|
186
|
-
|
|
332
|
+
|
|
333
|
+
// Emit UI-facing effects: focusDistance unscaled (matching AUTO_FOCUS_UPDATED),
|
|
334
|
+
// so the adapter is a plain passthrough with no scene-scale awareness.
|
|
335
|
+
const effects = this._captureEffects();
|
|
336
|
+
if ( effects ) effects.focusDistance /= this._getSceneScale();
|
|
337
|
+
this.dispatchEvent( { type: 'CameraSwitched', cameraIndex: index, effects, fov: this.camera.fov } );
|
|
187
338
|
|
|
188
339
|
}
|
|
189
340
|
|