@chocozhang/three-model-render 1.0.3 → 1.0.5
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/CHANGELOG.md +39 -0
- package/README.md +134 -97
- package/dist/camera/index.d.ts +59 -36
- package/dist/camera/index.js +83 -67
- package/dist/camera/index.js.map +1 -1
- package/dist/camera/index.mjs +83 -67
- package/dist/camera/index.mjs.map +1 -1
- package/dist/core/index.d.ts +81 -28
- package/dist/core/index.js +194 -104
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.mjs +194 -105
- package/dist/core/index.mjs.map +1 -1
- package/dist/effect/index.d.ts +47 -134
- package/dist/effect/index.js +287 -288
- package/dist/effect/index.js.map +1 -1
- package/dist/effect/index.mjs +287 -288
- package/dist/effect/index.mjs.map +1 -1
- package/dist/index.d.ts +432 -349
- package/dist/index.js +1399 -1228
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1395 -1229
- package/dist/index.mjs.map +1 -1
- package/dist/interaction/index.d.ts +85 -52
- package/dist/interaction/index.js +168 -142
- package/dist/interaction/index.js.map +1 -1
- package/dist/interaction/index.mjs +168 -142
- package/dist/interaction/index.mjs.map +1 -1
- package/dist/loader/index.d.ts +106 -58
- package/dist/loader/index.js +492 -454
- package/dist/loader/index.js.map +1 -1
- package/dist/loader/index.mjs +491 -455
- package/dist/loader/index.mjs.map +1 -1
- package/dist/setup/index.d.ts +26 -24
- package/dist/setup/index.js +125 -163
- package/dist/setup/index.js.map +1 -1
- package/dist/setup/index.mjs +124 -164
- package/dist/setup/index.mjs.map +1 -1
- package/dist/ui/index.d.ts +18 -7
- package/dist/ui/index.js +45 -37
- package/dist/ui/index.js.map +1 -1
- package/dist/ui/index.mjs +45 -37
- package/dist/ui/index.mjs.map +1 -1
- package/package.json +50 -22
package/dist/camera/index.js
CHANGED
|
@@ -21,32 +21,42 @@ function _interopNamespaceDefault(e) {
|
|
|
21
21
|
|
|
22
22
|
var THREE__namespace = /*#__PURE__*/_interopNamespaceDefault(THREE);
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
/**
|
|
25
|
+
* @file followModels.ts
|
|
26
|
+
* @description
|
|
27
|
+
* Camera utility to automatically follow and focus on 3D models.
|
|
28
|
+
* It smoothly moves the camera to an optimal viewing position relative to the target object(s).
|
|
29
|
+
*
|
|
30
|
+
* @best-practice
|
|
31
|
+
* - Use `followModels` to focus on a newly selected object.
|
|
32
|
+
* - Call `cancelFollow` before starting a new manual camera interaction if needed.
|
|
33
|
+
* - Adjust `padding` to control how tight the camera framing is.
|
|
34
|
+
*/
|
|
35
|
+
// Use WeakMap to track animations, allowing for cancellation
|
|
26
36
|
const _animationMap = new WeakMap();
|
|
27
37
|
/**
|
|
28
|
-
*
|
|
38
|
+
* Recommended camera angles for quick selection of common views
|
|
29
39
|
*/
|
|
30
40
|
const FOLLOW_ANGLES = {
|
|
31
|
-
/**
|
|
41
|
+
/** Isometric view (default) - suitable for architecture, mechanical equipment */
|
|
32
42
|
ISOMETRIC: { azimuth: Math.PI / 4, elevation: Math.PI / 4 },
|
|
33
|
-
/**
|
|
43
|
+
/** Front view - suitable for frontal display, UI alignment */
|
|
34
44
|
FRONT: { azimuth: 0, elevation: 0 },
|
|
35
|
-
/**
|
|
45
|
+
/** Right view - suitable for mechanical sections, side inspection */
|
|
36
46
|
RIGHT: { azimuth: Math.PI / 2, elevation: 0 },
|
|
37
|
-
/**
|
|
47
|
+
/** Left view */
|
|
38
48
|
LEFT: { azimuth: -Math.PI / 2, elevation: 0 },
|
|
39
|
-
/**
|
|
49
|
+
/** Back view */
|
|
40
50
|
BACK: { azimuth: Math.PI, elevation: 0 },
|
|
41
|
-
/**
|
|
51
|
+
/** Top view - suitable for maps, layout display */
|
|
42
52
|
TOP: { azimuth: 0, elevation: Math.PI / 2 },
|
|
43
|
-
/**
|
|
53
|
+
/** Low angle view - suitable for vehicles, characters near the ground */
|
|
44
54
|
LOW_ANGLE: { azimuth: Math.PI / 4, elevation: Math.PI / 6 },
|
|
45
|
-
/**
|
|
55
|
+
/** High angle view - suitable for bird's eye view, panoramic browsing */
|
|
46
56
|
HIGH_ANGLE: { azimuth: Math.PI / 4, elevation: Math.PI / 3 }
|
|
47
57
|
};
|
|
48
58
|
/**
|
|
49
|
-
*
|
|
59
|
+
* Collection of easing functions
|
|
50
60
|
*/
|
|
51
61
|
const EASING_FUNCTIONS = {
|
|
52
62
|
linear: (t) => t,
|
|
@@ -55,20 +65,20 @@ const EASING_FUNCTIONS = {
|
|
|
55
65
|
easeIn: (t) => t * t * t
|
|
56
66
|
};
|
|
57
67
|
/**
|
|
58
|
-
*
|
|
68
|
+
* Automatically moves the camera to a diagonal position relative to the target,
|
|
69
|
+
* ensuring the target is within the field of view (smooth transition).
|
|
59
70
|
*
|
|
60
|
-
*
|
|
61
|
-
* -
|
|
62
|
-
* -
|
|
63
|
-
* -
|
|
64
|
-
* - WeakMap
|
|
65
|
-
* -
|
|
71
|
+
* Features:
|
|
72
|
+
* - Supports multiple easing functions
|
|
73
|
+
* - Adds progress callback
|
|
74
|
+
* - Supports animation cancellation
|
|
75
|
+
* - Uses WeakMap to track and prevent memory leaks
|
|
76
|
+
* - Robust error handling
|
|
66
77
|
*/
|
|
67
78
|
function followModels(camera, targets, options = {}) {
|
|
68
|
-
|
|
69
|
-
// ✨ 取消之前的动画
|
|
79
|
+
// Cancel previous animation
|
|
70
80
|
cancelFollow(camera);
|
|
71
|
-
//
|
|
81
|
+
// Boundary check
|
|
72
82
|
const arr = [];
|
|
73
83
|
if (!targets)
|
|
74
84
|
return Promise.resolve();
|
|
@@ -77,31 +87,31 @@ function followModels(camera, targets, options = {}) {
|
|
|
77
87
|
else
|
|
78
88
|
arr.push(targets);
|
|
79
89
|
if (arr.length === 0) {
|
|
80
|
-
console.warn('followModels:
|
|
90
|
+
console.warn('followModels: Target object is empty');
|
|
81
91
|
return Promise.resolve();
|
|
82
92
|
}
|
|
83
93
|
try {
|
|
84
94
|
const box = new THREE__namespace.Box3();
|
|
85
95
|
arr.forEach((o) => box.expandByObject(o));
|
|
86
|
-
//
|
|
96
|
+
// Check bounding box validity
|
|
87
97
|
if (!isFinite(box.min.x) || !isFinite(box.max.x)) {
|
|
88
|
-
console.warn('followModels:
|
|
98
|
+
console.warn('followModels: Failed to calculate bounding box');
|
|
89
99
|
return Promise.resolve();
|
|
90
100
|
}
|
|
91
101
|
const sphere = new THREE__namespace.Sphere();
|
|
92
102
|
box.getBoundingSphere(sphere);
|
|
93
103
|
const center = sphere.center.clone();
|
|
94
104
|
const radiusBase = Math.max(0.001, sphere.radius);
|
|
95
|
-
const duration =
|
|
96
|
-
const padding =
|
|
105
|
+
const duration = options.duration ?? 700;
|
|
106
|
+
const padding = options.padding ?? 1.0;
|
|
97
107
|
const minDistance = options.minDistance;
|
|
98
108
|
const maxDistance = options.maxDistance;
|
|
99
|
-
const controls =
|
|
100
|
-
const azimuth =
|
|
101
|
-
const elevation =
|
|
102
|
-
const easing =
|
|
109
|
+
const controls = options.controls ?? null;
|
|
110
|
+
const azimuth = options.azimuth ?? Math.PI / 4;
|
|
111
|
+
const elevation = options.elevation ?? Math.PI / 4;
|
|
112
|
+
const easing = options.easing ?? 'easeOut';
|
|
103
113
|
const onProgress = options.onProgress;
|
|
104
|
-
//
|
|
114
|
+
// Get easing function
|
|
105
115
|
const easingFn = EASING_FUNCTIONS[easing] || EASING_FUNCTIONS.easeOut;
|
|
106
116
|
let distance = 10;
|
|
107
117
|
if (camera.isPerspectiveCamera) {
|
|
@@ -121,7 +131,7 @@ function followModels(camera, targets, options = {}) {
|
|
|
121
131
|
else {
|
|
122
132
|
distance = camera.position.distanceTo(center);
|
|
123
133
|
}
|
|
124
|
-
//
|
|
134
|
+
// Calculate direction based on azimuth / elevation
|
|
125
135
|
const hx = Math.sin(azimuth);
|
|
126
136
|
const hz = Math.cos(azimuth);
|
|
127
137
|
const dir = new THREE__namespace.Vector3(hx * Math.cos(elevation), Math.sin(elevation), hz * Math.cos(elevation)).normalize();
|
|
@@ -134,7 +144,6 @@ function followModels(camera, targets, options = {}) {
|
|
|
134
144
|
const startTime = performance.now();
|
|
135
145
|
return new Promise((resolve) => {
|
|
136
146
|
const step = (now) => {
|
|
137
|
-
var _a;
|
|
138
147
|
const elapsed = now - startTime;
|
|
139
148
|
const t = Math.min(1, duration > 0 ? elapsed / duration : 1);
|
|
140
149
|
const k = easingFn(t);
|
|
@@ -148,14 +157,16 @@ function followModels(camera, targets, options = {}) {
|
|
|
148
157
|
else {
|
|
149
158
|
camera.lookAt(endTarget);
|
|
150
159
|
}
|
|
151
|
-
(
|
|
152
|
-
|
|
160
|
+
if (camera.updateProjectionMatrix) {
|
|
161
|
+
camera.updateProjectionMatrix();
|
|
162
|
+
}
|
|
163
|
+
// Call progress callback
|
|
153
164
|
if (onProgress) {
|
|
154
165
|
try {
|
|
155
166
|
onProgress(t);
|
|
156
167
|
}
|
|
157
168
|
catch (error) {
|
|
158
|
-
console.error('followModels:
|
|
169
|
+
console.error('followModels: Progress callback error', error);
|
|
159
170
|
}
|
|
160
171
|
}
|
|
161
172
|
if (t < 1) {
|
|
@@ -181,12 +192,12 @@ function followModels(camera, targets, options = {}) {
|
|
|
181
192
|
});
|
|
182
193
|
}
|
|
183
194
|
catch (error) {
|
|
184
|
-
console.error('followModels:
|
|
195
|
+
console.error('followModels: Execution failed', error);
|
|
185
196
|
return Promise.reject(error);
|
|
186
197
|
}
|
|
187
198
|
}
|
|
188
199
|
/**
|
|
189
|
-
*
|
|
200
|
+
* Cancel the camera follow animation
|
|
190
201
|
*/
|
|
191
202
|
function cancelFollow(camera) {
|
|
192
203
|
const rafId = _animationMap.get(camera);
|
|
@@ -196,42 +207,47 @@ function cancelFollow(camera) {
|
|
|
196
207
|
}
|
|
197
208
|
}
|
|
198
209
|
|
|
199
|
-
// src/utils/setView.ts - 优化版
|
|
200
210
|
/**
|
|
201
|
-
*
|
|
211
|
+
* @file setView.ts
|
|
212
|
+
* @description
|
|
213
|
+
* Utility to smoothly transition the camera to preset views (Front, Back, Top, Isometric, etc.).
|
|
214
|
+
*
|
|
215
|
+
* @best-practice
|
|
216
|
+
* - Use `setView` for UI buttons that switch camera angles.
|
|
217
|
+
* - Leverage `ViewPresets` for readable code when using standard views.
|
|
218
|
+
*/
|
|
219
|
+
/**
|
|
220
|
+
* Smoothly switches the camera to the optimal angle for the model.
|
|
202
221
|
*
|
|
203
|
-
*
|
|
204
|
-
* -
|
|
205
|
-
* -
|
|
206
|
-
* -
|
|
207
|
-
* -
|
|
208
|
-
* -
|
|
222
|
+
* Features:
|
|
223
|
+
* - Reuses followModels logic to avoid code duplication
|
|
224
|
+
* - Supports more angles
|
|
225
|
+
* - Enhanced configuration options
|
|
226
|
+
* - Returns Promise to support chaining
|
|
227
|
+
* - Supports animation cancellation
|
|
209
228
|
*
|
|
210
|
-
* @param camera THREE.PerspectiveCamera
|
|
211
|
-
* @param controls OrbitControls
|
|
212
|
-
* @param targetObj THREE.Object3D
|
|
213
|
-
* @param position
|
|
214
|
-
* @param options
|
|
229
|
+
* @param camera THREE.PerspectiveCamera instance
|
|
230
|
+
* @param controls OrbitControls instance
|
|
231
|
+
* @param targetObj THREE.Object3D model object
|
|
232
|
+
* @param position View position
|
|
233
|
+
* @param options Configuration options
|
|
215
234
|
* @returns Promise<void>
|
|
216
235
|
*/
|
|
217
236
|
function setView(camera, controls, targetObj, position = 'front', options = {}) {
|
|
218
237
|
const { distanceFactor = 0.8, duration = 1000, easing = 'easeInOut', onProgress } = options;
|
|
219
|
-
//
|
|
238
|
+
// Boundary check
|
|
220
239
|
if (!targetObj) {
|
|
221
|
-
console.warn('setView:
|
|
240
|
+
console.warn('setView: Target object is empty');
|
|
222
241
|
return Promise.reject(new Error('Target object is required'));
|
|
223
242
|
}
|
|
224
243
|
try {
|
|
225
|
-
//
|
|
244
|
+
// Calculate bounding box
|
|
226
245
|
const box = new THREE__namespace.Box3().setFromObject(targetObj);
|
|
227
246
|
if (!isFinite(box.min.x)) {
|
|
228
|
-
console.warn('setView:
|
|
247
|
+
console.warn('setView: Failed to calculate bounding box');
|
|
229
248
|
return Promise.reject(new Error('Invalid bounding box'));
|
|
230
249
|
}
|
|
231
|
-
|
|
232
|
-
const size = box.getSize(new THREE__namespace.Vector3());
|
|
233
|
-
const maxSize = Math.max(size.x, size.y, size.z);
|
|
234
|
-
// ✨ 使用映射表简化视角计算
|
|
250
|
+
// Use mapping table for creating view angles
|
|
235
251
|
const viewAngles = {
|
|
236
252
|
'front': { azimuth: 0, elevation: 0 },
|
|
237
253
|
'back': { azimuth: Math.PI, elevation: 0 },
|
|
@@ -242,7 +258,7 @@ function setView(camera, controls, targetObj, position = 'front', options = {})
|
|
|
242
258
|
'iso': { azimuth: Math.PI / 4, elevation: Math.PI / 4 }
|
|
243
259
|
};
|
|
244
260
|
const angle = viewAngles[position] || viewAngles.front;
|
|
245
|
-
//
|
|
261
|
+
// Reuse followModels to avoid code duplication
|
|
246
262
|
return followModels(camera, targetObj, {
|
|
247
263
|
duration,
|
|
248
264
|
padding: distanceFactor,
|
|
@@ -254,30 +270,30 @@ function setView(camera, controls, targetObj, position = 'front', options = {})
|
|
|
254
270
|
});
|
|
255
271
|
}
|
|
256
272
|
catch (error) {
|
|
257
|
-
console.error('setView:
|
|
273
|
+
console.error('setView: Execution failed', error);
|
|
258
274
|
return Promise.reject(error);
|
|
259
275
|
}
|
|
260
276
|
}
|
|
261
277
|
/**
|
|
262
|
-
*
|
|
278
|
+
* Cancel view switch animation
|
|
263
279
|
*/
|
|
264
280
|
function cancelSetView(camera) {
|
|
265
281
|
cancelFollow(camera);
|
|
266
282
|
}
|
|
267
283
|
/**
|
|
268
|
-
*
|
|
284
|
+
* Preset view shortcut methods
|
|
269
285
|
*/
|
|
270
286
|
const ViewPresets = {
|
|
271
287
|
/**
|
|
272
|
-
*
|
|
288
|
+
* Front View
|
|
273
289
|
*/
|
|
274
290
|
front: (camera, controls, target, options) => setView(camera, controls, target, 'front', options),
|
|
275
291
|
/**
|
|
276
|
-
*
|
|
292
|
+
* Isometric View
|
|
277
293
|
*/
|
|
278
294
|
isometric: (camera, controls, target, options) => setView(camera, controls, target, 'iso', options),
|
|
279
295
|
/**
|
|
280
|
-
*
|
|
296
|
+
* Top View
|
|
281
297
|
*/
|
|
282
298
|
top: (camera, controls, target, options) => setView(camera, controls, target, 'top', options)
|
|
283
299
|
};
|
package/dist/camera/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../src/camera/followModels.ts","../../src/camera/setView.ts"],"sourcesContent":[null,null],"names":["THREE"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../src/camera/followModels.ts","../../src/camera/setView.ts"],"sourcesContent":[null,null],"names":["THREE"],"mappings":"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"}
|
package/dist/camera/index.mjs
CHANGED
|
@@ -1,31 +1,41 @@
|
|
|
1
1
|
import * as THREE from 'three';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
/**
|
|
4
|
+
* @file followModels.ts
|
|
5
|
+
* @description
|
|
6
|
+
* Camera utility to automatically follow and focus on 3D models.
|
|
7
|
+
* It smoothly moves the camera to an optimal viewing position relative to the target object(s).
|
|
8
|
+
*
|
|
9
|
+
* @best-practice
|
|
10
|
+
* - Use `followModels` to focus on a newly selected object.
|
|
11
|
+
* - Call `cancelFollow` before starting a new manual camera interaction if needed.
|
|
12
|
+
* - Adjust `padding` to control how tight the camera framing is.
|
|
13
|
+
*/
|
|
14
|
+
// Use WeakMap to track animations, allowing for cancellation
|
|
5
15
|
const _animationMap = new WeakMap();
|
|
6
16
|
/**
|
|
7
|
-
*
|
|
17
|
+
* Recommended camera angles for quick selection of common views
|
|
8
18
|
*/
|
|
9
19
|
const FOLLOW_ANGLES = {
|
|
10
|
-
/**
|
|
20
|
+
/** Isometric view (default) - suitable for architecture, mechanical equipment */
|
|
11
21
|
ISOMETRIC: { azimuth: Math.PI / 4, elevation: Math.PI / 4 },
|
|
12
|
-
/**
|
|
22
|
+
/** Front view - suitable for frontal display, UI alignment */
|
|
13
23
|
FRONT: { azimuth: 0, elevation: 0 },
|
|
14
|
-
/**
|
|
24
|
+
/** Right view - suitable for mechanical sections, side inspection */
|
|
15
25
|
RIGHT: { azimuth: Math.PI / 2, elevation: 0 },
|
|
16
|
-
/**
|
|
26
|
+
/** Left view */
|
|
17
27
|
LEFT: { azimuth: -Math.PI / 2, elevation: 0 },
|
|
18
|
-
/**
|
|
28
|
+
/** Back view */
|
|
19
29
|
BACK: { azimuth: Math.PI, elevation: 0 },
|
|
20
|
-
/**
|
|
30
|
+
/** Top view - suitable for maps, layout display */
|
|
21
31
|
TOP: { azimuth: 0, elevation: Math.PI / 2 },
|
|
22
|
-
/**
|
|
32
|
+
/** Low angle view - suitable for vehicles, characters near the ground */
|
|
23
33
|
LOW_ANGLE: { azimuth: Math.PI / 4, elevation: Math.PI / 6 },
|
|
24
|
-
/**
|
|
34
|
+
/** High angle view - suitable for bird's eye view, panoramic browsing */
|
|
25
35
|
HIGH_ANGLE: { azimuth: Math.PI / 4, elevation: Math.PI / 3 }
|
|
26
36
|
};
|
|
27
37
|
/**
|
|
28
|
-
*
|
|
38
|
+
* Collection of easing functions
|
|
29
39
|
*/
|
|
30
40
|
const EASING_FUNCTIONS = {
|
|
31
41
|
linear: (t) => t,
|
|
@@ -34,20 +44,20 @@ const EASING_FUNCTIONS = {
|
|
|
34
44
|
easeIn: (t) => t * t * t
|
|
35
45
|
};
|
|
36
46
|
/**
|
|
37
|
-
*
|
|
47
|
+
* Automatically moves the camera to a diagonal position relative to the target,
|
|
48
|
+
* ensuring the target is within the field of view (smooth transition).
|
|
38
49
|
*
|
|
39
|
-
*
|
|
40
|
-
* -
|
|
41
|
-
* -
|
|
42
|
-
* -
|
|
43
|
-
* - WeakMap
|
|
44
|
-
* -
|
|
50
|
+
* Features:
|
|
51
|
+
* - Supports multiple easing functions
|
|
52
|
+
* - Adds progress callback
|
|
53
|
+
* - Supports animation cancellation
|
|
54
|
+
* - Uses WeakMap to track and prevent memory leaks
|
|
55
|
+
* - Robust error handling
|
|
45
56
|
*/
|
|
46
57
|
function followModels(camera, targets, options = {}) {
|
|
47
|
-
|
|
48
|
-
// ✨ 取消之前的动画
|
|
58
|
+
// Cancel previous animation
|
|
49
59
|
cancelFollow(camera);
|
|
50
|
-
//
|
|
60
|
+
// Boundary check
|
|
51
61
|
const arr = [];
|
|
52
62
|
if (!targets)
|
|
53
63
|
return Promise.resolve();
|
|
@@ -56,31 +66,31 @@ function followModels(camera, targets, options = {}) {
|
|
|
56
66
|
else
|
|
57
67
|
arr.push(targets);
|
|
58
68
|
if (arr.length === 0) {
|
|
59
|
-
console.warn('followModels:
|
|
69
|
+
console.warn('followModels: Target object is empty');
|
|
60
70
|
return Promise.resolve();
|
|
61
71
|
}
|
|
62
72
|
try {
|
|
63
73
|
const box = new THREE.Box3();
|
|
64
74
|
arr.forEach((o) => box.expandByObject(o));
|
|
65
|
-
//
|
|
75
|
+
// Check bounding box validity
|
|
66
76
|
if (!isFinite(box.min.x) || !isFinite(box.max.x)) {
|
|
67
|
-
console.warn('followModels:
|
|
77
|
+
console.warn('followModels: Failed to calculate bounding box');
|
|
68
78
|
return Promise.resolve();
|
|
69
79
|
}
|
|
70
80
|
const sphere = new THREE.Sphere();
|
|
71
81
|
box.getBoundingSphere(sphere);
|
|
72
82
|
const center = sphere.center.clone();
|
|
73
83
|
const radiusBase = Math.max(0.001, sphere.radius);
|
|
74
|
-
const duration =
|
|
75
|
-
const padding =
|
|
84
|
+
const duration = options.duration ?? 700;
|
|
85
|
+
const padding = options.padding ?? 1.0;
|
|
76
86
|
const minDistance = options.minDistance;
|
|
77
87
|
const maxDistance = options.maxDistance;
|
|
78
|
-
const controls =
|
|
79
|
-
const azimuth =
|
|
80
|
-
const elevation =
|
|
81
|
-
const easing =
|
|
88
|
+
const controls = options.controls ?? null;
|
|
89
|
+
const azimuth = options.azimuth ?? Math.PI / 4;
|
|
90
|
+
const elevation = options.elevation ?? Math.PI / 4;
|
|
91
|
+
const easing = options.easing ?? 'easeOut';
|
|
82
92
|
const onProgress = options.onProgress;
|
|
83
|
-
//
|
|
93
|
+
// Get easing function
|
|
84
94
|
const easingFn = EASING_FUNCTIONS[easing] || EASING_FUNCTIONS.easeOut;
|
|
85
95
|
let distance = 10;
|
|
86
96
|
if (camera.isPerspectiveCamera) {
|
|
@@ -100,7 +110,7 @@ function followModels(camera, targets, options = {}) {
|
|
|
100
110
|
else {
|
|
101
111
|
distance = camera.position.distanceTo(center);
|
|
102
112
|
}
|
|
103
|
-
//
|
|
113
|
+
// Calculate direction based on azimuth / elevation
|
|
104
114
|
const hx = Math.sin(azimuth);
|
|
105
115
|
const hz = Math.cos(azimuth);
|
|
106
116
|
const dir = new THREE.Vector3(hx * Math.cos(elevation), Math.sin(elevation), hz * Math.cos(elevation)).normalize();
|
|
@@ -113,7 +123,6 @@ function followModels(camera, targets, options = {}) {
|
|
|
113
123
|
const startTime = performance.now();
|
|
114
124
|
return new Promise((resolve) => {
|
|
115
125
|
const step = (now) => {
|
|
116
|
-
var _a;
|
|
117
126
|
const elapsed = now - startTime;
|
|
118
127
|
const t = Math.min(1, duration > 0 ? elapsed / duration : 1);
|
|
119
128
|
const k = easingFn(t);
|
|
@@ -127,14 +136,16 @@ function followModels(camera, targets, options = {}) {
|
|
|
127
136
|
else {
|
|
128
137
|
camera.lookAt(endTarget);
|
|
129
138
|
}
|
|
130
|
-
(
|
|
131
|
-
|
|
139
|
+
if (camera.updateProjectionMatrix) {
|
|
140
|
+
camera.updateProjectionMatrix();
|
|
141
|
+
}
|
|
142
|
+
// Call progress callback
|
|
132
143
|
if (onProgress) {
|
|
133
144
|
try {
|
|
134
145
|
onProgress(t);
|
|
135
146
|
}
|
|
136
147
|
catch (error) {
|
|
137
|
-
console.error('followModels:
|
|
148
|
+
console.error('followModels: Progress callback error', error);
|
|
138
149
|
}
|
|
139
150
|
}
|
|
140
151
|
if (t < 1) {
|
|
@@ -160,12 +171,12 @@ function followModels(camera, targets, options = {}) {
|
|
|
160
171
|
});
|
|
161
172
|
}
|
|
162
173
|
catch (error) {
|
|
163
|
-
console.error('followModels:
|
|
174
|
+
console.error('followModels: Execution failed', error);
|
|
164
175
|
return Promise.reject(error);
|
|
165
176
|
}
|
|
166
177
|
}
|
|
167
178
|
/**
|
|
168
|
-
*
|
|
179
|
+
* Cancel the camera follow animation
|
|
169
180
|
*/
|
|
170
181
|
function cancelFollow(camera) {
|
|
171
182
|
const rafId = _animationMap.get(camera);
|
|
@@ -175,42 +186,47 @@ function cancelFollow(camera) {
|
|
|
175
186
|
}
|
|
176
187
|
}
|
|
177
188
|
|
|
178
|
-
// src/utils/setView.ts - 优化版
|
|
179
189
|
/**
|
|
180
|
-
*
|
|
190
|
+
* @file setView.ts
|
|
191
|
+
* @description
|
|
192
|
+
* Utility to smoothly transition the camera to preset views (Front, Back, Top, Isometric, etc.).
|
|
193
|
+
*
|
|
194
|
+
* @best-practice
|
|
195
|
+
* - Use `setView` for UI buttons that switch camera angles.
|
|
196
|
+
* - Leverage `ViewPresets` for readable code when using standard views.
|
|
197
|
+
*/
|
|
198
|
+
/**
|
|
199
|
+
* Smoothly switches the camera to the optimal angle for the model.
|
|
181
200
|
*
|
|
182
|
-
*
|
|
183
|
-
* -
|
|
184
|
-
* -
|
|
185
|
-
* -
|
|
186
|
-
* -
|
|
187
|
-
* -
|
|
201
|
+
* Features:
|
|
202
|
+
* - Reuses followModels logic to avoid code duplication
|
|
203
|
+
* - Supports more angles
|
|
204
|
+
* - Enhanced configuration options
|
|
205
|
+
* - Returns Promise to support chaining
|
|
206
|
+
* - Supports animation cancellation
|
|
188
207
|
*
|
|
189
|
-
* @param camera THREE.PerspectiveCamera
|
|
190
|
-
* @param controls OrbitControls
|
|
191
|
-
* @param targetObj THREE.Object3D
|
|
192
|
-
* @param position
|
|
193
|
-
* @param options
|
|
208
|
+
* @param camera THREE.PerspectiveCamera instance
|
|
209
|
+
* @param controls OrbitControls instance
|
|
210
|
+
* @param targetObj THREE.Object3D model object
|
|
211
|
+
* @param position View position
|
|
212
|
+
* @param options Configuration options
|
|
194
213
|
* @returns Promise<void>
|
|
195
214
|
*/
|
|
196
215
|
function setView(camera, controls, targetObj, position = 'front', options = {}) {
|
|
197
216
|
const { distanceFactor = 0.8, duration = 1000, easing = 'easeInOut', onProgress } = options;
|
|
198
|
-
//
|
|
217
|
+
// Boundary check
|
|
199
218
|
if (!targetObj) {
|
|
200
|
-
console.warn('setView:
|
|
219
|
+
console.warn('setView: Target object is empty');
|
|
201
220
|
return Promise.reject(new Error('Target object is required'));
|
|
202
221
|
}
|
|
203
222
|
try {
|
|
204
|
-
//
|
|
223
|
+
// Calculate bounding box
|
|
205
224
|
const box = new THREE.Box3().setFromObject(targetObj);
|
|
206
225
|
if (!isFinite(box.min.x)) {
|
|
207
|
-
console.warn('setView:
|
|
226
|
+
console.warn('setView: Failed to calculate bounding box');
|
|
208
227
|
return Promise.reject(new Error('Invalid bounding box'));
|
|
209
228
|
}
|
|
210
|
-
|
|
211
|
-
const size = box.getSize(new THREE.Vector3());
|
|
212
|
-
const maxSize = Math.max(size.x, size.y, size.z);
|
|
213
|
-
// ✨ 使用映射表简化视角计算
|
|
229
|
+
// Use mapping table for creating view angles
|
|
214
230
|
const viewAngles = {
|
|
215
231
|
'front': { azimuth: 0, elevation: 0 },
|
|
216
232
|
'back': { azimuth: Math.PI, elevation: 0 },
|
|
@@ -221,7 +237,7 @@ function setView(camera, controls, targetObj, position = 'front', options = {})
|
|
|
221
237
|
'iso': { azimuth: Math.PI / 4, elevation: Math.PI / 4 }
|
|
222
238
|
};
|
|
223
239
|
const angle = viewAngles[position] || viewAngles.front;
|
|
224
|
-
//
|
|
240
|
+
// Reuse followModels to avoid code duplication
|
|
225
241
|
return followModels(camera, targetObj, {
|
|
226
242
|
duration,
|
|
227
243
|
padding: distanceFactor,
|
|
@@ -233,30 +249,30 @@ function setView(camera, controls, targetObj, position = 'front', options = {})
|
|
|
233
249
|
});
|
|
234
250
|
}
|
|
235
251
|
catch (error) {
|
|
236
|
-
console.error('setView:
|
|
252
|
+
console.error('setView: Execution failed', error);
|
|
237
253
|
return Promise.reject(error);
|
|
238
254
|
}
|
|
239
255
|
}
|
|
240
256
|
/**
|
|
241
|
-
*
|
|
257
|
+
* Cancel view switch animation
|
|
242
258
|
*/
|
|
243
259
|
function cancelSetView(camera) {
|
|
244
260
|
cancelFollow(camera);
|
|
245
261
|
}
|
|
246
262
|
/**
|
|
247
|
-
*
|
|
263
|
+
* Preset view shortcut methods
|
|
248
264
|
*/
|
|
249
265
|
const ViewPresets = {
|
|
250
266
|
/**
|
|
251
|
-
*
|
|
267
|
+
* Front View
|
|
252
268
|
*/
|
|
253
269
|
front: (camera, controls, target, options) => setView(camera, controls, target, 'front', options),
|
|
254
270
|
/**
|
|
255
|
-
*
|
|
271
|
+
* Isometric View
|
|
256
272
|
*/
|
|
257
273
|
isometric: (camera, controls, target, options) => setView(camera, controls, target, 'iso', options),
|
|
258
274
|
/**
|
|
259
|
-
*
|
|
275
|
+
* Top View
|
|
260
276
|
*/
|
|
261
277
|
top: (camera, controls, target, options) => setView(camera, controls, target, 'top', options)
|
|
262
278
|
};
|