three-zoo 0.5.4 → 0.5.6

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/dist/index.js CHANGED
@@ -15,19 +15,15 @@ const MIN_FOV = 1;
15
15
  /** Maximum allowed field of view in degrees */
16
16
  const MAX_FOV = 179;
17
17
  /**
18
- * A camera that supports independent horizontal and vertical FOV settings.
19
- * Extends Three.js PerspectiveCamera to allow separate control over horizontal
20
- * and vertical fields of view.
18
+ * Camera with independent horizontal and vertical FOV settings.
21
19
  */
22
20
  class DualFovCamera extends PerspectiveCamera {
23
21
  /**
24
- * Creates a new DualFovCamera instance with independent horizontal and vertical FOV control.
25
- *
26
- * @param horizontalFov - Horizontal field of view in degrees. Must be between 1° and 179°. Defaults to 90°.
27
- * @param verticalFov - Vertical field of view in degrees. Must be between 1° and 179°. Defaults to 90°.
28
- * @param aspect - Camera aspect ratio (width/height). Defaults to 1.
29
- * @param near - Near clipping plane distance. Must be greater than 0. Defaults to 1.
30
- * @param far - Far clipping plane distance. Must be greater than near plane. Defaults to 1000.
22
+ * @param horizontalFov - Horizontal FOV in degrees (clamped 1-179°)
23
+ * @param verticalFov - Vertical FOV in degrees (clamped 1-179°)
24
+ * @param aspect - Aspect ratio (width/height)
25
+ * @param near - Near clipping plane distance
26
+ * @param far - Far clipping plane distance
31
27
  */
32
28
  constructor(horizontalFov = DEFAULT_HORIZONTAL_FOV, verticalFov = DEFAULT_VERTICAL_FOV, aspect = DEFAULT_ASPECT, near = DEFAULT_NEAR, far = DEFAULT_FAR) {
33
29
  super(verticalFov, aspect, near, far);
@@ -36,44 +32,36 @@ class DualFovCamera extends PerspectiveCamera {
36
32
  this.updateProjectionMatrix();
37
33
  }
38
34
  /**
39
- * Gets the current horizontal field of view in degrees.
40
- *
41
- * @returns The horizontal FOV value between 1° and 179°
35
+ * @returns Horizontal FOV in degrees
42
36
  */
43
37
  get horizontalFov() {
44
38
  return this._private_horizontalFovInternal;
45
39
  }
46
40
  /**
47
- * Gets the current vertical field of view in degrees.
48
- *
49
- * @returns The vertical FOV value between 1° and 179°
41
+ * @returns Vertical FOV in degrees
50
42
  */
51
43
  get verticalFov() {
52
44
  return this._private_verticalFovInternal;
53
45
  }
54
46
  /**
55
- * Sets the horizontal field of view in degrees.
56
- *
57
- * @param value - The horizontal FOV value in degrees. Will be clamped between 1° and 179°.
47
+ * @param value - Horizontal FOV in degrees (clamped 1-179°)
58
48
  */
59
49
  set horizontalFov(value) {
60
50
  this._private_horizontalFovInternal = MathUtils.clamp(value, MIN_FOV, MAX_FOV);
61
51
  this.updateProjectionMatrix();
62
52
  }
63
53
  /**
64
- * Sets the vertical field of view in degrees.
65
- *
66
- * @param value - The vertical FOV value in degrees. Will be clamped between 1° and 179°.
54
+ * @param value - Vertical FOV in degrees (clamped 1-179°)
67
55
  */
68
56
  set verticalFov(value) {
69
57
  this._private_verticalFovInternal = MathUtils.clamp(value, MIN_FOV, MAX_FOV);
70
58
  this.updateProjectionMatrix();
71
59
  }
72
60
  /**
73
- * Updates both horizontal and vertical field of view values simultaneously.
61
+ * Sets both FOV values.
74
62
  *
75
- * @param horizontal - Horizontal FOV in degrees. Will be clamped between and 179°.
76
- * @param vertical - Vertical FOV in degrees. Will be clamped between and 179°.
63
+ * @param horizontal - Horizontal FOV in degrees (clamped 1-179°)
64
+ * @param vertical - Vertical FOV in degrees (clamped 1-179°)
77
65
  */
78
66
  setFov(horizontal, vertical) {
79
67
  this._private_horizontalFovInternal = MathUtils.clamp(horizontal, MIN_FOV, MAX_FOV);
@@ -81,9 +69,9 @@ class DualFovCamera extends PerspectiveCamera {
81
69
  this.updateProjectionMatrix();
82
70
  }
83
71
  /**
84
- * Copies the field of view settings from another DualFovCamera instance.
72
+ * Copies FOV settings from another DualFovCamera.
85
73
  *
86
- * @param source - The DualFovCamera instance to copy FOV settings from.
74
+ * @param source - Source camera to copy from
87
75
  */
88
76
  copyFovSettings(source) {
89
77
  this._private_horizontalFovInternal = source.horizontalFov;
@@ -91,13 +79,10 @@ class DualFovCamera extends PerspectiveCamera {
91
79
  this.updateProjectionMatrix();
92
80
  }
93
81
  /**
94
- * Updates the projection matrix based on current FOV settings and aspect ratio.
82
+ * Updates projection matrix based on FOV and aspect ratio.
95
83
  *
96
- * The behavior differs based on orientation:
97
- * - **Landscape mode (aspect > 1)**: Preserves horizontal FOV, calculates vertical FOV
98
- * - **Portrait mode (aspect ≤ 1)**: Preserves vertical FOV, calculates horizontal FOV
99
- *
100
- * This method is automatically called when FOV values or aspect ratio changes.
84
+ * Landscape (aspect > 1): preserves horizontal FOV.
85
+ * Portrait (aspect 1): preserves vertical FOV.
101
86
  *
102
87
  * @override
103
88
  */
@@ -114,12 +99,9 @@ class DualFovCamera extends PerspectiveCamera {
114
99
  super.updateProjectionMatrix();
115
100
  }
116
101
  /**
117
- * Gets the actual horizontal field of view after aspect ratio adjustments.
118
- *
119
- * In landscape mode, this returns the set horizontal FOV.
120
- * In portrait mode, this calculates the actual horizontal FOV based on the vertical FOV and aspect ratio.
102
+ * Gets actual horizontal FOV after aspect ratio adjustments.
121
103
  *
122
- * @returns The actual horizontal FOV in degrees
104
+ * @returns Horizontal FOV in degrees
123
105
  */
124
106
  getActualHorizontalFov() {
125
107
  if (this.aspect >= 1) {
@@ -129,12 +111,9 @@ class DualFovCamera extends PerspectiveCamera {
129
111
  return MathUtils.radToDeg(Math.atan(Math.tan(verticalRadians / 2) * this.aspect) * 2);
130
112
  }
131
113
  /**
132
- * Gets the actual vertical field of view after aspect ratio adjustments.
133
- *
134
- * In portrait mode, this returns the set vertical FOV.
135
- * In landscape mode, this calculates the actual vertical FOV based on the horizontal FOV and aspect ratio.
114
+ * Gets actual vertical FOV after aspect ratio adjustments.
136
115
  *
137
- * @returns The actual vertical FOV in degrees
116
+ * @returns Vertical FOV in degrees
138
117
  */
139
118
  getActualVerticalFov() {
140
119
  if (this.aspect < 1) {
@@ -144,12 +123,9 @@ class DualFovCamera extends PerspectiveCamera {
144
123
  return MathUtils.radToDeg(Math.atan(Math.tan(horizontalRadians / 2) / this.aspect) * 2);
145
124
  }
146
125
  /**
147
- * Adjusts the vertical field of view to fit all specified points within the camera's view.
126
+ * Adjusts vertical FOV to fit points within camera view.
148
127
  *
149
- * This method calculates the required vertical FOV to ensure all provided vertices
150
- * are visible within the vertical bounds of the camera's frustum.
151
- *
152
- * @param vertices - Array of 3D points (in world coordinates) that should fit within the camera's vertical view
128
+ * @param vertices - Array of 3D points in world coordinates
153
129
  */
154
130
  fitVerticalFovToPoints(vertices) {
155
131
  const up = new Vector3(0, 1, 0).applyQuaternion(this.quaternion);
@@ -168,12 +144,9 @@ class DualFovCamera extends PerspectiveCamera {
168
144
  this.updateProjectionMatrix();
169
145
  }
170
146
  /**
171
- * Adjusts the vertical field of view to fit a bounding box within the camera's view.
172
- *
173
- * This method calculates the required vertical FOV to ensure the entire bounding box
174
- * is visible within the vertical bounds of the camera's frustum.
147
+ * Adjusts vertical FOV to fit bounding box within camera view.
175
148
  *
176
- * @param box - The 3D bounding box (in world coordinates) that should fit within the camera's vertical view
149
+ * @param box - 3D bounding box in world coordinates
177
150
  */
178
151
  fitVerticalFovToBox(box) {
179
152
  this.fitVerticalFovToPoints([
@@ -188,13 +161,10 @@ class DualFovCamera extends PerspectiveCamera {
188
161
  ]);
189
162
  }
190
163
  /**
191
- * Adjusts the vertical field of view to fit a skinned mesh within the camera's view.
164
+ * Adjusts vertical FOV to fit skinned mesh within camera view.
165
+ * Updates skeleton and applies bone transformations.
192
166
  *
193
- * This method updates the mesh's skeleton, applies bone transformations to all vertices,
194
- * and then calculates the required vertical FOV to ensure the entire deformed mesh
195
- * is visible within the vertical bounds of the camera's frustum.
196
- *
197
- * @param skinnedMesh - The skinned mesh (with active skeleton) that should fit within the camera's vertical view
167
+ * @param skinnedMesh - Skinned mesh with active skeleton
198
168
  */
199
169
  fitVerticalFovToMesh(skinnedMesh) {
200
170
  skinnedMesh.updateWorldMatrix(true, true);
@@ -211,17 +181,10 @@ class DualFovCamera extends PerspectiveCamera {
211
181
  this.fitVerticalFovToPoints(points);
212
182
  }
213
183
  /**
214
- * Points the camera to look at the center of mass of a skinned mesh.
215
- *
216
- * This method updates the mesh's skeleton, applies bone transformations to all vertices,
217
- * calculates the center of mass using a clustering algorithm, and then orients the camera
218
- * to look at that point.
219
- *
220
- * The center of mass calculation uses an iterative clustering approach to find the
221
- * main concentration of vertices, which provides better results than a simple average
222
- * for complex meshes.
184
+ * Points camera to look at skinned mesh center of mass.
185
+ * Uses iterative clustering to find main vertex concentration.
223
186
  *
224
- * @param skinnedMesh - The skinned mesh (with active skeleton) whose center of mass should be the camera's target
187
+ * @param skinnedMesh - Skinned mesh with active skeleton
225
188
  */
226
189
  lookAtMeshCenterOfMass(skinnedMesh) {
227
190
  skinnedMesh.updateWorldMatrix(true, true);
@@ -236,11 +199,11 @@ class DualFovCamera extends PerspectiveCamera {
236
199
  points.push(target.clone());
237
200
  }
238
201
  /**
239
- * Finds the main cluster center of a set of 3D points using iterative refinement.
202
+ * Finds main cluster center using iterative refinement.
240
203
  *
241
204
  * @param points - Array of 3D points to cluster
242
- * @param iterations - Number of refinement iterations to perform
243
- * @returns The calculated center point of the main cluster
205
+ * @param iterations - Number of refinement iterations
206
+ * @returns Center point of main cluster
244
207
  */
245
208
  const findMainCluster = (points, iterations = 3) => {
246
209
  if (points.length === 0) {
@@ -267,12 +230,9 @@ class DualFovCamera extends PerspectiveCamera {
267
230
  this.lookAt(centerOfMass);
268
231
  }
269
232
  /**
270
- * Creates a deep copy of this DualFovCamera instance.
233
+ * Creates a copy of this camera with identical settings.
271
234
  *
272
- * The cloned camera will have identical FOV settings, position, rotation,
273
- * and all other camera properties.
274
- *
275
- * @returns A new DualFovCamera instance that is an exact copy of this one
235
+ * @returns New DualFovCamera instance
276
236
  * @override
277
237
  */
278
238
  clone() {
@@ -283,27 +243,17 @@ class DualFovCamera extends PerspectiveCamera {
283
243
  }
284
244
 
285
245
  /**
286
- * Utility class for finding and modifying objects in a Three.js scene graph.
287
- *
288
- * This class provides static methods for traversing Three.js scene hierarchies,
289
- * searching for specific objects or materials, and performing batch operations
290
- * on collections of scene objects.
246
+ * Static methods for traversing Three.js scene hierarchies.
291
247
  *
292
- * All methods perform depth-first traversal of the scene graph starting from
293
- * the provided root object and recursively processing all children.
248
+ * All methods use depth-first traversal.
294
249
  */
295
250
  class SceneTraversal {
296
251
  /**
297
- * Finds the first object in the scene hierarchy with an exact name match.
252
+ * Finds first object with exact name match.
298
253
  *
299
- * Performs a depth-first search through the scene graph starting from the provided
300
- * root object. Returns the first object encountered whose name property exactly
301
- * matches the search string.
302
- *
303
- * @param object - The root Object3D to start searching from
304
- * @param name - The exact name to search for (case-sensitive)
305
- * @returns The first matching Object3D, or null if no match is found
306
-
254
+ * @param object - Root object to start from
255
+ * @param name - Name to search for (case-sensitive)
256
+ * @returns First matching object or null
307
257
  */
308
258
  static getObjectByName(object, name) {
309
259
  if (object.name === name) {
@@ -318,17 +268,11 @@ class SceneTraversal {
318
268
  return null;
319
269
  }
320
270
  /**
321
- * Finds the first material in the scene hierarchy with an exact name match.
322
- *
323
- * Performs a depth-first search through the scene graph, examining materials
324
- * attached to Mesh objects. Handles both single materials and material arrays.
325
- * Returns the first material encountered whose name property exactly matches
326
- * the search string.
271
+ * Finds first material with exact name match from mesh objects.
327
272
  *
328
- * @param object - The root Object3D to start searching from
329
- * @param name - The exact material name to search for (case-sensitive)
330
- * @returns The first matching Material, or null if no match is found
331
-
273
+ * @param object - Root object to start from
274
+ * @param name - Material name to search for (case-sensitive)
275
+ * @returns First matching material or null
332
276
  */
333
277
  static getMaterialByName(object, name) {
334
278
  if (object instanceof Mesh) {
@@ -352,17 +296,12 @@ class SceneTraversal {
352
296
  return null;
353
297
  }
354
298
  /**
355
- * Processes all objects of a specific type in the scene hierarchy.
299
+ * Executes callback for all objects of specified type.
356
300
  *
357
- * Performs a depth-first traversal and executes the provided callback function
358
- * for every object that is an instance of the specified type. This is useful
359
- * for batch operations on specific object types (e.g., all lights, all meshes, etc.).
360
- *
361
- * @template T - The type of objects to process
362
- * @param object - The root Object3D to start searching from
363
- * @param type - The constructor/class to filter by (e.g., DirectionalLight, Mesh)
364
- * @param callback - Function to execute for each matching object instance
365
-
301
+ * @template T - Type of objects to process
302
+ * @param object - Root object to start from
303
+ * @param type - Constructor to filter by
304
+ * @param callback - Function to execute for each matching object
366
305
  */
367
306
  static enumerateObjectsByType(object, type, callback) {
368
307
  if (object instanceof type) {
@@ -373,15 +312,47 @@ class SceneTraversal {
373
312
  }
374
313
  }
375
314
  /**
376
- * Processes all materials found in mesh objects within the scene hierarchy.
315
+ * Executes callback for all materials of specified type from mesh objects.
377
316
  *
378
- * Performs a depth-first traversal, finding all Mesh objects and executing
379
- * the provided callback function for each material. Handles both single
380
- * materials and material arrays properly.
317
+ * @template T - Type of materials to process
318
+ * @param object - Root object to start from
319
+ * @param type - Constructor to filter by
320
+ * @param callback - Function to execute for each matching material
321
+ */
322
+ static enumerateMaterialsByType(object, type, callback) {
323
+ if (object instanceof Mesh) {
324
+ if (Array.isArray(object.material)) {
325
+ for (const material of object.material) {
326
+ if (material instanceof type) {
327
+ callback(material);
328
+ }
329
+ }
330
+ }
331
+ else if (object.material instanceof type) {
332
+ callback(object.material);
333
+ }
334
+ }
335
+ for (const child of object.children) {
336
+ SceneTraversal.enumerateMaterialsByType(child, type, callback);
337
+ }
338
+ }
339
+ /**
340
+ * Executes callback for all objects in hierarchy.
381
341
  *
382
- * @param object - The root Object3D to start searching from
383
- * @param callback - Function to execute for each material found
384
-
342
+ * @param object - Root object to start from
343
+ * @param callback - Function to execute for each object
344
+ */
345
+ static enumerateObjects(object, callback) {
346
+ callback(object);
347
+ for (const child of object.children) {
348
+ SceneTraversal.enumerateObjects(child, callback);
349
+ }
350
+ }
351
+ /**
352
+ * Executes callback for all materials from mesh objects.
353
+ *
354
+ * @param object - Root object to start from
355
+ * @param callback - Function to execute for each material
385
356
  */
386
357
  static enumerateMaterials(object, callback) {
387
358
  if (object instanceof Mesh) {
@@ -399,16 +370,11 @@ class SceneTraversal {
399
370
  }
400
371
  }
401
372
  /**
402
- * Finds all objects in the scene hierarchy that match the specified filter criteria.
403
- *
404
- * Performs a depth-first search and collects all objects that either match
405
- * a regular expression pattern (applied to the object's name) or satisfy
406
- * a custom predicate function.
373
+ * Returns all objects matching filter criteria.
407
374
  *
408
- * @param object - The root Object3D to start searching from
409
- * @param filter - Either a RegExp to test against object names, or a predicate function
410
- * @returns Array of all matching Object3D instances
411
-
375
+ * @param object - Root object to start from
376
+ * @param filter - RegExp for object names or predicate function
377
+ * @returns Array of matching objects
412
378
  */
413
379
  static filterObjects(object, filter) {
414
380
  let result = [];
@@ -428,63 +394,62 @@ class SceneTraversal {
428
394
  return result;
429
395
  }
430
396
  /**
431
- * Finds all materials in the scene hierarchy whose names match a regular expression pattern.
432
- *
433
- * Performs a depth-first search through all Mesh objects and collects materials
434
- * whose name property matches the provided regular expression. Handles both
435
- * single materials and material arrays properly.
397
+ * Returns all materials matching filter criteria from mesh objects.
436
398
  *
437
- * @param object - The root Object3D to start searching from
438
- * @param name - Regular expression pattern to test against material names
439
- * @returns Array of all matching Material instances
440
-
399
+ * @param object - Root object to start from
400
+ * @param filter - RegExp for material names or predicate function
401
+ * @returns Array of matching materials
441
402
  */
442
- static filterMaterials(object, name) {
403
+ static filterMaterials(object, filter) {
443
404
  let result = [];
444
405
  if (object instanceof Mesh) {
445
406
  if (Array.isArray(object.material)) {
446
407
  for (const material of object.material) {
447
- if (material.name && name.test(material.name)) {
408
+ if (typeof filter === "function") {
409
+ if (filter(material)) {
410
+ result.push(material);
411
+ }
412
+ }
413
+ else if (filter.test(material.name)) {
448
414
  result.push(material);
449
415
  }
450
416
  }
451
417
  }
452
- else {
453
- if (object.material.name && name.test(object.material.name)) {
418
+ else if (typeof filter === "function") {
419
+ if (filter(object.material)) {
454
420
  result.push(object.material);
455
421
  }
456
422
  }
423
+ else if (filter.test(object.material.name)) {
424
+ result.push(object.material);
425
+ }
457
426
  }
458
427
  for (const child of object.children) {
459
- result = result.concat(SceneTraversal.filterMaterials(child, name));
428
+ result = result.concat(SceneTraversal.filterMaterials(child, filter));
460
429
  }
461
430
  return result;
462
431
  }
463
432
  /**
464
- * Finds all objects (mesh users) that use materials with names matching a regular expression pattern.
465
- *
466
- * Performs a depth-first search through all Mesh objects and collects the mesh objects
467
- * whose materials have names that match the provided regular expression. This is useful
468
- * for finding all objects that use specific material types or naming patterns.
433
+ * Returns all mesh objects that use any of the specified materials.
469
434
  *
470
- * @param object - The root Object3D to start searching from
471
- * @param materialName - Regular expression pattern to test against material names
472
- * @returns Array of all Mesh objects that use materials with matching names
435
+ * @param object - Root object to start from
436
+ * @param materials - Array of materials to search for
437
+ * @returns Array of mesh objects using the materials
473
438
  */
474
- static findMaterialUsers(object, materialName) {
439
+ static findMaterialUsers(object, materials) {
475
440
  let result = [];
476
441
  if (object instanceof Mesh) {
477
442
  let hasMatchingMaterial = false;
478
443
  if (Array.isArray(object.material)) {
479
444
  for (const material of object.material) {
480
- if (material.name && materialName.test(material.name)) {
445
+ if (materials.includes(material)) {
481
446
  hasMatchingMaterial = true;
482
447
  break;
483
448
  }
484
449
  }
485
450
  }
486
451
  else {
487
- if (object.material.name && materialName.test(object.material.name)) {
452
+ if (materials.includes(object.material)) {
488
453
  hasMatchingMaterial = true;
489
454
  }
490
455
  }
@@ -493,7 +458,7 @@ class SceneTraversal {
493
458
  }
494
459
  }
495
460
  for (const child of object.children) {
496
- result = result.concat(SceneTraversal.findMaterialUsers(child, materialName));
461
+ result = result.concat(SceneTraversal.findMaterialUsers(child, materials));
497
462
  }
498
463
  return result;
499
464
  }
@@ -501,14 +466,13 @@ class SceneTraversal {
501
466
 
502
467
  /** Number of components per vertex */
503
468
  const COMPONENT_COUNT = 3;
504
- /** Convert skinned meshes to regular static meshes */
469
+ /** Converts skinned meshes to static meshes. */
505
470
  class SkinnedMeshBaker {
506
471
  /**
507
- * Convert a skinned mesh to a regular mesh in its current pose.
508
- * The resulting mesh will have no bones but look identical.
472
+ * Converts skinned mesh to static mesh in current pose.
509
473
  *
510
474
  * @param skinnedMesh - Mesh to convert
511
- * @returns Static mesh with baked vertex positions
475
+ * @returns Static mesh with baked positions
512
476
  */
513
477
  static bakePose(skinnedMesh) {
514
478
  const bakedGeometry = skinnedMesh.geometry.clone();
@@ -531,13 +495,13 @@ class SkinnedMeshBaker {
531
495
  return mesh;
532
496
  }
533
497
  /**
534
- * Bake a single frame from an animation into a static mesh.
498
+ * Bakes animation frame to static mesh.
535
499
  *
536
- * @param armature - Root object with bones (usually from GLTF)
500
+ * @param armature - Root object with bones
537
501
  * @param skinnedMesh - Mesh to convert
538
- * @param timeOffset - Time in seconds within the animation
539
- * @param clip - Animation to get the pose from
540
- * @returns Static mesh with baked vertex positions
502
+ * @param timeOffset - Time in seconds within animation
503
+ * @param clip - Animation clip for pose
504
+ * @returns Static mesh with baked positions
541
505
  */
542
506
  static bakeAnimationFrame(armature, skinnedMesh, timeOffset, clip) {
543
507
  const mixer = new AnimationMixer(armature);
@@ -550,42 +514,20 @@ class SkinnedMeshBaker {
550
514
  }
551
515
  }
552
516
 
517
+ /** Factor for metalness brightness adjustment */
518
+ const METALNESS_BRIGHTNESS_FACTOR = 0.3;
519
+ /** Factor for emissive color contribution when combining with base color */
520
+ const EMISSIVE_CONTRIBUTION_FACTOR = 0.5;
553
521
  /**
554
- * Converts Three.js MeshStandardMaterial to MeshBasicMaterial
555
- *
556
- * This converter handles the translation from PBR (Physically Based Rendering)
557
- * StandardMaterial to the unlit BasicMaterial. Since BasicMaterial doesn't respond
558
- * to lighting, this converter applies various compensation techniques to maintain
559
- * visual similarity, including brightness adjustments and emissive color combination.
522
+ * Converts MeshStandardMaterial to MeshBasicMaterial with brightness compensation.
560
523
  */
561
524
  class StandardToBasicConverter {
562
525
  /**
563
- * Converts a MeshStandardMaterial to MeshBasicMaterial
564
- *
565
- * This method performs a comprehensive conversion from PBR StandardMaterial to
566
- * unlit BasicMaterial while attempting to preserve visual similarity through
567
- * brightness compensation and intelligent property mapping.
526
+ * Converts MeshStandardMaterial to MeshBasicMaterial.
568
527
  *
569
- * @param standardMaterial - The source MeshStandardMaterial to convert
570
- * @param options - Configuration options for the conversion
571
- * @returns A new MeshBasicMaterial with properties mapped from the standard material
572
- *
573
- * @example
574
- * ```typescript
575
- * const standardMaterial = new MeshStandardMaterial({
576
- * color: 0x00ff00,
577
- * metalness: 0.5,
578
- * emissive: 0x111111,
579
- * emissiveIntensity: 0.2
580
- * });
581
- *
582
- * const basicMaterial = StandardToBasicConverter.convert(standardMaterial, {
583
- * brightnessFactor: 1.4,
584
- * combineEmissive: true
585
- * });
586
- * ```
587
- *
588
- * @see {@link StandardToBasicConverterOptions} for available configuration options
528
+ * @param standardMaterial - Source material to convert
529
+ * @param options - Conversion options
530
+ * @returns New MeshBasicMaterial with mapped properties
589
531
  */
590
532
  static convert(standardMaterial, options = {}) {
591
533
  const config = {
@@ -614,14 +556,11 @@ class StandardToBasicConverter {
614
556
  return basicMaterial;
615
557
  }
616
558
  /**
617
- * Copies basic material properties from source to target material
559
+ * Copies basic material properties.
618
560
  *
619
- * Transfers common material properties including rendering settings,
620
- * visibility, fog interaction, wireframe settings, and user data.
621
- *
622
- * @param source - The source MeshStandardMaterial
623
- * @param target - The target MeshBasicMaterial
624
- * @param config - The resolved configuration options
561
+ * @param source - Source material
562
+ * @param target - Target material
563
+ * @param config - Configuration options
625
564
  * @internal
626
565
  */
627
566
  static copyBasicProperties(source, target, config) {
@@ -639,15 +578,11 @@ class StandardToBasicConverter {
639
578
  }
640
579
  }
641
580
  /**
642
- * Converts color-related properties with lighting compensation
643
- *
644
- * Applies brightness compensation and optional emissive color combination
645
- * to account for BasicMaterial's lack of lighting response. Metallic materials
646
- * receive additional brightness adjustment, and colors are clamped to valid ranges.
581
+ * Converts color properties with lighting compensation.
647
582
  *
648
- * @param source - The source MeshStandardMaterial
649
- * @param target - The target MeshBasicMaterial
650
- * @param config - The resolved configuration options
583
+ * @param source - Source material
584
+ * @param target - Target material
585
+ * @param config - Configuration options
651
586
  * @internal
652
587
  */
653
588
  static convertColorProperties(source, target, config) {
@@ -657,14 +592,14 @@ class StandardToBasicConverter {
657
592
  target.color.multiplyScalar(config.brightnessFactor);
658
593
  // Adjust for metalness - metallic materials tend to be darker without lighting
659
594
  if (source.metalness > 0) {
660
- const metalnessBrightness = 1 + source.metalness * 0.3;
595
+ const metalnessBrightness = 1 + source.metalness * METALNESS_BRIGHTNESS_FACTOR;
661
596
  target.color.multiplyScalar(metalnessBrightness);
662
597
  }
663
598
  // Combine emissive color if requested
664
599
  if (config.combineEmissive) {
665
600
  const emissiveContribution = source.emissive
666
601
  .clone()
667
- .multiplyScalar(source.emissiveIntensity * 0.5);
602
+ .multiplyScalar(source.emissiveIntensity * EMISSIVE_CONTRIBUTION_FACTOR);
668
603
  target.color.add(emissiveContribution);
669
604
  }
670
605
  // Ensure color doesn't exceed valid range
@@ -673,15 +608,10 @@ class StandardToBasicConverter {
673
608
  target.color.b = Math.min(target.color.b, 1.0);
674
609
  }
675
610
  /**
676
- * Converts and maps texture properties from Standard to Basic material
611
+ * Converts texture properties from Standard to Basic material.
677
612
  *
678
- * Handles the transfer of compatible texture maps including diffuse, alpha,
679
- * environment, light, and AO maps. The metalness map is repurposed as a
680
- * specular map for some reflective effect, and environment map reflectivity
681
- * is set based on the original material's metalness value.
682
- *
683
- * @param source - The source MeshStandardMaterial
684
- * @param target - The target MeshBasicMaterial
613
+ * @param source - Source material
614
+ * @param target - Target material
685
615
  * @internal
686
616
  */
687
617
  static convertTextureMaps(source, target) {
@@ -718,13 +648,10 @@ class StandardToBasicConverter {
718
648
  this.copyUVTransforms(source, target);
719
649
  }
720
650
  /**
721
- * Copies UV transformation properties for texture maps
722
- *
723
- * Transfers UV offset, repeat, rotation, and center properties from the
724
- * source material's main texture map to the target material's map.
651
+ * Copies UV transformation properties.
725
652
  *
726
- * @param source - The source MeshStandardMaterial
727
- * @param target - The target MeshBasicMaterial
653
+ * @param source - Source material
654
+ * @param target - Target material
728
655
  * @internal
729
656
  */
730
657
  static copyUVTransforms(source, target) {
@@ -737,13 +664,10 @@ class StandardToBasicConverter {
737
664
  }
738
665
  }
739
666
  /**
740
- * Converts transparency and rendering properties
667
+ * Converts transparency and rendering properties.
741
668
  *
742
- * Transfers transparency, opacity, alpha testing, depth testing,
743
- * depth writing, and blending mode settings from source to target.
744
- *
745
- * @param source - The source MeshStandardMaterial
746
- * @param target - The target MeshBasicMaterial
669
+ * @param source - Source material
670
+ * @param target - Target material
747
671
  * @internal
748
672
  */
749
673
  static convertTransparencyProperties(source, target) {
@@ -756,38 +680,24 @@ class StandardToBasicConverter {
756
680
  }
757
681
  }
758
682
 
683
+ /** Factor for metalness darkness adjustment */
684
+ const METALNESS_DARKNESS_FACTOR = 0.3;
685
+ /** Roughness threshold for additional darkening */
686
+ const ROUGHNESS_THRESHOLD = 0.5;
687
+ /** Factor for roughness color adjustment */
688
+ const ROUGHNESS_COLOR_ADJUSTMENT = 0.2;
689
+ /** Minimum reflectivity boost for environment maps */
690
+ const REFLECTIVITY_BOOST = 0.1;
759
691
  /**
760
- * Converts Three.js MeshStandardMaterial to MeshLambertMaterial
761
- *
762
- * This converter handles the translation between PBR (Physically Based Rendering)
763
- * properties of StandardMaterial and the simpler Lambertian reflectance model
764
- * used by LambertMaterial. The conversion preserves visual similarity by applying
765
- * color compensation based on metalness and roughness values.
692
+ * Converts MeshStandardMaterial to MeshLambertMaterial with PBR compensation.
766
693
  */
767
694
  class StandardToLambertConverter {
768
695
  /**
769
- * Converts a MeshStandardMaterial to MeshLambertMaterial
696
+ * Converts MeshStandardMaterial to MeshLambertMaterial.
770
697
  *
771
- * This method performs a comprehensive conversion from PBR StandardMaterial to
772
- * the simpler Lambert lighting model while attempting to preserve visual similarity
773
- * through intelligent color compensation.
774
- *
775
- * @param material - The source MeshStandardMaterial to convert
776
- * @param options - Configuration options for the conversion
777
- * @returns A new MeshLambertMaterial with properties mapped from the standard material
778
- *
779
- * @example
780
- * ```typescript
781
- * const standardMaterial = new MeshStandardMaterial({
782
- * color: 0xff0000,
783
- * metalness: 0.8,
784
- * roughness: 0.2
785
- * });
786
- *
787
- * const lambertMaterial = StandardToLambertConverter.convert(standardMaterial);
788
- * ```
789
- *
790
- * @see {@link StandardToLambertConverterOptions} for available configuration options
698
+ * @param material - Source material to convert
699
+ * @param options - Conversion options
700
+ * @returns New MeshLambertMaterial with mapped properties
791
701
  */
792
702
  static convert(material, options = {}) {
793
703
  const config = {
@@ -815,14 +725,11 @@ class StandardToLambertConverter {
815
725
  return lambertMaterial;
816
726
  }
817
727
  /**
818
- * Copies basic material properties from source to target material
819
- *
820
- * Transfers common material properties including rendering settings,
821
- * visibility, fog interaction, wireframe settings, and user data.
728
+ * Copies basic material properties.
822
729
  *
823
- * @param source - The source MeshStandardMaterial
824
- * @param target - The target MeshLambertMaterial
825
- * @param config - The resolved configuration options
730
+ * @param source - Source material
731
+ * @param target - Target material
732
+ * @param config - Configuration options
826
733
  * @internal
827
734
  */
828
735
  static copyBasicProperties(source, target, config) {
@@ -841,16 +748,11 @@ class StandardToLambertConverter {
841
748
  }
842
749
  }
843
750
  /**
844
- * Converts color-related properties with PBR compensation
751
+ * Converts color properties with PBR compensation.
845
752
  *
846
- * Applies intelligent color adjustments to compensate for the loss of
847
- * metalness and roughness information when converting to Lambert material.
848
- * Metallic materials are darkened and rough materials receive additional
849
- * darkening based on the roughnessColorFactor.
850
- *
851
- * @param source - The source MeshStandardMaterial
852
- * @param target - The target MeshLambertMaterial
853
- * @param config - The resolved configuration options
753
+ * @param source - Source material
754
+ * @param target - Target material
755
+ * @param config - Configuration options
854
756
  * @internal
855
757
  */
856
758
  static convertColorProperties(source, target, config) {
@@ -858,26 +760,23 @@ class StandardToLambertConverter {
858
760
  // Adjust color based on metalness and roughness for better visual match
859
761
  if (source.metalness > 0) {
860
762
  // Metallic materials tend to be darker in Lambert shading
861
- const metalnessFactor = 1 - source.metalness * 0.3;
763
+ const metalnessFactor = 1 - source.metalness * METALNESS_DARKNESS_FACTOR;
862
764
  target.color.multiplyScalar(metalnessFactor);
863
765
  }
864
- if (source.roughness > 0.5) {
766
+ if (source.roughness > ROUGHNESS_THRESHOLD) {
865
767
  // Rough materials appear slightly darker
866
- const roughnessFactor = config.roughnessColorFactor + source.roughness * 0.2;
768
+ const roughnessFactor = config.roughnessColorFactor +
769
+ source.roughness * ROUGHNESS_COLOR_ADJUSTMENT;
867
770
  target.color.multiplyScalar(roughnessFactor);
868
771
  }
869
772
  target.emissive = source.emissive.clone();
870
773
  target.emissiveIntensity = source.emissiveIntensity;
871
774
  }
872
775
  /**
873
- * Converts and maps texture properties from Standard to Lambert material
874
- *
875
- * Handles the transfer of compatible texture maps including diffuse, normal,
876
- * emissive, AO, light maps, and environment maps. The environment map
877
- * reflectivity is set based on the original material's metalness value.
776
+ * Converts texture properties from Standard to Lambert material.
878
777
  *
879
- * @param source - The source MeshStandardMaterial
880
- * @param target - The target MeshLambertMaterial
778
+ * @param source - Source material
779
+ * @param target - Target material
881
780
  * @internal
882
781
  */
883
782
  static convertTextureMaps(source, target) {
@@ -907,7 +806,7 @@ class StandardToLambertConverter {
907
806
  // Environment map (for reflections)
908
807
  if (source.envMap) {
909
808
  target.envMap = source.envMap;
910
- target.reflectivity = Math.min(source.metalness + 0.1, 1.0);
809
+ target.reflectivity = Math.min(source.metalness + REFLECTIVITY_BOOST, 1.0);
911
810
  }
912
811
  // Alpha map
913
812
  if (source.alphaMap) {
@@ -917,13 +816,10 @@ class StandardToLambertConverter {
917
816
  this.copyUVTransforms(source, target);
918
817
  }
919
818
  /**
920
- * Copies UV transformation properties for texture maps
819
+ * Copies UV transformation properties.
921
820
  *
922
- * Transfers UV offset, repeat, rotation, and center properties from the
923
- * source material's main texture map to the target material's map.
924
- *
925
- * @param source - The source MeshStandardMaterial
926
- * @param target - The target MeshLambertMaterial
821
+ * @param source - Source material
822
+ * @param target - Target material
927
823
  * @internal
928
824
  */
929
825
  static copyUVTransforms(source, target) {
@@ -936,13 +832,10 @@ class StandardToLambertConverter {
936
832
  }
937
833
  }
938
834
  /**
939
- * Converts transparency and rendering properties
940
- *
941
- * Transfers transparency, opacity, alpha testing, depth testing,
942
- * depth writing, and blending mode settings from source to target.
835
+ * Converts transparency and rendering properties.
943
836
  *
944
- * @param source - The source MeshStandardMaterial
945
- * @param target - The target MeshLambertMaterial
837
+ * @param source - Source material
838
+ * @param target - Target material
946
839
  * @internal
947
840
  */
948
841
  static convertTransparencyProperties(source, target) {
@@ -966,11 +859,7 @@ const LUMINANCE_G = 0.7152;
966
859
  /** Blue channel weight for luminance calculation (ITU-R BT.709) */
967
860
  const LUMINANCE_B = 0.0722;
968
861
  /**
969
- * A directional light with spherical positioning controls and advanced shadow mapping.
970
- *
971
- * Extends Three.js DirectionalLight to provide intuitive spherical coordinate control
972
- * (distance, elevation, azimuth) and automatic shadow map configuration for bounding boxes.
973
- * Also supports automatic sun direction calculation from HDR environment maps.
862
+ * Directional light with spherical positioning and HDR environment support.
974
863
  */
975
864
  class Sun extends DirectionalLight {
976
865
  constructor() {
@@ -988,64 +877,48 @@ class Sun extends DirectionalLight {
988
877
  this._private_tempSpherical = new Spherical();
989
878
  }
990
879
  /**
991
- * Gets the distance from the light to its target (origin).
992
- *
993
- * @returns The distance in world units
880
+ * @returns Distance from light position to origin
994
881
  */
995
882
  get distance() {
996
883
  return this.position.length();
997
884
  }
998
885
  /**
999
- * Gets the elevation angle (vertical angle from the horizontal plane).
1000
- *
1001
- * @returns The elevation angle in radians (0 = horizontal, π/2 = directly above)
886
+ * @returns Elevation angle in radians (phi angle)
1002
887
  */
1003
888
  get elevation() {
1004
889
  return this._private_tempSpherical.setFromVector3(this.position).phi;
1005
890
  }
1006
891
  /**
1007
- * Gets the azimuth angle (horizontal rotation around the target).
1008
- *
1009
- * @returns The azimuth angle in radians (0 = positive X axis, π/2 = positive Z axis)
892
+ * @returns Azimuth angle in radians (theta angle)
1010
893
  */
1011
894
  get azimuth() {
1012
895
  return this._private_tempSpherical.setFromVector3(this.position).theta;
1013
896
  }
1014
897
  /**
1015
- * Sets the distance while preserving current elevation and azimuth angles.
1016
- *
1017
- * @param value - The new distance in world units
898
+ * @param value - New distance in world units
1018
899
  */
1019
900
  set distance(value) {
1020
901
  this._private_tempSpherical.setFromVector3(this.position);
1021
902
  this.position.setFromSphericalCoords(value, this._private_tempSpherical.phi, this._private_tempSpherical.theta);
1022
903
  }
1023
904
  /**
1024
- * Sets the elevation angle while preserving current distance and azimuth.
1025
- *
1026
- * @param value - The new elevation angle in radians (0 = horizontal, π/2 = directly above)
905
+ * @param value - New elevation angle in radians (phi angle)
1027
906
  */
1028
907
  set elevation(value) {
1029
908
  this._private_tempSpherical.setFromVector3(this.position);
1030
909
  this.position.setFromSphericalCoords(this._private_tempSpherical.radius, value, this._private_tempSpherical.theta);
1031
910
  }
1032
911
  /**
1033
- * Sets the azimuth angle while preserving current distance and elevation.
1034
- *
1035
- * @param value - The new azimuth angle in radians (0 = positive X axis, π/2 = positive Z axis)
912
+ * @param value - New azimuth angle in radians (theta angle)
1036
913
  */
1037
914
  set azimuth(value) {
1038
915
  this._private_tempSpherical.setFromVector3(this.position);
1039
916
  this.position.setFromSphericalCoords(this._private_tempSpherical.radius, this._private_tempSpherical.phi, value);
1040
917
  }
1041
918
  /**
1042
- * Configures the shadow camera to optimally cover a bounding box.
919
+ * Configures shadow camera frustum to cover bounding box.
1043
920
  *
1044
- * This method automatically adjusts the directional light's shadow camera frustum
1045
- * to perfectly encompass the provided bounding box, ensuring efficient shadow map
1046
- * usage and eliminating shadow clipping issues.
1047
- *
1048
- * @param box3 - The 3D bounding box to cover with shadows
921
+ * @param box3 - 3D bounding box to cover with shadows
1049
922
  */
1050
923
  configureShadowsForBoundingBox(box3) {
1051
924
  const camera = this.shadow.camera;
@@ -1077,14 +950,10 @@ class Sun extends DirectionalLight {
1077
950
  camera.updateProjectionMatrix();
1078
951
  }
1079
952
  /**
1080
- * Sets the sun's direction based on the brightest point in an HDR environment map.
1081
- *
1082
- * This method analyzes an HDR texture to find the pixel with the highest luminance
1083
- * value and positions the sun to shine from that direction. This is useful for
1084
- * creating realistic lighting that matches HDR environment maps.
953
+ * Sets sun direction based on brightest point in HDR environment map.
1085
954
  *
1086
- * @param texture - The HDR texture to analyze (must have image data available)
1087
- * @param distance - The distance to place the sun from the origin (defaults to 1)
955
+ * @param texture - HDR texture to analyze (must have image data)
956
+ * @param distance - Distance to place sun from origin
1088
957
  */
1089
958
  setDirectionFromHDRTexture(texture, distance = 1) {
1090
959
  const data = texture.image.data;