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

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 (58) 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 +8 -0
  4. package/dist/lib-cjs/index.js +8 -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/cloning-helper.js +1 -1
  13. package/dist/lib-cjs/internal/cloning-helper.js.map +1 -1
  14. package/dist/lib-cjs/internal/texture-parameter-helper.js +26 -7
  15. package/dist/lib-cjs/internal/texture-parameter-helper.js.map +1 -1
  16. package/dist/lib-cjs/manager/camera-manager.d.ts +23 -2
  17. package/dist/lib-cjs/manager/camera-manager.js +91 -24
  18. package/dist/lib-cjs/manager/camera-manager.js.map +1 -1
  19. package/dist/lib-cjs/manager/debug-manager.d.ts +1 -1
  20. package/dist/lib-cjs/manager/debug-manager.js +3 -3
  21. package/dist/lib-cjs/manager/debug-manager.js.map +1 -1
  22. package/dist/lib-cjs/manager/dimension-line-manager.d.ts +126 -0
  23. package/dist/lib-cjs/manager/dimension-line-manager.js +138 -0
  24. package/dist/lib-cjs/manager/dimension-line-manager.js.map +1 -0
  25. package/dist/lib-cjs/manager/html-anchor-manager.d.ts +93 -0
  26. package/dist/lib-cjs/manager/html-anchor-manager.js +228 -0
  27. package/dist/lib-cjs/manager/html-anchor-manager.js.map +1 -0
  28. package/dist/lib-cjs/manager/model-manager.d.ts +11 -34
  29. package/dist/lib-cjs/manager/model-manager.js +47 -107
  30. package/dist/lib-cjs/manager/model-manager.js.map +1 -1
  31. package/dist/lib-cjs/manager/parameter-manager.d.ts +17 -12
  32. package/dist/lib-cjs/manager/parameter-manager.js +78 -69
  33. package/dist/lib-cjs/manager/parameter-manager.js.map +1 -1
  34. package/dist/lib-cjs/manager/scene-manager.d.ts +111 -5
  35. package/dist/lib-cjs/manager/scene-manager.js +276 -10
  36. package/dist/lib-cjs/manager/scene-manager.js.map +1 -1
  37. package/dist/lib-cjs/viewer-error.d.ts +1 -0
  38. package/dist/lib-cjs/viewer-error.js +1 -0
  39. package/dist/lib-cjs/viewer-error.js.map +1 -1
  40. package/dist/lib-cjs/viewer.d.ts +9 -14
  41. package/dist/lib-cjs/viewer.js +16 -38
  42. package/dist/lib-cjs/viewer.js.map +1 -1
  43. package/package.json +22 -12
  44. package/src/index.ts +8 -0
  45. package/src/internal/asset-helper.ts +115 -0
  46. package/src/internal/cbn-custom-babylon-loader-plugin.ts +30 -3
  47. package/src/internal/cloning-helper.ts +1 -1
  48. package/src/internal/texture-parameter-helper.ts +25 -8
  49. package/src/manager/camera-manager.ts +153 -39
  50. package/src/manager/debug-manager.ts +3 -3
  51. package/src/manager/dimension-line-manager.ts +255 -0
  52. package/src/manager/html-anchor-manager.ts +332 -0
  53. package/src/manager/model-manager.ts +55 -138
  54. package/src/manager/parameter-manager.ts +94 -75
  55. package/src/manager/scene-manager.ts +375 -10
  56. package/src/viewer-error.ts +1 -0
  57. package/src/viewer.ts +30 -56
  58. 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,336 @@ 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 dummy meshes for html anchor occlusion check
298
+ const isHtmlAnchorMesh = this.viewer.htmlAnchorManager.isHtmlAnchorMesh(mesh);
299
+ // ignore excluded meshes
300
+ const isExcluded = excludeGeometry ? isNodeExcluded(mesh, excludeGeometry) : false;
301
+
302
+ return (
303
+ isEnabled &&
304
+ hasValidBBoxInfo &&
305
+ !hasInfiniteDistance &&
306
+ !hasBackgroundMaterial &&
307
+ !isHtmlAnchorMesh &&
308
+ !isExcluded
309
+ );
310
+ })
311
+ .reduce(
312
+ (accBBoxMinMax, curMesh, idx) => {
313
+ curMesh.refreshBoundingInfo(true, true);
314
+ const bBox = curMesh.getBoundingInfo().boundingBox;
315
+ // use the first entry in the array as default value and get the resulting maximum/minimum values
316
+ const max = idx === 0 ? bBox.maximumWorld : Vector3.Maximize(accBBoxMinMax.max, bBox.maximumWorld);
317
+ const min = idx === 0 ? bBox.minimumWorld : Vector3.Minimize(accBBoxMinMax.min, bBox.minimumWorld);
318
+ return { max, min };
319
+ },
320
+ { max: new Vector3(), min: new Vector3() }
321
+ );
322
+
323
+ const boundingInfo = new BoundingInfo(min, max);
324
+ return boundingInfo;
325
+ }
326
+
327
+ /**
328
+ * Adjusts position and scaling of a dedicated "ground" meshes according to the bounding sphere of the current scene
329
+ * content.\
330
+ * This function is designed to adjust the ground that is created via `scene.createDefaultEnvironment`, but any other
331
+ * plane mesh can be used as well.
332
+ */
333
+ public updateGround(settings?: UpdateGroundSettings): void {
334
+ const bboxInfo = this.calculateBoundingInfo(settings?.excludeGeometry);
335
+
336
+ const groundMesh = settings?.groundMesh ?? this.viewer.scene.getMeshByName(SceneManager._DEFAULT_GROUND_PLANE_NAME);
337
+ if (!groundMesh) {
338
+ console.warn("Can't update ground, as no ground mesh is available");
339
+ return;
340
+ }
341
+
342
+ // 2: conversion from radius to diameter
343
+ const factor =
344
+ bboxInfo.boundingSphere.radius * 2 * (settings?.factor ?? SceneManager._DEFAULT_GROUND_SIZING_FACTOR);
345
+ const position = bboxInfo.boundingSphere.centerWorld;
346
+ groundMesh.scaling = new Vector3(factor, factor, 1);
347
+ groundMesh.position = new Vector3(position.x, 0, position.z);
348
+ }
349
+
350
+ /**
351
+ * Assigns available meshes in scene as shadow receiver and shadow casters of dedicated shadow generators, as defined
352
+ * in settings
353
+ */
354
+ public updateShadows(settings?: UpdateShadowsSettings): void {
355
+ const shadowGenerators =
356
+ settings?.shadowGenerators ??
357
+ (this.viewer.scene.lights.map(light => light.getShadowGenerator()).filter(Boolean) as IShadowGenerator[]);
358
+
359
+ const shadowCasterMeshes: AbstractMesh[] = [];
360
+ this.viewer.scene.meshes.forEach(mesh => {
361
+ const isShadowReceiver = settings?.excludeReceiver ? !isNodeExcluded(mesh, settings.excludeReceiver) : true;
362
+ if (isShadowReceiver) {
363
+ mesh.receiveShadows = true;
364
+ }
365
+
366
+ // excluding background meshes like ground or walls from shadow casters is benefitial to reduce the size of the
367
+ // poisson filters auto shadow plane calculation, which will result in better shadow resolution
368
+ const hasBackgroundMaterial = mesh.material instanceof BackgroundMaterial;
369
+ const isShadowCaster = settings?.excludeCaster ? !isNodeExcluded(mesh, settings.excludeCaster) : true;
370
+ if (isShadowCaster && !hasBackgroundMaterial) {
371
+ shadowCasterMeshes.push(mesh);
372
+ }
373
+ });
374
+
375
+ shadowGenerators.forEach(shadowGen => {
376
+ const shadowMap = shadowGen.getShadowMap();
377
+ if (!shadowMap) {
378
+ return;
379
+ }
380
+
381
+ shadowMap.renderList = [...shadowCasterMeshes];
382
+ shadowGen.recreateShadowMap();
383
+ });
384
+ }
385
+
67
386
  /**
68
387
  * Creates a camera and minimum lighting, so that the scene is set up good enough to show content.\
69
388
  * Settings can be overwritten in the constructor.
389
+ *
390
+ * @internal
70
391
  */
71
392
  public applyDefaultSettingsToScene(): void {
72
393
  const cameraSettings = this._defaultSceneSettings.camera;
73
394
  const envSettings = this._defaultSceneSettings.environment;
74
395
 
75
- this.viewer.scene.clearColor = this._defaultSceneSettings.backgroundColor;
396
+ // NOTE: default scene asset doesn't load anything, in this way the viewers "bootstrapping" process can remain
397
+ // synchronous
398
+ this._defaultSceneAsset = {
399
+ name: SceneManager._DEFAULT_SCENE_ASSET_NAME,
400
+ url: '',
401
+ state: 'loaded',
402
+ assetContainer: new AssetContainer(),
403
+ settings: {},
404
+ };
405
+
406
+ this._defaultSceneAsset.settings.clearColor = this._defaultSceneSettings.backgroundColor;
76
407
 
77
408
  // camera
78
409
  if (cameraSettings.create) {
79
410
  const camera = new ArcRotateCamera(
80
- `${SceneManager._DEFAULT_SCENE_NAME}.camera`,
411
+ `${SceneManager._DEFAULT_SCENE_ASSET_NAME}_camera`,
81
412
  cameraSettings.initialPosition.alpha,
82
413
  cameraSettings.initialPosition.beta,
83
414
  cameraSettings.initialPosition.radius,
84
415
  cameraSettings.initialPosition.target,
85
416
  this.viewer.scene
86
417
  );
87
- camera.attachControl(this.viewer.engine._workingCanvas, true);
88
418
  camera.minZ = cameraSettings.settings.minZ;
89
419
  camera.lowerRadiusLimit = cameraSettings.settings.lowerRadiusLimit;
90
420
  camera.wheelPrecision = cameraSettings.settings.wheelPrecision;
91
421
  camera.panningSensibility = cameraSettings.settings.panningSensibility;
422
+ camera.attachControl(undefined, true);
423
+
424
+ this._defaultSceneAsset.assetContainer.cameras.push(camera);
425
+ this.viewer.scene.removeCamera(camera);
92
426
  }
93
427
 
94
428
  // environment
95
429
  if (envSettings.create) {
96
430
  const envTexture = CubeTexture.CreateFromPrefilteredData(envSettings.url, this.viewer.scene);
97
- this.viewer.scene.environmentTexture = envTexture;
98
- this.viewer.scene.environmentIntensity = envSettings.intensity;
431
+
432
+ this._defaultSceneAsset.assetContainer.environmentTexture = envTexture;
433
+ this._defaultSceneAsset.settings.environmentIntensity = envSettings.intensity;
99
434
  }
435
+
436
+ this.setDefaultSceneAsset();
437
+ }
438
+
439
+ protected _getSceneAsset(name: string): SceneAsset | undefined {
440
+ if (name === SceneManager._DEFAULT_SCENE_ASSET_NAME) {
441
+ return this._defaultSceneAsset;
442
+ }
443
+
444
+ const sceneAsset = this._sceneAssets[name];
445
+ return sceneAsset;
446
+ }
447
+
448
+ protected async _loadSceneAsset(sceneAsset: SceneAsset): Promise<void> {
449
+ const loadSceneAssetPromise = async (): Promise<void> => {
450
+ const { sceneSettingsData } = await loadAsset(sceneAsset, this.viewer);
451
+
452
+ sceneAsset.settings = sceneSettingsData ?? {};
453
+
454
+ delete this._loadSceneAssetPromises[sceneAsset.name];
455
+ };
456
+
457
+ this._loadSceneAssetPromises[sceneAsset.name] = loadSceneAssetPromise();
458
+ return this._loadSceneAssetPromises[sceneAsset.name];
459
+ }
460
+
461
+ protected _hideSceneAsset(sceneAsset: SceneAsset): void {
462
+ sceneAsset.assetContainer.cameras.forEach(camera => camera.detachControl());
463
+ sceneAsset.assetContainer.removeFromScene();
464
+ sceneAsset.state = 'loaded';
100
465
  }
101
466
  }
@@ -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,28 +1,28 @@
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,
8
+ DimensionLineManager,
9
9
  Engine,
10
10
  EngineOptions,
11
11
  EventManager,
12
12
  GltfExportManager,
13
+ HtmlAnchorManager,
13
14
  MaterialManager,
14
15
  ModelManager,
16
+ NullEngine,
15
17
  ParameterManager,
16
18
  ParameterSubject,
17
19
  Scene,
18
20
  SceneManager,
19
21
  TextureManager,
20
22
  TransformNode,
21
- Vector3,
22
23
  } from './index';
23
24
  import { registerCustomCbnBabylonLoaderPlugin } from './internal/cbn-custom-babylon-loader-plugin';
24
25
  import { getIsScaledDownDevice } from './internal/device-helper';
25
- import { isNodeExcluded } from './internal/geometry-helper';
26
26
  import { cloneDeep, merge } from 'lodash-es';
27
27
 
28
28
  /**
@@ -82,8 +82,10 @@ export class Viewer {
82
82
 
83
83
  protected _cameraManager!: CameraManager;
84
84
  protected _debugManager!: DebugManager;
85
+ protected _dimensionLineManager!: DimensionLineManager;
85
86
  protected _eventManager!: EventManager;
86
87
  protected _gltfExportManager!: GltfExportManager;
88
+ protected _htmlAnchorManager!: HtmlAnchorManager;
87
89
  protected _materialManager!: MaterialManager;
88
90
  protected _modelManager!: ModelManager;
89
91
  protected _parameterManager!: ParameterManager;
@@ -112,8 +114,8 @@ export class Viewer {
112
114
  get scene(): Scene {
113
115
  return this._scene;
114
116
  }
115
- get engine(): Engine {
116
- return this.scene.getEngine() as Engine;
117
+ get engine(): AbstractEngine {
118
+ return this.scene.getEngine();
117
119
  }
118
120
  get cameraManager(): CameraManager {
119
121
  return this._cameraManager;
@@ -121,12 +123,18 @@ export class Viewer {
121
123
  get debugManager(): DebugManager {
122
124
  return this._debugManager;
123
125
  }
126
+ get dimensionLineManager(): DimensionLineManager {
127
+ return this._dimensionLineManager;
128
+ }
124
129
  get eventManager(): EventManager {
125
130
  return this._eventManager;
126
131
  }
127
132
  get gltfExportManager(): GltfExportManager {
128
133
  return this._gltfExportManager;
129
134
  }
135
+ get htmlAnchorManager(): HtmlAnchorManager {
136
+ return this._htmlAnchorManager;
137
+ }
130
138
  get materialManager(): MaterialManager {
131
139
  return this._materialManager;
132
140
  }
@@ -164,7 +172,7 @@ export class Viewer {
164
172
  * This scene contains a camera and an environment per default.
165
173
  */
166
174
  public constructor(
167
- public readonly canvas: HTMLCanvasElement,
175
+ public readonly canvas?: HTMLCanvasElement,
168
176
  viewerSettings?: DeepPartial<ViewerSettings>,
169
177
  defaultSceneSettings?: DeepPartial<DefaultSceneSettings>
170
178
  ) {
@@ -173,7 +181,7 @@ export class Viewer {
173
181
  }
174
182
 
175
183
  /**
176
- * Pause rendering can be usefull when doing internal scene processings that should not be visible to the user,
184
+ * Pause rendering can be useful when doing internal scene processings that should not be visible to the user,
177
185
  * e.g. cloning meshes for gltf export
178
186
  */
179
187
  public pauseRendering(): void {
@@ -195,48 +203,6 @@ export class Viewer {
195
203
  this.engine.dispose();
196
204
  }
197
205
 
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
206
  /**
241
207
  * Set up viewer (engine and scene) and initialize all managers
242
208
  */
@@ -252,12 +218,14 @@ export class Viewer {
252
218
  // - probably dimensions line handling (not implemented yet)
253
219
  TransformNode.BillboardUseParentOrientation = true;
254
220
 
255
- const engine = new Engine(
256
- this.canvas,
257
- this._viewerSettings.antialiasing,
258
- cloneDeep(this._viewerSettings.engineOptions),
259
- this._viewerSettings.adaptToDeviceRatio
260
- );
221
+ const engine: AbstractEngine = this.canvas
222
+ ? new Engine(
223
+ this.canvas,
224
+ this._viewerSettings.antialiasing,
225
+ cloneDeep(this._viewerSettings.engineOptions),
226
+ this._viewerSettings.adaptToDeviceRatio
227
+ )
228
+ : new NullEngine();
261
229
 
262
230
  const isScaledDownDevice = getIsScaledDownDevice(this._viewerSettings.limitTextureSize);
263
231
  if (this._viewerSettings.limitTextureSize && isScaledDownDevice) {
@@ -269,14 +237,20 @@ export class Viewer {
269
237
  }
270
238
 
271
239
  this._scene = new Scene(engine);
240
+ // NOTE: rendering group id "1" is reserved for occlusion helper sphere (see `HtmlAnchorManager`)
241
+ // rendering group id "1" has the same depth buffer as 0 in order to make this work
242
+ // => use rendering group id "2" or higher for keeping meshes in foreground
243
+ this._scene.setRenderingAutoClearDepthStencil(1, false, false, false);
272
244
 
273
245
  // NOTE: order of manage seems to be a bit counter intuitive as it's sorted alphabetically
274
246
  // semantically one would start with scene manager, etc...
275
247
  // still this is a good test as the order of manager constructors should not matter
276
248
  this._cameraManager = new CameraManager(this);
277
249
  this._debugManager = new DebugManager(this);
250
+ this._dimensionLineManager = new DimensionLineManager(this);
278
251
  this._eventManager = new EventManager(this);
279
252
  this._gltfExportManager = new GltfExportManager(this);
253
+ this._htmlAnchorManager = new HtmlAnchorManager(this);
280
254
  this._materialManager = new MaterialManager(this);
281
255
  this._modelManager = new ModelManager(this);
282
256
  this._parameterManager = new ParameterManager(this);
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
- }