@combeenation/3d-viewer 17.1.0 → 18.0.0-beta1

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.
Files changed (45) hide show
  1. package/dist/lib-cjs/buildinfo.json +1 -1
  2. package/dist/lib-cjs/commonjs.tsconfig.tsbuildinfo +1 -1
  3. package/dist/lib-cjs/index.d.ts +2 -0
  4. package/dist/lib-cjs/index.js +2 -0
  5. package/dist/lib-cjs/index.js.map +1 -1
  6. package/dist/lib-cjs/internal/asset-helper.d.ts +32 -0
  7. package/dist/lib-cjs/internal/asset-helper.js +105 -0
  8. package/dist/lib-cjs/internal/asset-helper.js.map +1 -0
  9. package/dist/lib-cjs/internal/cbn-custom-babylon-loader-plugin.d.ts +18 -0
  10. package/dist/lib-cjs/internal/cbn-custom-babylon-loader-plugin.js +22 -3
  11. package/dist/lib-cjs/internal/cbn-custom-babylon-loader-plugin.js.map +1 -1
  12. package/dist/lib-cjs/internal/texture-parameter-helper.js +26 -7
  13. package/dist/lib-cjs/internal/texture-parameter-helper.js.map +1 -1
  14. package/dist/lib-cjs/manager/camera-manager.js +4 -2
  15. package/dist/lib-cjs/manager/camera-manager.js.map +1 -1
  16. package/dist/lib-cjs/manager/debug-manager.js +1 -1
  17. package/dist/lib-cjs/manager/debug-manager.js.map +1 -1
  18. package/dist/lib-cjs/manager/model-manager.d.ts +11 -33
  19. package/dist/lib-cjs/manager/model-manager.js +47 -106
  20. package/dist/lib-cjs/manager/model-manager.js.map +1 -1
  21. package/dist/lib-cjs/manager/parameter-manager.d.ts +16 -11
  22. package/dist/lib-cjs/manager/parameter-manager.js +78 -69
  23. package/dist/lib-cjs/manager/parameter-manager.js.map +1 -1
  24. package/dist/lib-cjs/manager/scene-manager.d.ts +111 -5
  25. package/dist/lib-cjs/manager/scene-manager.js +269 -10
  26. package/dist/lib-cjs/manager/scene-manager.js.map +1 -1
  27. package/dist/lib-cjs/viewer-error.d.ts +1 -0
  28. package/dist/lib-cjs/viewer-error.js +1 -0
  29. package/dist/lib-cjs/viewer-error.js.map +1 -1
  30. package/dist/lib-cjs/viewer.d.ts +4 -13
  31. package/dist/lib-cjs/viewer.js +3 -37
  32. package/dist/lib-cjs/viewer.js.map +1 -1
  33. package/package.json +21 -12
  34. package/src/index.ts +2 -0
  35. package/src/internal/asset-helper.ts +115 -0
  36. package/src/internal/cbn-custom-babylon-loader-plugin.ts +30 -3
  37. package/src/internal/texture-parameter-helper.ts +25 -8
  38. package/src/manager/camera-manager.ts +4 -2
  39. package/src/manager/debug-manager.ts +1 -1
  40. package/src/manager/model-manager.ts +55 -137
  41. package/src/manager/parameter-manager.ts +93 -74
  42. package/src/manager/scene-manager.ts +366 -10
  43. package/src/viewer-error.ts +1 -0
  44. package/src/viewer.ts +13 -55
  45. package/src/dev.ts +0 -47
@@ -1,4 +1,22 @@
1
- import { ArcRotateCamera, CameraManager, Color4, CubeTexture, Vector3, Viewer } from '../index';
1
+ import {
2
+ AbstractMesh,
3
+ ArcRotateCamera,
4
+ AssetContainer,
5
+ BackgroundMaterial,
6
+ BoundingInfo,
7
+ CameraManager,
8
+ Color4,
9
+ CubeTexture,
10
+ ExcludedGeometryList,
11
+ IShadowGenerator,
12
+ TransformNode,
13
+ Vector3,
14
+ Viewer,
15
+ ViewerError,
16
+ ViewerErrorIds,
17
+ } from '../index';
18
+ import { BaseAsset, loadAsset, prepareAssetForScene } from '../internal/asset-helper';
19
+ import { isNodeExcluded } from '../internal/geometry-helper';
2
20
  import { merge } from 'lodash-es';
3
21
 
4
22
  /**
@@ -28,15 +46,68 @@ export type DefaultSceneSettings = {
28
46
  };
29
47
  };
30
48
 
49
+ export type SceneAssetDefinition = {
50
+ name: string;
51
+ url: string;
52
+ };
53
+
54
+ export type UpdateGroundSettings = {
55
+ /**
56
+ * Ground mesh, which will be rescaled and repositioned.\
57
+ * Searches for mesh with name "BackgroundPlane" if left `undefined`
58
+ */
59
+ groundMesh?: TransformNode;
60
+ /**
61
+ * Additional scaling factor for ground size, default is 5, which equals 5 times the bounding sphere diameter of the
62
+ * current scene
63
+ */
64
+ factor?: number;
65
+ /**
66
+ * Optional list of geometry to be excluded from scene size calculation
67
+ */
68
+ excludeGeometry?: ExcludedGeometryList;
69
+ };
70
+
71
+ export type UpdateShadowsSettings = {
72
+ /**
73
+ * Shadow generator, which should be updated.\
74
+ * All shadow generators will be updated, if value is left `undefined`.
75
+ */
76
+ shadowGenerators?: IShadowGenerator[];
77
+ /**
78
+ * Optional list of geometry which should not be defined as shadow caster
79
+ */
80
+ excludeCaster?: ExcludedGeometryList;
81
+ /**
82
+ * Optional list of geometry which should not be defined as shadow receiver
83
+ */
84
+ excludeReceiver?: ExcludedGeometryList;
85
+ };
86
+
31
87
  /**
32
- * Manager for tasks related to the Babylon.js scene.\
33
- * This contains creating or loading (WIP: Scene Asset) scenes with certain settings for lighting, cameras and
34
- * appearance in genereal.
88
+ * Additional scene settings, which are not available in a basic `AssetContainer`.
89
+ * !!! IMPORTANT when adding a new property !!!
90
+ * Add property in implementation of `cbnCustomBabylonLoader` as well
35
91
  *
36
92
  * @internal
37
93
  */
94
+ export type SceneAssetSettings = {
95
+ clearColor?: Color4;
96
+ environmentIntensity?: number;
97
+ };
98
+
99
+ type SceneAsset = BaseAsset & {
100
+ settings: SceneAssetSettings;
101
+ };
102
+
103
+ /**
104
+ * Manager for tasks related to the Babylon.js scene.\
105
+ * This contains creating or loading scenes with certain settings for lighting, cameras and appearance in genereal.
106
+ */
38
107
  export class SceneManager {
39
- protected static _DEFAULT_SCENE_NAME = '__defaultScene__';
108
+ protected static _DEFAULT_SCENE_ASSET_NAME = '$default';
109
+ protected static _DEFAULT_GROUND_PLANE_NAME = 'BackgroundPlane';
110
+ protected static _DEFAULT_GROUND_SIZING_FACTOR = 5;
40
111
 
41
112
  // default scene settings
42
113
  // will be overwritten in the constructor
@@ -60,42 +131,327 @@ export class SceneManager {
60
131
  },
61
132
  };
62
133
 
134
+ protected _sceneAssets: { [name: string]: SceneAsset } = {};
135
+ protected _defaultSceneAsset: SceneAsset = {
136
+ name: SceneManager._DEFAULT_SCENE_ASSET_NAME,
137
+ url: '',
138
+ state: 'loaded',
139
+ assetContainer: new AssetContainer(),
140
+ settings: {},
141
+ };
142
+ protected _activeSceneAssetName: string = '';
143
+ protected _loadSceneAssetPromises: { [sceneAssetName: string]: Promise<void> } = {};
144
+ protected _setSceneAssetCallId = 0;
145
+
146
+ /** @internal */
63
147
  public constructor(protected viewer: Viewer, defaultSceneSettings?: DeepPartial<DefaultSceneSettings>) {
64
148
  merge(this._defaultSceneSettings, defaultSceneSettings);
65
149
  }
66
150
 
151
+ /**
152
+ * Register scene assets for 3d viewer, this is required for each scene asset before it can be loaded/shown.\
153
+ * The "viewer control" inside the Combeenation framework calls this function automatically with all assigned
154
+ * scene assets.
155
+ */
156
+ public registerSceneAssets(sceneAssets: SceneAssetDefinition[]): void {
157
+ for (const { name, url } of sceneAssets) {
158
+ const existingSceneAsset = this._sceneAssets[name];
159
+ if (existingSceneAsset) {
160
+ console.warn(`Scene asset "${name}" is already registered`);
161
+ return;
162
+ }
163
+
164
+ const sceneAsset: SceneAsset = {
165
+ name,
166
+ url,
167
+ state: 'notLoaded',
168
+ assetContainer: new AssetContainer(),
169
+ settings: {},
170
+ };
171
+ this._sceneAssets[name] = sceneAsset;
172
+ }
173
+ }
174
+
175
+ /**
176
+ * Set desired scene asset as active and loads the content of the associated asset container (e.g. ground mesh).\
177
+ * This also deactivates the currently active scene asset, as only one scene asset can be active at a time.
178
+ */
179
+ public async setSceneAsset(name: string, skipPreparation?: boolean): Promise<void> {
180
+ const sceneAsset = this._getSceneAsset(name);
181
+ if (!sceneAsset) {
182
+ throw new ViewerError({
183
+ id: ViewerErrorIds.SceneAssetNotRegistered,
184
+ message: `Can't set scene asset "${name}" as scene asset is not registered`,
185
+ });
186
+ }
187
+
188
+ this._setSceneAssetCallId++;
189
+ const curSetSceneAssetCallId = this._setSceneAssetCallId;
190
+
191
+ if (sceneAsset.state === 'notLoaded') {
192
+ await this._loadSceneAsset(sceneAsset);
193
+ } else if (sceneAsset.state === 'loading') {
194
+ await this._loadSceneAssetPromises[name];
195
+ } else if (sceneAsset.state === 'inScene') {
196
+ console.warn(`Scene asset ${name} is already active`);
197
+ return;
198
+ }
199
+
200
+ // a new `setSceneAsset` call has been fired
201
+ if (curSetSceneAssetCallId !== this._setSceneAssetCallId) {
202
+ return;
203
+ }
204
+
205
+ if (!skipPreparation) {
206
+ await prepareAssetForScene(sceneAsset, this.viewer);
207
+ }
208
+
209
+ sceneAsset.assetContainer.addToScene();
210
+ const firstCam = sceneAsset.assetContainer.cameras[0];
211
+ if (firstCam) {
212
+ this.viewer.scene.activeCamera = firstCam;
213
+ this.viewer.scene.activeCamera.attachControl(undefined, true);
214
+ }
215
+
216
+ if (sceneAsset.assetContainer.environmentTexture) {
217
+ this.viewer.scene.environmentTexture = sceneAsset.assetContainer.environmentTexture;
218
+ }
219
+ if (sceneAsset.settings.clearColor) {
220
+ this.viewer.scene.clearColor = sceneAsset.settings.clearColor;
221
+ }
222
+ if (sceneAsset.settings.environmentIntensity !== undefined) {
223
+ this.viewer.scene.environmentIntensity = sceneAsset.settings.environmentIntensity;
224
+ }
225
+
226
+ sceneAsset.state = 'inScene';
227
+
228
+ // now hide old scene asset
229
+ // it's important that this is done after setting the new one to active, as there might be a render cycle with no
230
+ // cameras instead
231
+ const activeSceneAsset = this._getSceneAsset(this._activeSceneAssetName);
232
+ if (activeSceneAsset) {
233
+ this._hideSceneAsset(activeSceneAsset);
234
+ }
235
+
236
+ // finally set new scene asset as active
237
+ this._activeSceneAssetName = name;
238
+ }
239
+
240
+ /**
241
+ * Activate default scene asset
242
+ */
243
+ public setDefaultSceneAsset(): void {
244
+ // NOTE: this function is not async because:
245
+ // - `setDefaultSceneAsset` is part of the viewers "bootstrapping" process which is synchronous
246
+ // - default scene asset only adjusts some setting but doesn't load anything
247
+ this.setSceneAsset(SceneManager._DEFAULT_SCENE_ASSET_NAME, true);
248
+ }
249
+
250
+ /**
251
+ * Loads and returns the asset container of a certain scene asset.\
252
+ * This can be used to access the scene asset content without having to add it to the scene.
253
+ */
254
+ public async getAssetContainerOfSceneAsset(name: string): Promise<AssetContainer> {
255
+ const sceneAsset = this._getSceneAsset(name);
256
+ if (!sceneAsset) {
257
+ throw new ViewerError({
258
+ id: ViewerErrorIds.SceneAssetNotRegistered,
259
+ message: `Can't get asset container of scene asset "${name}" as scene asset is not registered`,
260
+ });
261
+ }
262
+
263
+ if (sceneAsset.state === 'notLoaded') {
264
+ await this._loadSceneAsset(sceneAsset);
265
+ } else if (sceneAsset.state === 'loading') {
266
+ await this._loadSceneAssetPromises[sceneAsset.name];
267
+ }
268
+
269
+ if (sceneAsset.state !== 'inScene') {
270
+ await prepareAssetForScene(sceneAsset, this.viewer);
271
+ }
272
+
273
+ return sceneAsset.assetContainer;
274
+ }
275
+
276
+ /**
277
+ * Calculates size of the current scene.\
278
+ * Only takes meshes into considerations that:
279
+ * - are visible
280
+ * - are not excluded by "excludeGeometry" parameter
281
+ * - do not have a material of type "BackgroundMaterial"
282
+ * - do not have an infinite distance (like sky boxes)
283
+ */
284
+ public calculateBoundingInfo(excludeGeometry?: ExcludedGeometryList): BoundingInfo {
285
+ // CB-6062: workaround for BoundingBox not respecting render loop
286
+ this.viewer.scene.render();
287
+
288
+ const { max, min } = this.viewer.scene.meshes
289
+ .filter(mesh => {
290
+ const isEnabled = mesh.isEnabled();
291
+ // ignore meshes with invalid bounding infos
292
+ const hasValidBBoxInfo = mesh.getBoundingInfo().boundingSphere.radius > 0;
293
+ // ignore meshes with infinite distance, typically these are sky boxes
294
+ const hasInfiniteDistance = mesh.infiniteDistance;
295
+ // ignore meshes with "BackgroundMaterial" - usually a ground or skybox
296
+ const hasBackgroundMaterial = mesh.material instanceof BackgroundMaterial;
297
+ // ignore excluded meshes
298
+ const isExcluded = excludeGeometry ? isNodeExcluded(mesh, excludeGeometry) : false;
299
+
300
+ return isEnabled && hasValidBBoxInfo && !hasInfiniteDistance && !hasBackgroundMaterial && !isExcluded;
301
+ })
302
+ .reduce(
303
+ (accBBoxMinMax, curMesh, idx) => {
304
+ curMesh.refreshBoundingInfo(true, true);
305
+ const bBox = curMesh.getBoundingInfo().boundingBox;
306
+ // use the first entry in the array as default value and get the resulting maximum/minimum values
307
+ const max = idx === 0 ? bBox.maximumWorld : Vector3.Maximize(accBBoxMinMax.max, bBox.maximumWorld);
308
+ const min = idx === 0 ? bBox.minimumWorld : Vector3.Minimize(accBBoxMinMax.min, bBox.minimumWorld);
309
+ return { max, min };
310
+ },
311
+ { max: new Vector3(), min: new Vector3() }
312
+ );
313
+
314
+ const boundingInfo = new BoundingInfo(min, max);
315
+ return boundingInfo;
316
+ }
317
+
318
+ /**
319
+ * Adjusts position and scaling of a dedicated "ground" meshes according to the bounding sphere of the current scene
320
+ * content.\
321
+ * This function is designed to adjust the ground that is created via `scene.createDefaultEnvironment`, but any other
322
+ * plane mesh can be used as well.
323
+ */
324
+ public updateGround(settings?: UpdateGroundSettings): void {
325
+ const bboxInfo = this.calculateBoundingInfo(settings?.excludeGeometry);
326
+
327
+ const groundMesh = settings?.groundMesh ?? this.viewer.scene.getMeshByName(SceneManager._DEFAULT_GROUND_PLANE_NAME);
328
+ if (!groundMesh) {
329
+ console.warn("Can't update ground, as no ground mesh is available");
330
+ return;
331
+ }
332
+
333
+ // 2: conversion from radius to diameter
334
+ const factor =
335
+ bboxInfo.boundingSphere.radius * 2 * (settings?.factor ?? SceneManager._DEFAULT_GROUND_SIZING_FACTOR);
336
+ const position = bboxInfo.boundingSphere.centerWorld;
337
+ groundMesh.scaling = new Vector3(factor, factor, 1);
338
+ groundMesh.position = new Vector3(position.x, 0, position.z);
339
+ }
340
+
341
+ /**
342
+ * Assigns available meshes in scene as shadow receiver and shadow casters of dedicated shadow generators, as defined
343
+ * in settings
344
+ */
345
+ public updateShadows(settings?: UpdateShadowsSettings): void {
346
+ const shadowGenerators =
347
+ settings?.shadowGenerators ??
348
+ (this.viewer.scene.lights.map(light => light.getShadowGenerator()).filter(Boolean) as IShadowGenerator[]);
349
+
350
+ const shadowCasterMeshes: AbstractMesh[] = [];
351
+ this.viewer.scene.meshes.forEach(mesh => {
352
+ const isShadowReceiver = settings?.excludeReceiver ? !isNodeExcluded(mesh, settings.excludeReceiver) : true;
353
+ if (isShadowReceiver) {
354
+ mesh.receiveShadows = true;
355
+ }
356
+
357
+ // excluding background meshes like ground or walls from shadow casters is benefitial to reduce the size of the
358
+ // poisson filters auto shadow plane calculation, which will result in better shadow resolution
359
+ const hasBackgroundMaterial = mesh.material instanceof BackgroundMaterial;
360
+ const isShadowCaster = settings?.excludeCaster ? !isNodeExcluded(mesh, settings.excludeCaster) : true;
361
+ if (isShadowCaster && !hasBackgroundMaterial) {
362
+ shadowCasterMeshes.push(mesh);
363
+ }
364
+ });
365
+
366
+ shadowGenerators.forEach(shadowGen => {
367
+ const shadowMap = shadowGen.getShadowMap();
368
+ if (!shadowMap) {
369
+ return;
370
+ }
371
+
372
+ shadowMap.renderList = [...shadowCasterMeshes];
373
+ shadowGen.recreateShadowMap();
374
+ });
375
+ }
376
+
67
377
  /**
68
378
  * Creates a camera and minimum lighting, so that the scene is set up good enough to show content.\
69
379
  * Settings can be overwritten in the constructor.
380
+ *
381
+ * @internal
70
382
  */
71
383
  public applyDefaultSettingsToScene(): void {
72
384
  const cameraSettings = this._defaultSceneSettings.camera;
73
385
  const envSettings = this._defaultSceneSettings.environment;
74
386
 
75
- this.viewer.scene.clearColor = this._defaultSceneSettings.backgroundColor;
387
+ // NOTE: default scene asset doesn't load anything, in this way the viewers "bootstrapping" process can remain
388
+ // synchronous
389
+ this._defaultSceneAsset = {
390
+ name: SceneManager._DEFAULT_SCENE_ASSET_NAME,
391
+ url: '',
392
+ state: 'loaded',
393
+ assetContainer: new AssetContainer(),
394
+ settings: {},
395
+ };
396
+
397
+ this._defaultSceneAsset.settings.clearColor = this._defaultSceneSettings.backgroundColor;
76
398
 
77
399
  // camera
78
400
  if (cameraSettings.create) {
79
401
  const camera = new ArcRotateCamera(
80
- `${SceneManager._DEFAULT_SCENE_NAME}.camera`,
402
+ `${SceneManager._DEFAULT_SCENE_ASSET_NAME}.camera`,
81
403
  cameraSettings.initialPosition.alpha,
82
404
  cameraSettings.initialPosition.beta,
83
405
  cameraSettings.initialPosition.radius,
84
406
  cameraSettings.initialPosition.target,
85
407
  this.viewer.scene
86
408
  );
87
- camera.attachControl(this.viewer.engine._workingCanvas, true);
88
409
  camera.minZ = cameraSettings.settings.minZ;
89
410
  camera.lowerRadiusLimit = cameraSettings.settings.lowerRadiusLimit;
90
411
  camera.wheelPrecision = cameraSettings.settings.wheelPrecision;
91
412
  camera.panningSensibility = cameraSettings.settings.panningSensibility;
413
+ camera.attachControl(undefined, true);
414
+
415
+ this._defaultSceneAsset.assetContainer.cameras.push(camera);
416
+ this.viewer.scene.removeCamera(camera);
92
417
  }
93
418
 
94
419
  // environment
95
420
  if (envSettings.create) {
96
421
  const envTexture = CubeTexture.CreateFromPrefilteredData(envSettings.url, this.viewer.scene);
97
- this.viewer.scene.environmentTexture = envTexture;
98
- this.viewer.scene.environmentIntensity = envSettings.intensity;
422
+
423
+ this._defaultSceneAsset.assetContainer.environmentTexture = envTexture;
424
+ this._defaultSceneAsset.settings.environmentIntensity = envSettings.intensity;
99
425
  }
426
+
427
+ this.setDefaultSceneAsset();
428
+ }
429
+
430
+ protected _getSceneAsset(name: string): SceneAsset | undefined {
431
+ if (name === SceneManager._DEFAULT_SCENE_ASSET_NAME) {
432
+ return this._defaultSceneAsset;
433
+ }
434
+
435
+ const sceneAsset = this._sceneAssets[name];
436
+ return sceneAsset;
437
+ }
438
+
439
+ protected async _loadSceneAsset(sceneAsset: SceneAsset): Promise<void> {
440
+ const loadSceneAssetPromise = async (): Promise<void> => {
441
+ const { sceneSettingsData } = await loadAsset(sceneAsset, this.viewer);
442
+
443
+ sceneAsset.settings = sceneSettingsData ?? {};
444
+
445
+ delete this._loadSceneAssetPromises[sceneAsset.name];
446
+ };
447
+
448
+ this._loadSceneAssetPromises[sceneAsset.name] = loadSceneAssetPromise();
449
+ return this._loadSceneAssetPromises[sceneAsset.name];
450
+ }
451
+
452
+ protected _hideSceneAsset(sceneAsset: SceneAsset): void {
453
+ sceneAsset.assetContainer.cameras.forEach(camera => camera.detachControl());
454
+ sceneAsset.assetContainer.removeFromScene();
455
+ sceneAsset.state = 'loaded';
100
456
  }
101
457
  }
@@ -25,6 +25,7 @@ export const ViewerErrorIds = {
25
25
  ModelNotRegistered: 'ModelNotRegistered',
26
26
  ModelAlreadyExists: 'ModelAlreadyExists',
27
27
  ModelIsNotAClone: 'ModelIsNotAClone',
28
+ SceneAssetNotRegistered: 'SceneAssetNotRegistered',
28
29
  AssetLoadingFailed: 'AssetLoadingFailed',
29
30
  MaterialAlreadyExists: 'MaterialAlreadyExists',
30
31
  NotAClonedMaterial: 'NotAClonedMaterial',
package/src/viewer.ts CHANGED
@@ -1,8 +1,7 @@
1
1
  import buildInfo from './buildinfo.json';
2
2
  import * as Index from './index';
3
3
  import {
4
- BackgroundMaterial,
5
- BoundingInfo,
4
+ AbstractEngine,
6
5
  CameraManager,
7
6
  DebugManager,
8
7
  DefaultSceneSettings,
@@ -12,17 +11,16 @@ import {
12
11
  GltfExportManager,
13
12
  MaterialManager,
14
13
  ModelManager,
14
+ NullEngine,
15
15
  ParameterManager,
16
16
  ParameterSubject,
17
17
  Scene,
18
18
  SceneManager,
19
19
  TextureManager,
20
20
  TransformNode,
21
- Vector3,
22
21
  } from './index';
23
22
  import { registerCustomCbnBabylonLoaderPlugin } from './internal/cbn-custom-babylon-loader-plugin';
24
23
  import { getIsScaledDownDevice } from './internal/device-helper';
25
- import { isNodeExcluded } from './internal/geometry-helper';
26
24
  import { cloneDeep, merge } from 'lodash-es';
27
25
 
28
26
  /**
@@ -112,8 +110,8 @@ export class Viewer {
112
110
  get scene(): Scene {
113
111
  return this._scene;
114
112
  }
115
- get engine(): Engine {
116
- return this.scene.getEngine() as Engine;
113
+ get engine(): AbstractEngine {
114
+ return this.scene.getEngine();
117
115
  }
118
116
  get cameraManager(): CameraManager {
119
117
  return this._cameraManager;
@@ -164,7 +162,7 @@ export class Viewer {
164
162
  * This scene contains a camera and an environment per default.
165
163
  */
166
164
  public constructor(
167
- public readonly canvas: HTMLCanvasElement,
165
+ public readonly canvas?: HTMLCanvasElement,
168
166
  viewerSettings?: DeepPartial<ViewerSettings>,
169
167
  defaultSceneSettings?: DeepPartial<DefaultSceneSettings>
170
168
  ) {
@@ -195,48 +193,6 @@ export class Viewer {
195
193
  this.engine.dispose();
196
194
  }
197
195
 
198
- /**
199
- * Calculates size of the current scene.\
200
- * Only takes meshes into considerations that:
201
- * - are visible
202
- * - are not excluded by "excludeGeometry" parameter
203
- * - do not have a material of type "BackgroundMaterial"
204
- * - do not have an infinite distance (like sky boxes)
205
- */
206
- public calculateBoundingInfo(excludeGeometry?: ExcludedGeometryList): BoundingInfo {
207
- // CB-6062: workaround for BoundingBox not respecting render loop
208
- this.scene.render();
209
-
210
- const { max, min } = this.scene.meshes
211
- .filter(mesh => {
212
- const isEnabled = mesh.isEnabled();
213
- // ignore meshes with invalid bounding infos
214
- const hasValidBBoxInfo = mesh.getBoundingInfo().boundingSphere.radius > 0;
215
- // ignore meshes with infinite distance, typically these are sky boxes
216
- const hasInfiniteDistance = mesh.infiniteDistance;
217
- // ignore meshes with "BackgroundMaterial" - usually a ground or skybox
218
- const hasBackgroundMaterial = mesh.material instanceof BackgroundMaterial;
219
- // ignore excluded meshes
220
- const isExcluded = excludeGeometry ? isNodeExcluded(mesh, excludeGeometry) : false;
221
-
222
- return isEnabled && hasValidBBoxInfo && !hasInfiniteDistance && !hasBackgroundMaterial && !isExcluded;
223
- })
224
- .reduce(
225
- (accBBoxMinMax, curMesh, idx) => {
226
- curMesh.refreshBoundingInfo(true, true);
227
- const bBox = curMesh.getBoundingInfo().boundingBox;
228
- // use the first entry in the array as default value and get the resulting maximum/minimum values
229
- const max = idx === 0 ? bBox.maximumWorld : Vector3.Maximize(accBBoxMinMax.max, bBox.maximumWorld);
230
- const min = idx === 0 ? bBox.minimumWorld : Vector3.Minimize(accBBoxMinMax.min, bBox.minimumWorld);
231
- return { max, min };
232
- },
233
- { max: new Vector3(), min: new Vector3() }
234
- );
235
-
236
- const boundingInfo = new BoundingInfo(min, max);
237
- return boundingInfo;
238
- }
239
-
240
196
  /**
241
197
  * Set up viewer (engine and scene) and initialize all managers
242
198
  */
@@ -252,12 +208,14 @@ export class Viewer {
252
208
  // - probably dimensions line handling (not implemented yet)
253
209
  TransformNode.BillboardUseParentOrientation = true;
254
210
 
255
- const engine = new Engine(
256
- this.canvas,
257
- this._viewerSettings.antialiasing,
258
- cloneDeep(this._viewerSettings.engineOptions),
259
- this._viewerSettings.adaptToDeviceRatio
260
- );
211
+ const engine: AbstractEngine = this.canvas
212
+ ? new Engine(
213
+ this.canvas,
214
+ this._viewerSettings.antialiasing,
215
+ cloneDeep(this._viewerSettings.engineOptions),
216
+ this._viewerSettings.adaptToDeviceRatio
217
+ )
218
+ : new NullEngine();
261
219
 
262
220
  const isScaledDownDevice = getIsScaledDownDevice(this._viewerSettings.limitTextureSize);
263
221
  if (this._viewerSettings.limitTextureSize && isScaledDownDevice) {
package/src/dev.ts DELETED
@@ -1,47 +0,0 @@
1
- import { Viewer } from '.';
2
- import {
3
- afterViewerSetup,
4
- createUIelements,
5
- getDefaultSceneSettings,
6
- getMaterial,
7
- getViewerSettings,
8
- } from '../assets/index';
9
- import { mockMaterials } from '../assets/utils/mock-materials';
10
- import { set } from 'lodash-es';
11
-
12
- document.addEventListener('DOMContentLoaded', main);
13
-
14
- window.Cbn = {
15
- Assets: {
16
- async getMaterial(materialId: string): Promise<object> {
17
- //! this creates a new function on the object that uses the imported function of the same name..
18
- const material = await getMaterial(materialId);
19
- if (material) return material;
20
-
21
- // Fallback to random mock material
22
- return mockMaterials[Math.floor(Math.random() * mockMaterials.length)];
23
- },
24
- assertMaterialExists(materialId: string): boolean {
25
- return true;
26
- },
27
- },
28
- utils: {
29
- Viewer3dHelper: {
30
- getCfgrParentDomElementForInspector(): HTMLElement | undefined {
31
- // render in parent of viewer
32
- return document.querySelector<HTMLElement>('display-container') ?? undefined;
33
- },
34
- },
35
- },
36
- };
37
-
38
- async function main(): Promise<void> {
39
- const canvas = document.getElementById('babylon-canvas') as HTMLCanvasElement;
40
- const viewer = new Viewer(canvas, getViewerSettings(), getDefaultSceneSettings());
41
-
42
- await afterViewerSetup(viewer);
43
- await createUIelements(viewer);
44
-
45
- // "Export" for console testing...
46
- set(window, 'viewer', viewer);
47
- }