@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.
- package/dist/lib-cjs/buildinfo.json +1 -1
- package/dist/lib-cjs/commonjs.tsconfig.tsbuildinfo +1 -1
- package/dist/lib-cjs/index.d.ts +2 -0
- package/dist/lib-cjs/index.js +2 -0
- package/dist/lib-cjs/index.js.map +1 -1
- package/dist/lib-cjs/internal/asset-helper.d.ts +32 -0
- package/dist/lib-cjs/internal/asset-helper.js +105 -0
- package/dist/lib-cjs/internal/asset-helper.js.map +1 -0
- package/dist/lib-cjs/internal/cbn-custom-babylon-loader-plugin.d.ts +18 -0
- package/dist/lib-cjs/internal/cbn-custom-babylon-loader-plugin.js +22 -3
- package/dist/lib-cjs/internal/cbn-custom-babylon-loader-plugin.js.map +1 -1
- package/dist/lib-cjs/internal/texture-parameter-helper.js +26 -7
- package/dist/lib-cjs/internal/texture-parameter-helper.js.map +1 -1
- package/dist/lib-cjs/manager/camera-manager.js +4 -2
- package/dist/lib-cjs/manager/camera-manager.js.map +1 -1
- package/dist/lib-cjs/manager/debug-manager.js +1 -1
- package/dist/lib-cjs/manager/debug-manager.js.map +1 -1
- package/dist/lib-cjs/manager/model-manager.d.ts +11 -33
- package/dist/lib-cjs/manager/model-manager.js +47 -106
- package/dist/lib-cjs/manager/model-manager.js.map +1 -1
- package/dist/lib-cjs/manager/parameter-manager.d.ts +16 -11
- package/dist/lib-cjs/manager/parameter-manager.js +78 -69
- package/dist/lib-cjs/manager/parameter-manager.js.map +1 -1
- package/dist/lib-cjs/manager/scene-manager.d.ts +111 -5
- package/dist/lib-cjs/manager/scene-manager.js +269 -10
- package/dist/lib-cjs/manager/scene-manager.js.map +1 -1
- package/dist/lib-cjs/viewer-error.d.ts +1 -0
- package/dist/lib-cjs/viewer-error.js +1 -0
- package/dist/lib-cjs/viewer-error.js.map +1 -1
- package/dist/lib-cjs/viewer.d.ts +4 -13
- package/dist/lib-cjs/viewer.js +3 -37
- package/dist/lib-cjs/viewer.js.map +1 -1
- package/package.json +21 -12
- package/src/index.ts +2 -0
- package/src/internal/asset-helper.ts +115 -0
- package/src/internal/cbn-custom-babylon-loader-plugin.ts +30 -3
- package/src/internal/texture-parameter-helper.ts +25 -8
- package/src/manager/camera-manager.ts +4 -2
- package/src/manager/debug-manager.ts +1 -1
- package/src/manager/model-manager.ts +55 -137
- package/src/manager/parameter-manager.ts +93 -74
- package/src/manager/scene-manager.ts +366 -10
- package/src/viewer-error.ts +1 -0
- package/src/viewer.ts +13 -55
- package/src/dev.ts +0 -47
|
@@ -1,4 +1,22 @@
|
|
|
1
|
-
import {
|
|
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
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
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
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
98
|
-
this.
|
|
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
|
}
|
package/src/viewer-error.ts
CHANGED
|
@@ -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
|
-
|
|
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():
|
|
116
|
-
return this.scene.getEngine()
|
|
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
|
|
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 =
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
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
|
-
}
|