@combeenation/3d-viewer 14.0.1-rc1 → 15.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -9
- package/dist/lib-cjs/buildinfo.json +3 -3
- package/dist/lib-cjs/commonjs.tsconfig.tsbuildinfo +1 -1
- package/dist/lib-cjs/index.d.ts +51 -62
- package/dist/lib-cjs/index.js +84 -94
- package/dist/lib-cjs/index.js.map +1 -1
- package/dist/lib-cjs/internal/cbn-custom-babylon-loader-plugin.d.ts +10 -10
- package/dist/lib-cjs/internal/cbn-custom-babylon-loader-plugin.js +131 -131
- package/dist/lib-cjs/internal/cbn-custom-babylon-loader-plugin.js.map +1 -1
- package/dist/lib-cjs/internal/cloning-helper.d.ts +19 -19
- package/dist/lib-cjs/internal/cloning-helper.js +163 -163
- package/dist/lib-cjs/internal/device-helper.d.ts +9 -9
- package/dist/lib-cjs/internal/device-helper.js +24 -24
- package/dist/lib-cjs/internal/geometry-helper.d.ts +21 -21
- package/dist/lib-cjs/internal/geometry-helper.js +145 -145
- package/dist/lib-cjs/internal/metadata-helper.d.ts +26 -26
- package/dist/lib-cjs/internal/metadata-helper.js +50 -50
- package/dist/lib-cjs/internal/paintable-helper.d.ts +40 -40
- package/dist/lib-cjs/internal/paintable-helper.js +234 -286
- package/dist/lib-cjs/internal/paintable-helper.js.map +1 -1
- package/dist/lib-cjs/internal/svg-helper.d.ts +4 -0
- package/dist/lib-cjs/internal/svg-helper.js +67 -0
- package/dist/lib-cjs/internal/svg-helper.js.map +1 -0
- package/dist/lib-cjs/internal/tags-helper.d.ts +12 -12
- package/dist/lib-cjs/internal/tags-helper.js +39 -37
- package/dist/lib-cjs/internal/tags-helper.js.map +1 -1
- package/dist/lib-cjs/internal/texture-parameter-helper.d.ts +37 -0
- package/dist/lib-cjs/internal/texture-parameter-helper.js +287 -0
- package/dist/lib-cjs/internal/texture-parameter-helper.js.map +1 -0
- package/dist/lib-cjs/manager/camera-manager.d.ts +110 -110
- package/dist/lib-cjs/manager/camera-manager.js +209 -206
- package/dist/lib-cjs/manager/camera-manager.js.map +1 -1
- package/dist/lib-cjs/manager/debug-manager.d.ts +60 -60
- package/dist/lib-cjs/manager/debug-manager.js +217 -217
- package/dist/lib-cjs/manager/event-manager.d.ts +52 -52
- package/dist/lib-cjs/manager/event-manager.js +71 -71
- package/dist/lib-cjs/manager/gltf-export-manager.d.ts +75 -84
- package/dist/lib-cjs/manager/gltf-export-manager.js +286 -290
- package/dist/lib-cjs/manager/gltf-export-manager.js.map +1 -1
- package/dist/lib-cjs/manager/material-manager.d.ts +35 -35
- package/dist/lib-cjs/manager/material-manager.js +125 -125
- package/dist/lib-cjs/manager/model-manager.d.ts +145 -145
- package/dist/lib-cjs/manager/model-manager.js +382 -382
- package/dist/lib-cjs/manager/parameter-manager.d.ts +228 -210
- package/dist/lib-cjs/manager/parameter-manager.js +573 -514
- package/dist/lib-cjs/manager/parameter-manager.js.map +1 -1
- package/dist/lib-cjs/manager/scene-manager.d.ts +45 -45
- package/dist/lib-cjs/manager/scene-manager.js +64 -64
- package/dist/lib-cjs/manager/texture-manager.d.ts +12 -12
- package/dist/lib-cjs/manager/texture-manager.js +43 -43
- package/dist/lib-cjs/viewer-error.d.ts +49 -48
- package/dist/lib-cjs/viewer-error.js +61 -60
- package/dist/lib-cjs/viewer-error.js.map +1 -1
- package/dist/lib-cjs/viewer.d.ts +115 -115
- package/dist/lib-cjs/viewer.js +217 -217
- package/dist/lib-cjs/viewer.js.map +1 -1
- package/package.json +94 -91
- package/src/buildinfo.json +3 -3
- package/src/dev.ts +47 -47
- package/src/global-types.d.ts +39 -39
- package/src/index.ts +71 -81
- package/src/internal/cbn-custom-babylon-loader-plugin.ts +159 -159
- package/src/internal/cloning-helper.ts +225 -225
- package/src/internal/device-helper.ts +25 -25
- package/src/internal/geometry-helper.ts +181 -181
- package/src/internal/metadata-helper.ts +63 -63
- package/src/internal/paintable-helper.ts +258 -310
- package/src/internal/svg-helper.ts +52 -0
- package/src/internal/tags-helper.ts +43 -41
- package/src/internal/texture-parameter-helper.ts +353 -0
- package/src/manager/camera-manager.ts +368 -365
- package/src/manager/debug-manager.ts +245 -245
- package/src/manager/event-manager.ts +72 -72
- package/src/manager/gltf-export-manager.ts +356 -357
- package/src/manager/material-manager.ts +135 -135
- package/src/manager/model-manager.ts +458 -458
- package/src/manager/parameter-manager.ts +730 -652
- package/src/manager/scene-manager.ts +101 -101
- package/src/manager/texture-manager.ts +32 -32
- package/src/viewer-error.ts +69 -68
- package/src/viewer.ts +290 -290
|
@@ -1,365 +1,368 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Animation,
|
|
3
|
-
AnimationGroup,
|
|
4
|
-
ArcRotateCamera,
|
|
5
|
-
BoundingSphere,
|
|
6
|
-
ExcludedGeometryList,
|
|
7
|
-
IScreenshotSize,
|
|
8
|
-
ScreenshotTools,
|
|
9
|
-
Vector3,
|
|
10
|
-
Viewer,
|
|
11
|
-
ViewerEvent,
|
|
12
|
-
} from '../index';
|
|
13
|
-
import { isNodeExcluded } from '../internal/geometry-helper';
|
|
14
|
-
|
|
15
|
-
export type CameraPosition = {
|
|
16
|
-
alpha: number;
|
|
17
|
-
beta: number;
|
|
18
|
-
radius: number;
|
|
19
|
-
target: Vector3;
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
export type AutofocusSettings = {
|
|
23
|
-
/** Can be used to customize the margins shown around the 3d model. Defaults to 1. */
|
|
24
|
-
radiusFactor?: number;
|
|
25
|
-
adjustWheelPrecision?: boolean;
|
|
26
|
-
adjustPanningSensibility?: boolean;
|
|
27
|
-
adjustPinchPrecision?: boolean;
|
|
28
|
-
/** Desired horizontal camera angle, this won't be overwritten by the autofocus function */
|
|
29
|
-
alpha?: number;
|
|
30
|
-
/** Desired vertical camera angle, this won't be overwritten by the autofocus function */
|
|
31
|
-
beta?: number;
|
|
32
|
-
/** Optional list of geometry to be excluded from consideration */
|
|
33
|
-
exclude?: ExcludedGeometryList;
|
|
34
|
-
durationMs?: number;
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
export type ScreenshotSettings = {
|
|
38
|
-
/** Width of the final screenshot image, defaults to canvas width */
|
|
39
|
-
width?: number;
|
|
40
|
-
/** Height of the final screenshot image, defaults to canvas height */
|
|
41
|
-
height?: number;
|
|
42
|
-
/** Camera alpha angle used for the screenshot, defaults to alpha angle of currently active camera */
|
|
43
|
-
alpha?: number;
|
|
44
|
-
/** Camera beta angle used for the screenshot, defaults to beta angle of currently active camera */
|
|
45
|
-
beta?: number;
|
|
46
|
-
/**
|
|
47
|
-
* Camera radius used for the screenshot, default value depends on `autofocusScene` flag:
|
|
48
|
-
* - `true`: radius is calculated automatically so that the whole current scene content is visible
|
|
49
|
-
* - `false`: radius of currently active camera is used
|
|
50
|
-
*/
|
|
51
|
-
radius?: number;
|
|
52
|
-
/**
|
|
53
|
-
* Camera target used for the screenshot, default value depends on `autofocusScene` flag:
|
|
54
|
-
* - `true`: center of the current scene content is set as camera target
|
|
55
|
-
* - `false`: target of currently active camera is used
|
|
56
|
-
*/
|
|
57
|
-
target?: Vector3;
|
|
58
|
-
/** Used to scale the calculated radius if `radius` property is not set and `autofocusScene` mode is active */
|
|
59
|
-
radiusFactor?: number;
|
|
60
|
-
/** Can be used to automatically calculate camera `radius` and `target`, if these 2 settings are not defined
|
|
61
|
-
* explicitely */
|
|
62
|
-
autofocusScene?: boolean;
|
|
63
|
-
/** Optional list of geometry to be excluded from consideration */
|
|
64
|
-
exclude?: ExcludedGeometryList;
|
|
65
|
-
/**
|
|
66
|
-
* "MIME type" of the returned screenshot image, defaults to `image/png`
|
|
67
|
-
*
|
|
68
|
-
* **Info regarding JPEG:** \
|
|
69
|
-
* Use mimeType `image/jpeg` (**not** `image/jpg`) when creating jpeg's. \
|
|
70
|
-
* Also ensure that the viewer scenes `clearColor` has an alpha value of `1` as jpeg's don't
|
|
71
|
-
* support transparency. Otherwise background will always be black for jpeg's.
|
|
72
|
-
*/
|
|
73
|
-
mimeType?: string;
|
|
74
|
-
/** If file name is given, the screenshot image will be downloaded and the base64 string will NOT be returned! */
|
|
75
|
-
fileName?: string;
|
|
76
|
-
/** Expert settings to tweak the screenshot image, see [Babylon.js](https://doc.babylonjs.com/typedoc/functions/BABYLON.CreateScreenshotUsingRenderTarget) docs for further information */
|
|
77
|
-
samples?: number;
|
|
78
|
-
/** Expert settings to tweak the screenshot image, see [Babylon.js](https://doc.babylonjs.com/typedoc/functions/BABYLON.CreateScreenshotUsingRenderTarget) docs for further information */
|
|
79
|
-
antialiasing?: boolean;
|
|
80
|
-
/** Expert settings to tweak the screenshot image, see [Babylon.js](https://doc.babylonjs.com/typedoc/functions/BABYLON.CreateScreenshotUsingRenderTarget) docs for further information */
|
|
81
|
-
renderSprites?: boolean;
|
|
82
|
-
/** Expert settings to tweak the screenshot image, see [Babylon.js](https://doc.babylonjs.com/typedoc/functions/BABYLON.CreateScreenshotUsingRenderTarget) docs for further information */
|
|
83
|
-
enableStencilBuffer?: boolean;
|
|
84
|
-
/** Expert settings to tweak the screenshot image, see [Babylon.js](https://doc.babylonjs.com/typedoc/functions/BABYLON.CreateScreenshotUsingRenderTarget) docs for further information */
|
|
85
|
-
useLayerMask?: boolean;
|
|
86
|
-
/** Expert settings to tweak the screenshot image, see [Babylon.js](https://doc.babylonjs.com/typedoc/functions/BABYLON.CreateScreenshotUsingRenderTarget) docs for further information */
|
|
87
|
-
quality?: number;
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Manager for camera related tasks
|
|
92
|
-
*/
|
|
93
|
-
export class CameraManager {
|
|
94
|
-
public static readonly CAMERA_ANIMATION_NAME = '__cameraAnimation__';
|
|
95
|
-
|
|
96
|
-
/** @internal */
|
|
97
|
-
public static readonly DEFAULT_CAMERA_POSITION: CameraPosition = {
|
|
98
|
-
alpha: (45 * Math.PI) / 180,
|
|
99
|
-
beta: (75 * Math.PI) / 180,
|
|
100
|
-
radius: 1,
|
|
101
|
-
target: new Vector3(0, 0, 0),
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
protected static readonly _AUTOFOCUS_CONSTANTS = {
|
|
105
|
-
minZ: 100,
|
|
106
|
-
wheelPrecision: 100,
|
|
107
|
-
panningSensibility: 2500,
|
|
108
|
-
pinchPrecision: 200,
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
protected static readonly _DEFAULT_AUTOFOCUS_RADIUS_FACTOR = 1;
|
|
112
|
-
protected static readonly _DEFAULT_CAM_SPEED_MS = 250;
|
|
113
|
-
protected static readonly _SCREENSHOT_CAMERA_NAME = '__screenshotCamera__';
|
|
114
|
-
|
|
115
|
-
/** @internal */
|
|
116
|
-
public constructor(protected viewer: Viewer) {}
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Focuses the camera to see every visible mesh in scene and tries to optimize wheel precision and panning
|
|
120
|
-
*/
|
|
121
|
-
public async autofocusActiveCamera(settings?: AutofocusSettings): Promise<void> {
|
|
122
|
-
const activeCamera = this.viewer.scene.activeCamera;
|
|
123
|
-
|
|
124
|
-
if (!(activeCamera instanceof ArcRotateCamera)) {
|
|
125
|
-
throw new Error(`Camera type "${activeCamera?.getClassName()}" is not implemented for "autofocusActiveCamera".`);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// get bounding box of all visible meshes, this is the base for the autofocus algorithm
|
|
129
|
-
const boundingInfo = this.viewer.calculateBoundingInfo(settings?.exclude);
|
|
130
|
-
// optionally show bounding sphere for debugging purpose
|
|
131
|
-
this.viewer.eventManager.fireEvent(ViewerEvent.AutofocusStart, boundingInfo.boundingSphere);
|
|
132
|
-
|
|
133
|
-
const distance = this._getAutofocusZoomingDistance(boundingInfo.boundingSphere, activeCamera);
|
|
134
|
-
const radius = boundingInfo.boundingSphere.radius;
|
|
135
|
-
const center = boundingInfo.boundingSphere.center;
|
|
136
|
-
|
|
137
|
-
// set lower radius limit on edge of bounding sphere to make sure that we can't dive into the meshes
|
|
138
|
-
activeCamera.lowerRadiusLimit = radius;
|
|
139
|
-
|
|
140
|
-
// additional settings
|
|
141
|
-
// constants for division are taken directly from Babylon.js repository
|
|
142
|
-
activeCamera.minZ = Math.min(radius / CameraManager._AUTOFOCUS_CONSTANTS.minZ, 1);
|
|
143
|
-
if (settings?.adjustWheelPrecision !== false) {
|
|
144
|
-
activeCamera.wheelPrecision = CameraManager._AUTOFOCUS_CONSTANTS.wheelPrecision / radius;
|
|
145
|
-
}
|
|
146
|
-
if (settings?.adjustPanningSensibility !== false) {
|
|
147
|
-
activeCamera.panningSensibility = CameraManager._AUTOFOCUS_CONSTANTS.panningSensibility / radius;
|
|
148
|
-
}
|
|
149
|
-
if (settings?.adjustPinchPrecision !== false) {
|
|
150
|
-
activeCamera.pinchPrecision = CameraManager._AUTOFOCUS_CONSTANTS.pinchPrecision / radius;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
const radiusFactor = settings?.radiusFactor ?? CameraManager._DEFAULT_AUTOFOCUS_RADIUS_FACTOR;
|
|
154
|
-
const alpha = settings?.alpha ?? CameraManager.DEFAULT_CAMERA_POSITION.alpha;
|
|
155
|
-
const beta = settings?.beta ?? CameraManager.DEFAULT_CAMERA_POSITION.beta;
|
|
156
|
-
|
|
157
|
-
const newCameraPosition: CameraPosition = {
|
|
158
|
-
alpha: alpha,
|
|
159
|
-
beta: beta,
|
|
160
|
-
radius: distance * radiusFactor,
|
|
161
|
-
target: center,
|
|
162
|
-
};
|
|
163
|
-
|
|
164
|
-
await this.moveActiveCameraTo(newCameraPosition, settings?.durationMs);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
/**
|
|
168
|
-
* Moves the active camera smoothly to certain position
|
|
169
|
-
*
|
|
170
|
-
* @param durationMs defaults to 250ms if unset, use 0 for instant movement
|
|
171
|
-
*/
|
|
172
|
-
public async moveActiveCameraTo(
|
|
173
|
-
position: CameraPosition,
|
|
174
|
-
durationMs = CameraManager._DEFAULT_CAM_SPEED_MS
|
|
175
|
-
): Promise<void> {
|
|
176
|
-
const activeCamera = this.viewer.scene.activeCamera;
|
|
177
|
-
|
|
178
|
-
if (!(activeCamera instanceof ArcRotateCamera)) {
|
|
179
|
-
throw new Error(`Camera type "${activeCamera?.getClassName()}" is not implemented yet for "moveActiveCameraTo".`);
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
if (durationMs === 0) {
|
|
183
|
-
// instant movement without animation
|
|
184
|
-
activeCamera.alpha = position.alpha ?? activeCamera.alpha;
|
|
185
|
-
activeCamera.beta = position.beta ?? activeCamera.beta;
|
|
186
|
-
activeCamera.radius = position.radius ?? activeCamera.radius;
|
|
187
|
-
activeCamera.target = position.target ?? activeCamera.target;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
const framesPerSec = 100;
|
|
191
|
-
const animationGroup = new AnimationGroup(CameraManager.CAMERA_ANIMATION_NAME, this.viewer.scene);
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
const
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
if (settings?.
|
|
270
|
-
screenshotCam.
|
|
271
|
-
}
|
|
272
|
-
if (settings?.
|
|
273
|
-
screenshotCam.
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
//
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
settings?.
|
|
305
|
-
settings?.
|
|
306
|
-
settings?.
|
|
307
|
-
settings?.
|
|
308
|
-
settings?.
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
const
|
|
360
|
-
const
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
1
|
+
import {
|
|
2
|
+
Animation,
|
|
3
|
+
AnimationGroup,
|
|
4
|
+
ArcRotateCamera,
|
|
5
|
+
BoundingSphere,
|
|
6
|
+
ExcludedGeometryList,
|
|
7
|
+
IScreenshotSize,
|
|
8
|
+
ScreenshotTools,
|
|
9
|
+
Vector3,
|
|
10
|
+
Viewer,
|
|
11
|
+
ViewerEvent,
|
|
12
|
+
} from '../index';
|
|
13
|
+
import { isNodeExcluded } from '../internal/geometry-helper';
|
|
14
|
+
|
|
15
|
+
export type CameraPosition = {
|
|
16
|
+
alpha: number;
|
|
17
|
+
beta: number;
|
|
18
|
+
radius: number;
|
|
19
|
+
target: Vector3;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export type AutofocusSettings = {
|
|
23
|
+
/** Can be used to customize the margins shown around the 3d model. Defaults to 1. */
|
|
24
|
+
radiusFactor?: number;
|
|
25
|
+
adjustWheelPrecision?: boolean;
|
|
26
|
+
adjustPanningSensibility?: boolean;
|
|
27
|
+
adjustPinchPrecision?: boolean;
|
|
28
|
+
/** Desired horizontal camera angle, this won't be overwritten by the autofocus function */
|
|
29
|
+
alpha?: number;
|
|
30
|
+
/** Desired vertical camera angle, this won't be overwritten by the autofocus function */
|
|
31
|
+
beta?: number;
|
|
32
|
+
/** Optional list of geometry to be excluded from consideration */
|
|
33
|
+
exclude?: ExcludedGeometryList;
|
|
34
|
+
durationMs?: number;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export type ScreenshotSettings = {
|
|
38
|
+
/** Width of the final screenshot image, defaults to canvas width */
|
|
39
|
+
width?: number;
|
|
40
|
+
/** Height of the final screenshot image, defaults to canvas height */
|
|
41
|
+
height?: number;
|
|
42
|
+
/** Camera alpha angle used for the screenshot, defaults to alpha angle of currently active camera */
|
|
43
|
+
alpha?: number;
|
|
44
|
+
/** Camera beta angle used for the screenshot, defaults to beta angle of currently active camera */
|
|
45
|
+
beta?: number;
|
|
46
|
+
/**
|
|
47
|
+
* Camera radius used for the screenshot, default value depends on `autofocusScene` flag:
|
|
48
|
+
* - `true`: radius is calculated automatically so that the whole current scene content is visible
|
|
49
|
+
* - `false`: radius of currently active camera is used
|
|
50
|
+
*/
|
|
51
|
+
radius?: number;
|
|
52
|
+
/**
|
|
53
|
+
* Camera target used for the screenshot, default value depends on `autofocusScene` flag:
|
|
54
|
+
* - `true`: center of the current scene content is set as camera target
|
|
55
|
+
* - `false`: target of currently active camera is used
|
|
56
|
+
*/
|
|
57
|
+
target?: Vector3;
|
|
58
|
+
/** Used to scale the calculated radius if `radius` property is not set and `autofocusScene` mode is active */
|
|
59
|
+
radiusFactor?: number;
|
|
60
|
+
/** Can be used to automatically calculate camera `radius` and `target`, if these 2 settings are not defined
|
|
61
|
+
* explicitely */
|
|
62
|
+
autofocusScene?: boolean;
|
|
63
|
+
/** Optional list of geometry to be excluded from consideration */
|
|
64
|
+
exclude?: ExcludedGeometryList;
|
|
65
|
+
/**
|
|
66
|
+
* "MIME type" of the returned screenshot image, defaults to `image/png`
|
|
67
|
+
*
|
|
68
|
+
* **Info regarding JPEG:** \
|
|
69
|
+
* Use mimeType `image/jpeg` (**not** `image/jpg`) when creating jpeg's. \
|
|
70
|
+
* Also ensure that the viewer scenes `clearColor` has an alpha value of `1` as jpeg's don't
|
|
71
|
+
* support transparency. Otherwise background will always be black for jpeg's.
|
|
72
|
+
*/
|
|
73
|
+
mimeType?: string;
|
|
74
|
+
/** If file name is given, the screenshot image will be downloaded and the base64 string will NOT be returned! */
|
|
75
|
+
fileName?: string;
|
|
76
|
+
/** Expert settings to tweak the screenshot image, see [Babylon.js](https://doc.babylonjs.com/typedoc/functions/BABYLON.CreateScreenshotUsingRenderTarget) docs for further information */
|
|
77
|
+
samples?: number;
|
|
78
|
+
/** Expert settings to tweak the screenshot image, see [Babylon.js](https://doc.babylonjs.com/typedoc/functions/BABYLON.CreateScreenshotUsingRenderTarget) docs for further information */
|
|
79
|
+
antialiasing?: boolean;
|
|
80
|
+
/** Expert settings to tweak the screenshot image, see [Babylon.js](https://doc.babylonjs.com/typedoc/functions/BABYLON.CreateScreenshotUsingRenderTarget) docs for further information */
|
|
81
|
+
renderSprites?: boolean;
|
|
82
|
+
/** Expert settings to tweak the screenshot image, see [Babylon.js](https://doc.babylonjs.com/typedoc/functions/BABYLON.CreateScreenshotUsingRenderTarget) docs for further information */
|
|
83
|
+
enableStencilBuffer?: boolean;
|
|
84
|
+
/** Expert settings to tweak the screenshot image, see [Babylon.js](https://doc.babylonjs.com/typedoc/functions/BABYLON.CreateScreenshotUsingRenderTarget) docs for further information */
|
|
85
|
+
useLayerMask?: boolean;
|
|
86
|
+
/** Expert settings to tweak the screenshot image, see [Babylon.js](https://doc.babylonjs.com/typedoc/functions/BABYLON.CreateScreenshotUsingRenderTarget) docs for further information */
|
|
87
|
+
quality?: number;
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Manager for camera related tasks
|
|
92
|
+
*/
|
|
93
|
+
export class CameraManager {
|
|
94
|
+
public static readonly CAMERA_ANIMATION_NAME = '__cameraAnimation__';
|
|
95
|
+
|
|
96
|
+
/** @internal */
|
|
97
|
+
public static readonly DEFAULT_CAMERA_POSITION: CameraPosition = {
|
|
98
|
+
alpha: (45 * Math.PI) / 180,
|
|
99
|
+
beta: (75 * Math.PI) / 180,
|
|
100
|
+
radius: 1,
|
|
101
|
+
target: new Vector3(0, 0, 0),
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
protected static readonly _AUTOFOCUS_CONSTANTS = {
|
|
105
|
+
minZ: 100,
|
|
106
|
+
wheelPrecision: 100,
|
|
107
|
+
panningSensibility: 2500,
|
|
108
|
+
pinchPrecision: 200,
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
protected static readonly _DEFAULT_AUTOFOCUS_RADIUS_FACTOR = 1;
|
|
112
|
+
protected static readonly _DEFAULT_CAM_SPEED_MS = 250;
|
|
113
|
+
protected static readonly _SCREENSHOT_CAMERA_NAME = '__screenshotCamera__';
|
|
114
|
+
|
|
115
|
+
/** @internal */
|
|
116
|
+
public constructor(protected viewer: Viewer) {}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Focuses the camera to see every visible mesh in scene and tries to optimize wheel precision and panning
|
|
120
|
+
*/
|
|
121
|
+
public async autofocusActiveCamera(settings?: AutofocusSettings): Promise<void> {
|
|
122
|
+
const activeCamera = this.viewer.scene.activeCamera;
|
|
123
|
+
|
|
124
|
+
if (!(activeCamera instanceof ArcRotateCamera)) {
|
|
125
|
+
throw new Error(`Camera type "${activeCamera?.getClassName()}" is not implemented for "autofocusActiveCamera".`);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// get bounding box of all visible meshes, this is the base for the autofocus algorithm
|
|
129
|
+
const boundingInfo = this.viewer.calculateBoundingInfo(settings?.exclude);
|
|
130
|
+
// optionally show bounding sphere for debugging purpose
|
|
131
|
+
this.viewer.eventManager.fireEvent(ViewerEvent.AutofocusStart, boundingInfo.boundingSphere);
|
|
132
|
+
|
|
133
|
+
const distance = this._getAutofocusZoomingDistance(boundingInfo.boundingSphere, activeCamera);
|
|
134
|
+
const radius = boundingInfo.boundingSphere.radius;
|
|
135
|
+
const center = boundingInfo.boundingSphere.center;
|
|
136
|
+
|
|
137
|
+
// set lower radius limit on edge of bounding sphere to make sure that we can't dive into the meshes
|
|
138
|
+
activeCamera.lowerRadiusLimit = radius;
|
|
139
|
+
|
|
140
|
+
// additional settings
|
|
141
|
+
// constants for division are taken directly from Babylon.js repository
|
|
142
|
+
activeCamera.minZ = Math.min(radius / CameraManager._AUTOFOCUS_CONSTANTS.minZ, 1);
|
|
143
|
+
if (settings?.adjustWheelPrecision !== false) {
|
|
144
|
+
activeCamera.wheelPrecision = CameraManager._AUTOFOCUS_CONSTANTS.wheelPrecision / radius;
|
|
145
|
+
}
|
|
146
|
+
if (settings?.adjustPanningSensibility !== false) {
|
|
147
|
+
activeCamera.panningSensibility = CameraManager._AUTOFOCUS_CONSTANTS.panningSensibility / radius;
|
|
148
|
+
}
|
|
149
|
+
if (settings?.adjustPinchPrecision !== false) {
|
|
150
|
+
activeCamera.pinchPrecision = CameraManager._AUTOFOCUS_CONSTANTS.pinchPrecision / radius;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const radiusFactor = settings?.radiusFactor ?? CameraManager._DEFAULT_AUTOFOCUS_RADIUS_FACTOR;
|
|
154
|
+
const alpha = settings?.alpha ?? CameraManager.DEFAULT_CAMERA_POSITION.alpha;
|
|
155
|
+
const beta = settings?.beta ?? CameraManager.DEFAULT_CAMERA_POSITION.beta;
|
|
156
|
+
|
|
157
|
+
const newCameraPosition: CameraPosition = {
|
|
158
|
+
alpha: alpha,
|
|
159
|
+
beta: beta,
|
|
160
|
+
radius: distance * radiusFactor,
|
|
161
|
+
target: center,
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
await this.moveActiveCameraTo(newCameraPosition, settings?.durationMs);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Moves the active camera smoothly to certain position
|
|
169
|
+
*
|
|
170
|
+
* @param durationMs defaults to 250ms if unset, use 0 for instant movement
|
|
171
|
+
*/
|
|
172
|
+
public async moveActiveCameraTo(
|
|
173
|
+
position: CameraPosition,
|
|
174
|
+
durationMs = CameraManager._DEFAULT_CAM_SPEED_MS
|
|
175
|
+
): Promise<void> {
|
|
176
|
+
const activeCamera = this.viewer.scene.activeCamera;
|
|
177
|
+
|
|
178
|
+
if (!(activeCamera instanceof ArcRotateCamera)) {
|
|
179
|
+
throw new Error(`Camera type "${activeCamera?.getClassName()}" is not implemented yet for "moveActiveCameraTo".`);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (durationMs === 0) {
|
|
183
|
+
// instant movement without animation
|
|
184
|
+
activeCamera.alpha = position.alpha ?? activeCamera.alpha;
|
|
185
|
+
activeCamera.beta = position.beta ?? activeCamera.beta;
|
|
186
|
+
activeCamera.radius = position.radius ?? activeCamera.radius;
|
|
187
|
+
activeCamera.target = position.target ?? activeCamera.target;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const framesPerSec = 100;
|
|
191
|
+
const animationGroup = new AnimationGroup(CameraManager.CAMERA_ANIMATION_NAME, this.viewer.scene);
|
|
192
|
+
|
|
193
|
+
// it's important to start with the target, as it internally overwrites alpha, beta and radius
|
|
194
|
+
// these values can then be overwritten afterwards if provided on the input of this function
|
|
195
|
+
// for further details see CB-10015
|
|
196
|
+
if (position.target !== undefined) {
|
|
197
|
+
CameraManager._addCameraAnimationToGroup(
|
|
198
|
+
'target',
|
|
199
|
+
activeCamera.target,
|
|
200
|
+
position.target,
|
|
201
|
+
framesPerSec,
|
|
202
|
+
Animation.ANIMATIONTYPE_VECTOR3,
|
|
203
|
+
animationGroup,
|
|
204
|
+
activeCamera
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
if (position.alpha !== undefined) {
|
|
208
|
+
// transform the target's alpha value into the same turn as the current camera position to avoid movements
|
|
209
|
+
// > 360 degrees
|
|
210
|
+
const alphaGap = activeCamera.alpha - position.alpha;
|
|
211
|
+
const cntTurns = Math.round(alphaGap / (2 * Math.PI));
|
|
212
|
+
const targetAlpha = position.alpha + 2 * Math.PI * cntTurns;
|
|
213
|
+
|
|
214
|
+
CameraManager._addCameraAnimationToGroup(
|
|
215
|
+
'alpha',
|
|
216
|
+
activeCamera.alpha,
|
|
217
|
+
targetAlpha,
|
|
218
|
+
framesPerSec,
|
|
219
|
+
Animation.ANIMATIONTYPE_FLOAT,
|
|
220
|
+
animationGroup,
|
|
221
|
+
activeCamera
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
if (position.beta !== undefined) {
|
|
225
|
+
CameraManager._addCameraAnimationToGroup(
|
|
226
|
+
'beta',
|
|
227
|
+
activeCamera.beta,
|
|
228
|
+
position.beta,
|
|
229
|
+
framesPerSec,
|
|
230
|
+
Animation.ANIMATIONTYPE_FLOAT,
|
|
231
|
+
animationGroup,
|
|
232
|
+
activeCamera
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
if (position.radius !== undefined) {
|
|
236
|
+
CameraManager._addCameraAnimationToGroup(
|
|
237
|
+
'radius',
|
|
238
|
+
activeCamera.radius,
|
|
239
|
+
position.radius,
|
|
240
|
+
framesPerSec,
|
|
241
|
+
Animation.ANIMATIONTYPE_FLOAT,
|
|
242
|
+
animationGroup,
|
|
243
|
+
activeCamera
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// animation is created for 1 second (100 frames), adjust speed ratio according to desired movement time
|
|
248
|
+
const speedRatio = 1000 / durationMs;
|
|
249
|
+
|
|
250
|
+
return new Promise<void>(resolve => {
|
|
251
|
+
animationGroup.onAnimationGroupEndObservable.addOnce(() => {
|
|
252
|
+
animationGroup.dispose();
|
|
253
|
+
resolve();
|
|
254
|
+
});
|
|
255
|
+
animationGroup.start(false, speedRatio, 0, 100);
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Takes a sceenshot the the current scene.\
|
|
261
|
+
* The result is a string containing a base64 encoded image.
|
|
262
|
+
*/
|
|
263
|
+
public async createScreenshot(settings?: ScreenshotSettings): Promise<string> {
|
|
264
|
+
const screenshotCam = this.viewer.scene.activeCamera?.clone(
|
|
265
|
+
CameraManager._SCREENSHOT_CAMERA_NAME
|
|
266
|
+
) as ArcRotateCamera;
|
|
267
|
+
const boundingInfo = settings?.autofocusScene ? this.viewer.calculateBoundingInfo(settings.exclude) : undefined;
|
|
268
|
+
|
|
269
|
+
if (settings?.alpha !== undefined) {
|
|
270
|
+
screenshotCam.alpha = settings.alpha;
|
|
271
|
+
}
|
|
272
|
+
if (settings?.beta !== undefined) {
|
|
273
|
+
screenshotCam.beta = settings.beta;
|
|
274
|
+
}
|
|
275
|
+
if (settings?.radius !== undefined) {
|
|
276
|
+
screenshotCam.radius = settings.radius;
|
|
277
|
+
} else if (boundingInfo) {
|
|
278
|
+
// zoom out to have full scene in view if requested by `autofocusScene` flag
|
|
279
|
+
const distance = this._getAutofocusZoomingDistance(boundingInfo.boundingSphere, screenshotCam);
|
|
280
|
+
const radiusFactor = settings?.radiusFactor ?? 1;
|
|
281
|
+
screenshotCam.radius = distance * radiusFactor;
|
|
282
|
+
}
|
|
283
|
+
// `cloneAlphaBetaRadius` has to be set to true, otherwise these values get adapted by setting the new target
|
|
284
|
+
// this would also be the case when setting `screenshotCam.target` directly
|
|
285
|
+
if (settings?.target !== undefined) {
|
|
286
|
+
screenshotCam.setTarget(settings.target, undefined, undefined, true);
|
|
287
|
+
} else if (boundingInfo) {
|
|
288
|
+
screenshotCam.setTarget(boundingInfo.boundingSphere.center, undefined, undefined, true);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// don't expose internal props of `IScreenshotSize` in the API (yet), as it gets rather confusing and it shouldn't
|
|
292
|
+
// be necessary in the first place
|
|
293
|
+
// also let Babylon.js do all the fallback handling for missing properties
|
|
294
|
+
const size: IScreenshotSize = { width: settings?.width, height: settings?.height };
|
|
295
|
+
|
|
296
|
+
// for some reason the `customizeTexture` property is not exposed in the async version of this function, therefore
|
|
297
|
+
// we create the promise here manually
|
|
298
|
+
const imageStr = await new Promise<string>(resolve => {
|
|
299
|
+
ScreenshotTools.CreateScreenshotUsingRenderTarget(
|
|
300
|
+
this.viewer.engine,
|
|
301
|
+
screenshotCam,
|
|
302
|
+
size,
|
|
303
|
+
(data: string) => resolve(data),
|
|
304
|
+
settings?.mimeType,
|
|
305
|
+
settings?.samples,
|
|
306
|
+
settings?.antialiasing,
|
|
307
|
+
settings?.fileName,
|
|
308
|
+
settings?.renderSprites,
|
|
309
|
+
settings?.enableStencilBuffer,
|
|
310
|
+
settings?.useLayerMask,
|
|
311
|
+
settings?.quality,
|
|
312
|
+
texture => {
|
|
313
|
+
texture.renderList = this.viewer.scene.meshes.filter(
|
|
314
|
+
mesh => !settings?.exclude || !isNodeExcluded(mesh, settings.exclude)
|
|
315
|
+
);
|
|
316
|
+
}
|
|
317
|
+
);
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
screenshotCam.dispose();
|
|
321
|
+
|
|
322
|
+
return imageStr;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
protected static _addCameraAnimationToGroup(
|
|
326
|
+
targetProperty: string,
|
|
327
|
+
from: number | Vector3,
|
|
328
|
+
to: number | Vector3,
|
|
329
|
+
framesPerSec: number,
|
|
330
|
+
dataType: number,
|
|
331
|
+
animationGroup: AnimationGroup,
|
|
332
|
+
activeCamera: ArcRotateCamera
|
|
333
|
+
): void {
|
|
334
|
+
const alphaAnimation = new Animation(
|
|
335
|
+
targetProperty,
|
|
336
|
+
targetProperty,
|
|
337
|
+
framesPerSec,
|
|
338
|
+
dataType,
|
|
339
|
+
Animation.ANIMATIONLOOPMODE_CONSTANT
|
|
340
|
+
);
|
|
341
|
+
alphaAnimation.setKeys([
|
|
342
|
+
{
|
|
343
|
+
frame: 0,
|
|
344
|
+
value: from,
|
|
345
|
+
},
|
|
346
|
+
{
|
|
347
|
+
frame: 100,
|
|
348
|
+
value: to,
|
|
349
|
+
},
|
|
350
|
+
]);
|
|
351
|
+
animationGroup.addTargetedAnimation(alphaAnimation, activeCamera);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
protected _getAutofocusZoomingDistance(boundingSphere: BoundingSphere, camera: ArcRotateCamera): number {
|
|
355
|
+
// calculation is taken from Babylon.js repository, which on their side took it from this SO post:
|
|
356
|
+
// http://stackoverflow.com/questions/2866350/move-camera-to-fit-3d-scene
|
|
357
|
+
// there's a good sketch which explains the calculation quite a bit
|
|
358
|
+
const aspectRatio = this.viewer.engine.getAspectRatio(camera);
|
|
359
|
+
const frustumSlopeY = Math.tan(camera.fov / 2);
|
|
360
|
+
const frustumSlopeX = frustumSlopeY * aspectRatio;
|
|
361
|
+
|
|
362
|
+
const distanceForHorizontalFrustum = boundingSphere.radius * Math.sqrt(1 + 1 / (frustumSlopeX * frustumSlopeX));
|
|
363
|
+
const distanceForVerticalFrustum = boundingSphere.radius * Math.sqrt(1 + 1 / (frustumSlopeY * frustumSlopeY));
|
|
364
|
+
const distance = Math.max(distanceForHorizontalFrustum, distanceForVerticalFrustum);
|
|
365
|
+
|
|
366
|
+
return distance;
|
|
367
|
+
}
|
|
368
|
+
}
|