three-zoo 0.5.5 → 0.6.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/dist/DualFovCamera.d.ts +33 -72
- package/dist/SceneTraversal.d.ts +64 -65
- package/dist/SkinnedMeshBaker.d.ts +7 -8
- package/dist/StandardToBasicConverter.d.ts +11 -33
- package/dist/StandardToLambertConverter.d.ts +10 -28
- package/dist/Sun.d.ts +12 -35
- package/dist/index.js +217 -283
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/package.json +1 -1
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
|
-
*
|
|
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
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* @param
|
|
27
|
-
* @param
|
|
28
|
-
* @param
|
|
29
|
-
* @param near - Near clipping plane distance.
|
|
30
|
-
* @param far - Far clipping plane distance.
|
|
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
|
-
*
|
|
40
|
-
*
|
|
41
|
-
* @returns The horizontal FOV value
|
|
35
|
+
* @returns Horizontal FOV in degrees
|
|
42
36
|
*/
|
|
43
37
|
get horizontalFov() {
|
|
44
38
|
return this._private_horizontalFovInternal;
|
|
45
39
|
}
|
|
46
40
|
/**
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
* @returns The vertical FOV value
|
|
41
|
+
* @returns Vertical FOV in degrees
|
|
50
42
|
*/
|
|
51
43
|
get verticalFov() {
|
|
52
44
|
return this._private_verticalFovInternal;
|
|
53
45
|
}
|
|
54
46
|
/**
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
* @param value - The horizontal FOV value in degrees. 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
|
-
*
|
|
65
|
-
*
|
|
66
|
-
* @param value - The vertical FOV value in degrees. 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
|
-
* Sets both
|
|
61
|
+
* Sets both FOV values.
|
|
74
62
|
*
|
|
75
|
-
* @param horizontal - Horizontal FOV in degrees
|
|
76
|
-
* @param vertical - Vertical FOV in degrees
|
|
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
|
|
72
|
+
* Copies FOV settings from another DualFovCamera.
|
|
85
73
|
*
|
|
86
|
-
* @param source -
|
|
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
|
|
95
|
-
*
|
|
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
|
|
82
|
+
* Updates projection matrix based on FOV and aspect ratio.
|
|
99
83
|
*
|
|
100
|
-
*
|
|
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
|
|
102
|
+
* Gets actual horizontal FOV after aspect ratio adjustments.
|
|
118
103
|
*
|
|
119
|
-
*
|
|
120
|
-
* In portrait mode, calculates the horizontal FOV from vertical FOV and aspect ratio.
|
|
121
|
-
*
|
|
122
|
-
* @returns The 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
|
|
133
|
-
*
|
|
134
|
-
* In portrait mode, returns the set vertical FOV.
|
|
135
|
-
* In landscape mode, calculates the vertical FOV from horizontal FOV and aspect ratio.
|
|
114
|
+
* Gets actual vertical FOV after aspect ratio adjustments.
|
|
136
115
|
*
|
|
137
|
-
* @returns
|
|
116
|
+
* @returns Vertical FOV in degrees
|
|
138
117
|
*/
|
|
139
118
|
getActualVerticalFov() {
|
|
140
119
|
if (this.aspect < 1) {
|
|
@@ -144,10 +123,7 @@ class DualFovCamera extends PerspectiveCamera {
|
|
|
144
123
|
return MathUtils.radToDeg(Math.atan(Math.tan(horizontalRadians / 2) / this.aspect) * 2);
|
|
145
124
|
}
|
|
146
125
|
/**
|
|
147
|
-
* Adjusts
|
|
148
|
-
*
|
|
149
|
-
* Calculates the required vertical FOV to ensure all provided vertices
|
|
150
|
-
* are visible within the vertical bounds of the camera's frustum.
|
|
126
|
+
* Adjusts vertical FOV to fit points within camera view.
|
|
151
127
|
*
|
|
152
128
|
* @param vertices - Array of 3D points in world coordinates
|
|
153
129
|
*/
|
|
@@ -168,12 +144,9 @@ class DualFovCamera extends PerspectiveCamera {
|
|
|
168
144
|
this.updateProjectionMatrix();
|
|
169
145
|
}
|
|
170
146
|
/**
|
|
171
|
-
* Adjusts
|
|
147
|
+
* Adjusts vertical FOV to fit bounding box within camera view.
|
|
172
148
|
*
|
|
173
|
-
*
|
|
174
|
-
* is visible within the vertical bounds of the camera's frustum.
|
|
175
|
-
*
|
|
176
|
-
* @param box - The 3D bounding box in world coordinates
|
|
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
|
|
192
|
-
*
|
|
193
|
-
* Updates the mesh's skeleton, applies bone transformations to vertices,
|
|
194
|
-
* and calculates the required vertical FOV to fit the deformed mesh
|
|
195
|
-
* within the vertical bounds of the camera's frustum.
|
|
164
|
+
* Adjusts vertical FOV to fit skinned mesh within camera view.
|
|
165
|
+
* Updates skeleton and applies bone transformations.
|
|
196
166
|
*
|
|
197
|
-
* @param skinnedMesh -
|
|
167
|
+
* @param skinnedMesh - Skinned mesh with active skeleton
|
|
198
168
|
*/
|
|
199
169
|
fitVerticalFovToMesh(skinnedMesh) {
|
|
200
170
|
skinnedMesh.updateWorldMatrix(true, true);
|
|
@@ -211,16 +181,10 @@ class DualFovCamera extends PerspectiveCamera {
|
|
|
211
181
|
this.fitVerticalFovToPoints(points);
|
|
212
182
|
}
|
|
213
183
|
/**
|
|
214
|
-
* Points
|
|
184
|
+
* Points camera to look at skinned mesh center of mass.
|
|
185
|
+
* Uses iterative clustering to find main vertex concentration.
|
|
215
186
|
*
|
|
216
|
-
*
|
|
217
|
-
* calculates the center of mass using a clustering algorithm, and orients the camera
|
|
218
|
-
* to look at that point.
|
|
219
|
-
*
|
|
220
|
-
* The center of mass calculation uses iterative clustering to find the
|
|
221
|
-
* main concentration of vertices.
|
|
222
|
-
*
|
|
223
|
-
* @param skinnedMesh - The skinned mesh with active skeleton
|
|
187
|
+
* @param skinnedMesh - Skinned mesh with active skeleton
|
|
224
188
|
*/
|
|
225
189
|
lookAtMeshCenterOfMass(skinnedMesh) {
|
|
226
190
|
skinnedMesh.updateWorldMatrix(true, true);
|
|
@@ -235,11 +199,11 @@ class DualFovCamera extends PerspectiveCamera {
|
|
|
235
199
|
points.push(target.clone());
|
|
236
200
|
}
|
|
237
201
|
/**
|
|
238
|
-
* Finds
|
|
202
|
+
* Finds main cluster center using iterative refinement.
|
|
239
203
|
*
|
|
240
204
|
* @param points - Array of 3D points to cluster
|
|
241
205
|
* @param iterations - Number of refinement iterations
|
|
242
|
-
* @returns
|
|
206
|
+
* @returns Center point of main cluster
|
|
243
207
|
*/
|
|
244
208
|
const findMainCluster = (points, iterations = 3) => {
|
|
245
209
|
if (points.length === 0) {
|
|
@@ -266,12 +230,9 @@ class DualFovCamera extends PerspectiveCamera {
|
|
|
266
230
|
this.lookAt(centerOfMass);
|
|
267
231
|
}
|
|
268
232
|
/**
|
|
269
|
-
* Creates a copy of this
|
|
270
|
-
*
|
|
271
|
-
* The cloned camera has identical FOV settings, position, rotation,
|
|
272
|
-
* and all other camera properties.
|
|
233
|
+
* Creates a copy of this camera with identical settings.
|
|
273
234
|
*
|
|
274
|
-
* @returns
|
|
235
|
+
* @returns New DualFovCamera instance
|
|
275
236
|
* @override
|
|
276
237
|
*/
|
|
277
238
|
clone() {
|
|
@@ -282,25 +243,17 @@ class DualFovCamera extends PerspectiveCamera {
|
|
|
282
243
|
}
|
|
283
244
|
|
|
284
245
|
/**
|
|
285
|
-
*
|
|
246
|
+
* Static methods for traversing Three.js scene hierarchies.
|
|
286
247
|
*
|
|
287
|
-
*
|
|
288
|
-
* searching for objects or materials, and performing batch operations.
|
|
289
|
-
*
|
|
290
|
-
* All methods perform depth-first traversal starting from the provided
|
|
291
|
-
* root object and recursively processing all children.
|
|
248
|
+
* All methods use depth-first traversal.
|
|
292
249
|
*/
|
|
293
250
|
class SceneTraversal {
|
|
294
251
|
/**
|
|
295
|
-
* Finds
|
|
296
|
-
*
|
|
297
|
-
* Performs depth-first search through the scene graph starting from the
|
|
298
|
-
* root object. Returns the first object whose name property matches
|
|
299
|
-
* the search string.
|
|
252
|
+
* Finds first object with exact name match.
|
|
300
253
|
*
|
|
301
|
-
* @param object -
|
|
302
|
-
* @param name -
|
|
303
|
-
* @returns
|
|
254
|
+
* @param object - Root object to start from
|
|
255
|
+
* @param name - Name to search for (case-sensitive)
|
|
256
|
+
* @returns First matching object or undefined
|
|
304
257
|
*/
|
|
305
258
|
static getObjectByName(object, name) {
|
|
306
259
|
if (object.name === name) {
|
|
@@ -312,18 +265,14 @@ class SceneTraversal {
|
|
|
312
265
|
return result;
|
|
313
266
|
}
|
|
314
267
|
}
|
|
315
|
-
return
|
|
268
|
+
return undefined;
|
|
316
269
|
}
|
|
317
270
|
/**
|
|
318
|
-
* Finds
|
|
271
|
+
* Finds first material with exact name match from mesh objects.
|
|
319
272
|
*
|
|
320
|
-
*
|
|
321
|
-
*
|
|
322
|
-
*
|
|
323
|
-
*
|
|
324
|
-
* @param object - The root Object3D to start searching from
|
|
325
|
-
* @param name - The exact material name to search for (case-sensitive)
|
|
326
|
-
* @returns The first matching Material, or null if no match is found
|
|
273
|
+
* @param object - Root object to start from
|
|
274
|
+
* @param name - Material name to search for (case-sensitive)
|
|
275
|
+
* @returns First matching material or undefined
|
|
327
276
|
*/
|
|
328
277
|
static getMaterialByName(object, name) {
|
|
329
278
|
if (object instanceof Mesh) {
|
|
@@ -344,18 +293,15 @@ class SceneTraversal {
|
|
|
344
293
|
return material;
|
|
345
294
|
}
|
|
346
295
|
}
|
|
347
|
-
return
|
|
296
|
+
return undefined;
|
|
348
297
|
}
|
|
349
298
|
/**
|
|
350
|
-
*
|
|
351
|
-
*
|
|
352
|
-
* Performs depth-first traversal and executes the callback function
|
|
353
|
-
* for every object that is an instance of the specified type.
|
|
299
|
+
* Executes callback for all objects of specified type.
|
|
354
300
|
*
|
|
355
|
-
* @template T -
|
|
356
|
-
* @param object -
|
|
357
|
-
* @param type -
|
|
358
|
-
* @param callback - Function to execute for each matching object
|
|
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
|
|
359
305
|
*/
|
|
360
306
|
static enumerateObjectsByType(object, type, callback) {
|
|
361
307
|
if (object instanceof type) {
|
|
@@ -366,14 +312,47 @@ class SceneTraversal {
|
|
|
366
312
|
}
|
|
367
313
|
}
|
|
368
314
|
/**
|
|
369
|
-
*
|
|
315
|
+
* Executes callback for all materials of specified type from mesh objects.
|
|
370
316
|
*
|
|
371
|
-
*
|
|
372
|
-
*
|
|
373
|
-
*
|
|
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.
|
|
341
|
+
*
|
|
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.
|
|
374
353
|
*
|
|
375
|
-
* @param object -
|
|
376
|
-
* @param callback - Function to execute for each material
|
|
354
|
+
* @param object - Root object to start from
|
|
355
|
+
* @param callback - Function to execute for each material
|
|
377
356
|
*/
|
|
378
357
|
static enumerateMaterials(object, callback) {
|
|
379
358
|
if (object instanceof Mesh) {
|
|
@@ -391,15 +370,11 @@ class SceneTraversal {
|
|
|
391
370
|
}
|
|
392
371
|
}
|
|
393
372
|
/**
|
|
394
|
-
*
|
|
395
|
-
*
|
|
396
|
-
* Performs depth-first search and collects all objects that either match
|
|
397
|
-
* a regular expression pattern (applied to object names) or satisfy
|
|
398
|
-
* a predicate function.
|
|
373
|
+
* Returns all objects matching filter criteria.
|
|
399
374
|
*
|
|
400
|
-
* @param object -
|
|
401
|
-
* @param filter -
|
|
402
|
-
* @returns Array of
|
|
375
|
+
* @param object - Root object to start from
|
|
376
|
+
* @param filter - RegExp for object names or predicate function
|
|
377
|
+
* @returns Array of matching objects
|
|
403
378
|
*/
|
|
404
379
|
static filterObjects(object, filter) {
|
|
405
380
|
let result = [];
|
|
@@ -419,63 +394,62 @@ class SceneTraversal {
|
|
|
419
394
|
return result;
|
|
420
395
|
}
|
|
421
396
|
/**
|
|
422
|
-
*
|
|
397
|
+
* Returns all materials matching filter criteria from mesh objects.
|
|
423
398
|
*
|
|
424
|
-
*
|
|
425
|
-
*
|
|
426
|
-
*
|
|
427
|
-
*
|
|
428
|
-
* @param object - The root Object3D to start searching from
|
|
429
|
-
* @param name - Regular expression pattern to test against material names
|
|
430
|
-
* @returns Array of all matching Material instances
|
|
399
|
+
* @param object - Root object to start from
|
|
400
|
+
* @param filter - RegExp for material names or predicate function
|
|
401
|
+
* @returns Array of matching materials
|
|
431
402
|
*/
|
|
432
|
-
static filterMaterials(object,
|
|
403
|
+
static filterMaterials(object, filter) {
|
|
433
404
|
let result = [];
|
|
434
405
|
if (object instanceof Mesh) {
|
|
435
406
|
if (Array.isArray(object.material)) {
|
|
436
407
|
for (const material of object.material) {
|
|
437
|
-
if (
|
|
408
|
+
if (typeof filter === "function") {
|
|
409
|
+
if (filter(material)) {
|
|
410
|
+
result.push(material);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
else if (filter.test(material.name)) {
|
|
438
414
|
result.push(material);
|
|
439
415
|
}
|
|
440
416
|
}
|
|
441
417
|
}
|
|
442
|
-
else {
|
|
443
|
-
if (object.material
|
|
444
|
-
name.test(object.material.name)) {
|
|
418
|
+
else if (typeof filter === "function") {
|
|
419
|
+
if (filter(object.material)) {
|
|
445
420
|
result.push(object.material);
|
|
446
421
|
}
|
|
447
422
|
}
|
|
423
|
+
else if (filter.test(object.material.name)) {
|
|
424
|
+
result.push(object.material);
|
|
425
|
+
}
|
|
448
426
|
}
|
|
449
427
|
for (const child of object.children) {
|
|
450
|
-
result = result.concat(SceneTraversal.filterMaterials(child,
|
|
428
|
+
result = result.concat(SceneTraversal.filterMaterials(child, filter));
|
|
451
429
|
}
|
|
452
430
|
return result;
|
|
453
431
|
}
|
|
454
432
|
/**
|
|
455
|
-
*
|
|
456
|
-
*
|
|
457
|
-
* Performs depth-first search through all Mesh objects and collects mesh objects
|
|
458
|
-
* whose materials have names that match the regular expression.
|
|
433
|
+
* Returns all mesh objects that use any of the specified materials.
|
|
459
434
|
*
|
|
460
|
-
* @param object -
|
|
461
|
-
* @param
|
|
462
|
-
* @returns Array of
|
|
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
|
|
463
438
|
*/
|
|
464
|
-
static findMaterialUsers(object,
|
|
439
|
+
static findMaterialUsers(object, materials) {
|
|
465
440
|
let result = [];
|
|
466
441
|
if (object instanceof Mesh) {
|
|
467
442
|
let hasMatchingMaterial = false;
|
|
468
443
|
if (Array.isArray(object.material)) {
|
|
469
444
|
for (const material of object.material) {
|
|
470
|
-
if (
|
|
445
|
+
if (materials.includes(material)) {
|
|
471
446
|
hasMatchingMaterial = true;
|
|
472
447
|
break;
|
|
473
448
|
}
|
|
474
449
|
}
|
|
475
450
|
}
|
|
476
451
|
else {
|
|
477
|
-
if (object.material
|
|
478
|
-
materialName.test(object.material.name)) {
|
|
452
|
+
if (materials.includes(object.material)) {
|
|
479
453
|
hasMatchingMaterial = true;
|
|
480
454
|
}
|
|
481
455
|
}
|
|
@@ -484,22 +458,57 @@ class SceneTraversal {
|
|
|
484
458
|
}
|
|
485
459
|
}
|
|
486
460
|
for (const child of object.children) {
|
|
487
|
-
result = result.concat(SceneTraversal.findMaterialUsers(child,
|
|
461
|
+
result = result.concat(SceneTraversal.findMaterialUsers(child, materials));
|
|
488
462
|
}
|
|
489
463
|
return result;
|
|
490
464
|
}
|
|
465
|
+
/**
|
|
466
|
+
* Clones material by name and replaces all instances with the clone.
|
|
467
|
+
*
|
|
468
|
+
* @param object - Root object to start from
|
|
469
|
+
* @param name - Material name to search for (case-sensitive)
|
|
470
|
+
* @returns Cloned material or undefined if not found
|
|
471
|
+
*/
|
|
472
|
+
static cloneMaterialByName(object, name) {
|
|
473
|
+
const originalMaterial = SceneTraversal.getMaterialByName(object, name);
|
|
474
|
+
if (!originalMaterial) {
|
|
475
|
+
return undefined;
|
|
476
|
+
}
|
|
477
|
+
const clonedMaterial = originalMaterial.clone();
|
|
478
|
+
SceneTraversal.replaceMaterial(object, originalMaterial, clonedMaterial);
|
|
479
|
+
return clonedMaterial;
|
|
480
|
+
}
|
|
481
|
+
/**
|
|
482
|
+
* Replaces all instances of a material with another material.
|
|
483
|
+
*
|
|
484
|
+
* @param object - Root object to start from
|
|
485
|
+
* @param oldMaterial - Material to replace
|
|
486
|
+
* @param newMaterial - Material to use as replacement
|
|
487
|
+
*/
|
|
488
|
+
static replaceMaterial(object, oldMaterial, newMaterial) {
|
|
489
|
+
if (object instanceof Mesh) {
|
|
490
|
+
if (Array.isArray(object.material)) {
|
|
491
|
+
object.material = object.material.map((material) => material === oldMaterial ? newMaterial : material);
|
|
492
|
+
}
|
|
493
|
+
else if (object.material === oldMaterial) {
|
|
494
|
+
object.material = newMaterial;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
for (const child of object.children) {
|
|
498
|
+
SceneTraversal.replaceMaterial(child, oldMaterial, newMaterial);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
491
501
|
}
|
|
492
502
|
|
|
493
503
|
/** Number of components per vertex */
|
|
494
504
|
const COMPONENT_COUNT = 3;
|
|
495
|
-
/** Converts skinned meshes to static meshes */
|
|
505
|
+
/** Converts skinned meshes to static meshes. */
|
|
496
506
|
class SkinnedMeshBaker {
|
|
497
507
|
/**
|
|
498
|
-
* Converts
|
|
499
|
-
* The resulting mesh has no bones but looks identical.
|
|
508
|
+
* Converts skinned mesh to static mesh in current pose.
|
|
500
509
|
*
|
|
501
510
|
* @param skinnedMesh - Mesh to convert
|
|
502
|
-
* @returns Static mesh with baked
|
|
511
|
+
* @returns Static mesh with baked positions
|
|
503
512
|
*/
|
|
504
513
|
static bakePose(skinnedMesh) {
|
|
505
514
|
const bakedGeometry = skinnedMesh.geometry.clone();
|
|
@@ -522,13 +531,13 @@ class SkinnedMeshBaker {
|
|
|
522
531
|
return mesh;
|
|
523
532
|
}
|
|
524
533
|
/**
|
|
525
|
-
* Bakes
|
|
534
|
+
* Bakes animation frame to static mesh.
|
|
526
535
|
*
|
|
527
536
|
* @param armature - Root object with bones
|
|
528
537
|
* @param skinnedMesh - Mesh to convert
|
|
529
|
-
* @param timeOffset - Time in seconds within
|
|
530
|
-
* @param clip - Animation
|
|
531
|
-
* @returns Static mesh with baked
|
|
538
|
+
* @param timeOffset - Time in seconds within animation
|
|
539
|
+
* @param clip - Animation clip for pose
|
|
540
|
+
* @returns Static mesh with baked positions
|
|
532
541
|
*/
|
|
533
542
|
static bakeAnimationFrame(armature, skinnedMesh, timeOffset, clip) {
|
|
534
543
|
const mixer = new AnimationMixer(armature);
|
|
@@ -546,37 +555,15 @@ const METALNESS_BRIGHTNESS_FACTOR = 0.3;
|
|
|
546
555
|
/** Factor for emissive color contribution when combining with base color */
|
|
547
556
|
const EMISSIVE_CONTRIBUTION_FACTOR = 0.5;
|
|
548
557
|
/**
|
|
549
|
-
* Converts
|
|
550
|
-
*
|
|
551
|
-
* Handles translation from PBR StandardMaterial to unlit BasicMaterial.
|
|
552
|
-
* Since BasicMaterial doesn't respond to lighting, applies compensation
|
|
553
|
-
* techniques including brightness adjustments and emissive color combination.
|
|
558
|
+
* Converts MeshStandardMaterial to MeshBasicMaterial with brightness compensation.
|
|
554
559
|
*/
|
|
555
560
|
class StandardToBasicConverter {
|
|
556
561
|
/**
|
|
557
|
-
* Converts
|
|
562
|
+
* Converts MeshStandardMaterial to MeshBasicMaterial.
|
|
558
563
|
*
|
|
559
|
-
*
|
|
560
|
-
*
|
|
561
|
-
*
|
|
562
|
-
* @param standardMaterial - The source MeshStandardMaterial to convert
|
|
563
|
-
* @param options - Configuration options for the conversion
|
|
564
|
-
* @returns A new MeshBasicMaterial with properties mapped from the standard material
|
|
565
|
-
*
|
|
566
|
-
* @example
|
|
567
|
-
* ```typescript
|
|
568
|
-
* const standardMaterial = new MeshStandardMaterial({
|
|
569
|
-
* color: 0x00ff00,
|
|
570
|
-
* metalness: 0.5,
|
|
571
|
-
* emissive: 0x111111,
|
|
572
|
-
* emissiveIntensity: 0.2
|
|
573
|
-
* });
|
|
574
|
-
*
|
|
575
|
-
* const basicMaterial = StandardToBasicConverter.convert(standardMaterial, {
|
|
576
|
-
* brightnessFactor: 1.4,
|
|
577
|
-
* combineEmissive: true
|
|
578
|
-
* });
|
|
579
|
-
* ```
|
|
564
|
+
* @param standardMaterial - Source material to convert
|
|
565
|
+
* @param options - Conversion options
|
|
566
|
+
* @returns New MeshBasicMaterial with mapped properties
|
|
580
567
|
*/
|
|
581
568
|
static convert(standardMaterial, options = {}) {
|
|
582
569
|
const config = {
|
|
@@ -605,11 +592,11 @@ class StandardToBasicConverter {
|
|
|
605
592
|
return basicMaterial;
|
|
606
593
|
}
|
|
607
594
|
/**
|
|
608
|
-
* Copies basic material properties
|
|
595
|
+
* Copies basic material properties.
|
|
609
596
|
*
|
|
610
|
-
* @param source -
|
|
611
|
-
* @param target -
|
|
612
|
-
* @param config -
|
|
597
|
+
* @param source - Source material
|
|
598
|
+
* @param target - Target material
|
|
599
|
+
* @param config - Configuration options
|
|
613
600
|
* @internal
|
|
614
601
|
*/
|
|
615
602
|
static copyBasicProperties(source, target, config) {
|
|
@@ -627,14 +614,11 @@ class StandardToBasicConverter {
|
|
|
627
614
|
}
|
|
628
615
|
}
|
|
629
616
|
/**
|
|
630
|
-
* Converts color
|
|
617
|
+
* Converts color properties with lighting compensation.
|
|
631
618
|
*
|
|
632
|
-
*
|
|
633
|
-
*
|
|
634
|
-
*
|
|
635
|
-
* @param source - The source MeshStandardMaterial
|
|
636
|
-
* @param target - The target MeshBasicMaterial
|
|
637
|
-
* @param config - The resolved configuration options
|
|
619
|
+
* @param source - Source material
|
|
620
|
+
* @param target - Target material
|
|
621
|
+
* @param config - Configuration options
|
|
638
622
|
* @internal
|
|
639
623
|
*/
|
|
640
624
|
static convertColorProperties(source, target, config) {
|
|
@@ -660,13 +644,10 @@ class StandardToBasicConverter {
|
|
|
660
644
|
target.color.b = Math.min(target.color.b, 1.0);
|
|
661
645
|
}
|
|
662
646
|
/**
|
|
663
|
-
* Converts
|
|
664
|
-
*
|
|
665
|
-
* Transfers compatible texture maps including diffuse, alpha, environment,
|
|
666
|
-
* light, and AO maps.
|
|
647
|
+
* Converts texture properties from Standard to Basic material.
|
|
667
648
|
*
|
|
668
|
-
* @param source -
|
|
669
|
-
* @param target -
|
|
649
|
+
* @param source - Source material
|
|
650
|
+
* @param target - Target material
|
|
670
651
|
* @internal
|
|
671
652
|
*/
|
|
672
653
|
static convertTextureMaps(source, target) {
|
|
@@ -703,10 +684,10 @@ class StandardToBasicConverter {
|
|
|
703
684
|
this.copyUVTransforms(source, target);
|
|
704
685
|
}
|
|
705
686
|
/**
|
|
706
|
-
* Copies UV transformation properties
|
|
687
|
+
* Copies UV transformation properties.
|
|
707
688
|
*
|
|
708
|
-
* @param source -
|
|
709
|
-
* @param target -
|
|
689
|
+
* @param source - Source material
|
|
690
|
+
* @param target - Target material
|
|
710
691
|
* @internal
|
|
711
692
|
*/
|
|
712
693
|
static copyUVTransforms(source, target) {
|
|
@@ -721,8 +702,8 @@ class StandardToBasicConverter {
|
|
|
721
702
|
/**
|
|
722
703
|
* Converts transparency and rendering properties.
|
|
723
704
|
*
|
|
724
|
-
* @param source -
|
|
725
|
-
* @param target -
|
|
705
|
+
* @param source - Source material
|
|
706
|
+
* @param target - Target material
|
|
726
707
|
* @internal
|
|
727
708
|
*/
|
|
728
709
|
static convertTransparencyProperties(source, target) {
|
|
@@ -744,33 +725,15 @@ const ROUGHNESS_COLOR_ADJUSTMENT = 0.2;
|
|
|
744
725
|
/** Minimum reflectivity boost for environment maps */
|
|
745
726
|
const REFLECTIVITY_BOOST = 0.1;
|
|
746
727
|
/**
|
|
747
|
-
* Converts
|
|
748
|
-
*
|
|
749
|
-
* Handles translation between PBR properties of StandardMaterial and
|
|
750
|
-
* the Lambertian reflectance model used by LambertMaterial. Applies
|
|
751
|
-
* color compensation based on metalness and roughness values.
|
|
728
|
+
* Converts MeshStandardMaterial to MeshLambertMaterial with PBR compensation.
|
|
752
729
|
*/
|
|
753
730
|
class StandardToLambertConverter {
|
|
754
731
|
/**
|
|
755
|
-
* Converts
|
|
756
|
-
*
|
|
757
|
-
* Performs conversion from PBR StandardMaterial to Lambert lighting model
|
|
758
|
-
* with color compensation based on metalness and roughness values.
|
|
759
|
-
*
|
|
760
|
-
* @param material - The source MeshStandardMaterial to convert
|
|
761
|
-
* @param options - Configuration options for the conversion
|
|
762
|
-
* @returns A new MeshLambertMaterial with properties mapped from the standard material
|
|
732
|
+
* Converts MeshStandardMaterial to MeshLambertMaterial.
|
|
763
733
|
*
|
|
764
|
-
* @
|
|
765
|
-
*
|
|
766
|
-
*
|
|
767
|
-
* color: 0xff0000,
|
|
768
|
-
* metalness: 0.8,
|
|
769
|
-
* roughness: 0.2
|
|
770
|
-
* });
|
|
771
|
-
*
|
|
772
|
-
* const lambertMaterial = StandardToLambertConverter.convert(standardMaterial);
|
|
773
|
-
* ```
|
|
734
|
+
* @param material - Source material to convert
|
|
735
|
+
* @param options - Conversion options
|
|
736
|
+
* @returns New MeshLambertMaterial with mapped properties
|
|
774
737
|
*/
|
|
775
738
|
static convert(material, options = {}) {
|
|
776
739
|
const config = {
|
|
@@ -798,11 +761,11 @@ class StandardToLambertConverter {
|
|
|
798
761
|
return lambertMaterial;
|
|
799
762
|
}
|
|
800
763
|
/**
|
|
801
|
-
* Copies basic material properties
|
|
764
|
+
* Copies basic material properties.
|
|
802
765
|
*
|
|
803
|
-
* @param source -
|
|
804
|
-
* @param target -
|
|
805
|
-
* @param config -
|
|
766
|
+
* @param source - Source material
|
|
767
|
+
* @param target - Target material
|
|
768
|
+
* @param config - Configuration options
|
|
806
769
|
* @internal
|
|
807
770
|
*/
|
|
808
771
|
static copyBasicProperties(source, target, config) {
|
|
@@ -821,14 +784,11 @@ class StandardToLambertConverter {
|
|
|
821
784
|
}
|
|
822
785
|
}
|
|
823
786
|
/**
|
|
824
|
-
* Converts color
|
|
825
|
-
*
|
|
826
|
-
* Applies color adjustments to compensate for the loss of metalness and
|
|
827
|
-
* roughness information when converting to Lambert material.
|
|
787
|
+
* Converts color properties with PBR compensation.
|
|
828
788
|
*
|
|
829
|
-
* @param source -
|
|
830
|
-
* @param target -
|
|
831
|
-
* @param config -
|
|
789
|
+
* @param source - Source material
|
|
790
|
+
* @param target - Target material
|
|
791
|
+
* @param config - Configuration options
|
|
832
792
|
* @internal
|
|
833
793
|
*/
|
|
834
794
|
static convertColorProperties(source, target, config) {
|
|
@@ -849,13 +809,10 @@ class StandardToLambertConverter {
|
|
|
849
809
|
target.emissiveIntensity = source.emissiveIntensity;
|
|
850
810
|
}
|
|
851
811
|
/**
|
|
852
|
-
* Converts
|
|
812
|
+
* Converts texture properties from Standard to Lambert material.
|
|
853
813
|
*
|
|
854
|
-
*
|
|
855
|
-
*
|
|
856
|
-
*
|
|
857
|
-
* @param source - The source MeshStandardMaterial
|
|
858
|
-
* @param target - The target MeshLambertMaterial
|
|
814
|
+
* @param source - Source material
|
|
815
|
+
* @param target - Target material
|
|
859
816
|
* @internal
|
|
860
817
|
*/
|
|
861
818
|
static convertTextureMaps(source, target) {
|
|
@@ -895,10 +852,10 @@ class StandardToLambertConverter {
|
|
|
895
852
|
this.copyUVTransforms(source, target);
|
|
896
853
|
}
|
|
897
854
|
/**
|
|
898
|
-
* Copies UV transformation properties
|
|
855
|
+
* Copies UV transformation properties.
|
|
899
856
|
*
|
|
900
|
-
* @param source -
|
|
901
|
-
* @param target -
|
|
857
|
+
* @param source - Source material
|
|
858
|
+
* @param target - Target material
|
|
902
859
|
* @internal
|
|
903
860
|
*/
|
|
904
861
|
static copyUVTransforms(source, target) {
|
|
@@ -913,8 +870,8 @@ class StandardToLambertConverter {
|
|
|
913
870
|
/**
|
|
914
871
|
* Converts transparency and rendering properties.
|
|
915
872
|
*
|
|
916
|
-
* @param source -
|
|
917
|
-
* @param target -
|
|
873
|
+
* @param source - Source material
|
|
874
|
+
* @param target - Target material
|
|
918
875
|
* @internal
|
|
919
876
|
*/
|
|
920
877
|
static convertTransparencyProperties(source, target) {
|
|
@@ -938,11 +895,7 @@ const LUMINANCE_G = 0.7152;
|
|
|
938
895
|
/** Blue channel weight for luminance calculation (ITU-R BT.709) */
|
|
939
896
|
const LUMINANCE_B = 0.0722;
|
|
940
897
|
/**
|
|
941
|
-
*
|
|
942
|
-
*
|
|
943
|
-
* Extends Three.js DirectionalLight to provide spherical coordinate control
|
|
944
|
-
* (distance, elevation, azimuth) and shadow map configuration for bounding boxes.
|
|
945
|
-
* Also supports sun direction calculation from HDR environment maps.
|
|
898
|
+
* Directional light with spherical positioning and HDR environment support.
|
|
946
899
|
*/
|
|
947
900
|
class Sun extends DirectionalLight {
|
|
948
901
|
constructor() {
|
|
@@ -960,64 +913,48 @@ class Sun extends DirectionalLight {
|
|
|
960
913
|
this._private_tempSpherical = new Spherical();
|
|
961
914
|
}
|
|
962
915
|
/**
|
|
963
|
-
*
|
|
964
|
-
*
|
|
965
|
-
* @returns The distance in world units
|
|
916
|
+
* @returns Distance from light position to origin
|
|
966
917
|
*/
|
|
967
918
|
get distance() {
|
|
968
919
|
return this.position.length();
|
|
969
920
|
}
|
|
970
921
|
/**
|
|
971
|
-
*
|
|
972
|
-
*
|
|
973
|
-
* @returns The elevation angle in radians (phi angle from Three.js Spherical coordinates)
|
|
922
|
+
* @returns Elevation angle in radians (phi angle)
|
|
974
923
|
*/
|
|
975
924
|
get elevation() {
|
|
976
925
|
return this._private_tempSpherical.setFromVector3(this.position).phi;
|
|
977
926
|
}
|
|
978
927
|
/**
|
|
979
|
-
*
|
|
980
|
-
*
|
|
981
|
-
* @returns The azimuth angle in radians (theta angle from Three.js Spherical coordinates)
|
|
928
|
+
* @returns Azimuth angle in radians (theta angle)
|
|
982
929
|
*/
|
|
983
930
|
get azimuth() {
|
|
984
931
|
return this._private_tempSpherical.setFromVector3(this.position).theta;
|
|
985
932
|
}
|
|
986
933
|
/**
|
|
987
|
-
*
|
|
988
|
-
*
|
|
989
|
-
* @param value - The new distance in world units
|
|
934
|
+
* @param value - New distance in world units
|
|
990
935
|
*/
|
|
991
936
|
set distance(value) {
|
|
992
937
|
this._private_tempSpherical.setFromVector3(this.position);
|
|
993
938
|
this.position.setFromSphericalCoords(value, this._private_tempSpherical.phi, this._private_tempSpherical.theta);
|
|
994
939
|
}
|
|
995
940
|
/**
|
|
996
|
-
*
|
|
997
|
-
*
|
|
998
|
-
* @param value - The new elevation angle in radians (phi angle for Three.js Spherical coordinates)
|
|
941
|
+
* @param value - New elevation angle in radians (phi angle)
|
|
999
942
|
*/
|
|
1000
943
|
set elevation(value) {
|
|
1001
944
|
this._private_tempSpherical.setFromVector3(this.position);
|
|
1002
945
|
this.position.setFromSphericalCoords(this._private_tempSpherical.radius, value, this._private_tempSpherical.theta);
|
|
1003
946
|
}
|
|
1004
947
|
/**
|
|
1005
|
-
*
|
|
1006
|
-
*
|
|
1007
|
-
* @param value - The new azimuth angle in radians (theta angle for Three.js Spherical coordinates)
|
|
948
|
+
* @param value - New azimuth angle in radians (theta angle)
|
|
1008
949
|
*/
|
|
1009
950
|
set azimuth(value) {
|
|
1010
951
|
this._private_tempSpherical.setFromVector3(this.position);
|
|
1011
952
|
this.position.setFromSphericalCoords(this._private_tempSpherical.radius, this._private_tempSpherical.phi, value);
|
|
1012
953
|
}
|
|
1013
954
|
/**
|
|
1014
|
-
* Configures
|
|
955
|
+
* Configures shadow camera frustum to cover bounding box.
|
|
1015
956
|
*
|
|
1016
|
-
*
|
|
1017
|
-
* provided bounding box by transforming box corners to light space and
|
|
1018
|
-
* setting camera bounds accordingly.
|
|
1019
|
-
*
|
|
1020
|
-
* @param box3 - The 3D bounding box to cover with shadows
|
|
957
|
+
* @param box3 - 3D bounding box to cover with shadows
|
|
1021
958
|
*/
|
|
1022
959
|
configureShadowsForBoundingBox(box3) {
|
|
1023
960
|
const camera = this.shadow.camera;
|
|
@@ -1049,13 +986,10 @@ class Sun extends DirectionalLight {
|
|
|
1049
986
|
camera.updateProjectionMatrix();
|
|
1050
987
|
}
|
|
1051
988
|
/**
|
|
1052
|
-
* Sets
|
|
1053
|
-
*
|
|
1054
|
-
* Analyzes an HDR texture to find the pixel with the highest luminance value
|
|
1055
|
-
* and positions the sun to shine from that direction using spherical coordinates.
|
|
989
|
+
* Sets sun direction based on brightest point in HDR environment map.
|
|
1056
990
|
*
|
|
1057
|
-
* @param texture -
|
|
1058
|
-
* @param distance -
|
|
991
|
+
* @param texture - HDR texture to analyze (must have image data)
|
|
992
|
+
* @param distance - Distance to place sun from origin
|
|
1059
993
|
*/
|
|
1060
994
|
setDirectionFromHDRTexture(texture, distance = 1) {
|
|
1061
995
|
const data = texture.image.data;
|