@combeenation/3d-viewer 5.0.1 → 5.0.3-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 (109) hide show
  1. package/README.md +111 -114
  2. package/dist/lib-cjs/api/classes/animationInterface.d.ts +8 -8
  3. package/dist/lib-cjs/api/classes/animationInterface.js +1 -1
  4. package/dist/lib-cjs/api/classes/dottedPath.d.ts +79 -79
  5. package/dist/lib-cjs/api/classes/dottedPath.js +187 -187
  6. package/dist/lib-cjs/api/classes/element.d.ts +139 -139
  7. package/dist/lib-cjs/api/classes/element.js +794 -794
  8. package/dist/lib-cjs/api/classes/element.js.map +1 -1
  9. package/dist/lib-cjs/api/classes/elementParameterizable.d.ts +14 -0
  10. package/dist/lib-cjs/api/classes/elementParameterizable.js +135 -0
  11. package/dist/lib-cjs/api/classes/elementParameterizable.js.map +1 -0
  12. package/dist/lib-cjs/api/classes/event.d.ts +326 -326
  13. package/dist/lib-cjs/api/classes/event.js +371 -371
  14. package/dist/lib-cjs/api/classes/eventBroadcaster.d.ts +26 -26
  15. package/dist/lib-cjs/api/classes/eventBroadcaster.js +53 -53
  16. package/dist/lib-cjs/api/classes/parameter.d.ts +316 -259
  17. package/dist/lib-cjs/api/classes/parameter.js +451 -388
  18. package/dist/lib-cjs/api/classes/parameter.js.map +1 -1
  19. package/dist/lib-cjs/api/classes/parameterObservable.d.ts +36 -36
  20. package/dist/lib-cjs/api/classes/parameterObservable.js +101 -101
  21. package/dist/lib-cjs/api/classes/parameterizable.d.ts +15 -15
  22. package/dist/lib-cjs/api/classes/parameterizable.js +149 -149
  23. package/dist/lib-cjs/api/classes/placementAnimation.d.ts +44 -44
  24. package/dist/lib-cjs/api/classes/placementAnimation.js +163 -163
  25. package/dist/lib-cjs/api/classes/variant.d.ts +234 -234
  26. package/dist/lib-cjs/api/classes/variant.js +1154 -1154
  27. package/dist/lib-cjs/api/classes/variantInstance.d.ts +45 -45
  28. package/dist/lib-cjs/api/classes/variantInstance.js +108 -108
  29. package/dist/lib-cjs/api/classes/variantParameterizable.d.ts +17 -17
  30. package/dist/lib-cjs/api/classes/variantParameterizable.js +99 -99
  31. package/dist/lib-cjs/api/classes/viewer.d.ts +177 -175
  32. package/dist/lib-cjs/api/classes/viewer.js +717 -701
  33. package/dist/lib-cjs/api/classes/viewer.js.map +1 -1
  34. package/dist/lib-cjs/api/classes/viewerLight.d.ts +66 -66
  35. package/dist/lib-cjs/api/classes/viewerLight.js +392 -392
  36. package/dist/lib-cjs/api/internal/debugViewer.d.ts +13 -13
  37. package/dist/lib-cjs/api/internal/debugViewer.js +86 -86
  38. package/dist/lib-cjs/api/internal/lensRendering.d.ts +8 -8
  39. package/dist/lib-cjs/api/internal/lensRendering.js +11 -11
  40. package/dist/lib-cjs/api/internal/sceneSetup.d.ts +13 -10
  41. package/dist/lib-cjs/api/internal/sceneSetup.js +238 -234
  42. package/dist/lib-cjs/api/internal/sceneSetup.js.map +1 -1
  43. package/dist/lib-cjs/api/manager/animationManager.d.ts +29 -29
  44. package/dist/lib-cjs/api/manager/animationManager.js +130 -130
  45. package/dist/lib-cjs/api/manager/gltfExportManager.d.ts +65 -65
  46. package/dist/lib-cjs/api/manager/gltfExportManager.js +223 -222
  47. package/dist/lib-cjs/api/manager/gltfExportManager.js.map +1 -1
  48. package/dist/lib-cjs/api/manager/sceneManager.d.ts +31 -32
  49. package/dist/lib-cjs/api/manager/sceneManager.js +153 -132
  50. package/dist/lib-cjs/api/manager/sceneManager.js.map +1 -1
  51. package/dist/lib-cjs/api/manager/variantInstanceManager.d.ts +92 -92
  52. package/dist/lib-cjs/api/manager/variantInstanceManager.js +335 -335
  53. package/dist/lib-cjs/api/store/specStorage.d.ts +24 -24
  54. package/dist/lib-cjs/api/store/specStorage.js +51 -51
  55. package/dist/lib-cjs/api/util/babylonHelper.d.ts +174 -166
  56. package/dist/lib-cjs/api/util/babylonHelper.js +575 -497
  57. package/dist/lib-cjs/api/util/babylonHelper.js.map +1 -1
  58. package/dist/lib-cjs/api/util/globalTypes.d.ts +366 -356
  59. package/dist/lib-cjs/api/util/globalTypes.js +1 -1
  60. package/dist/lib-cjs/api/util/resourceHelper.d.ts +58 -53
  61. package/dist/lib-cjs/api/util/resourceHelper.js +257 -242
  62. package/dist/lib-cjs/api/util/resourceHelper.js.map +1 -1
  63. package/dist/lib-cjs/api/util/stringHelper.d.ts +9 -9
  64. package/dist/lib-cjs/api/util/stringHelper.js +25 -25
  65. package/dist/lib-cjs/api/util/structureHelper.d.ts +9 -9
  66. package/dist/lib-cjs/api/util/structureHelper.js +48 -44
  67. package/dist/lib-cjs/api/util/structureHelper.js.map +1 -1
  68. package/dist/lib-cjs/buildinfo.json +3 -3
  69. package/dist/lib-cjs/index.d.ts +49 -49
  70. package/dist/lib-cjs/index.js +89 -89
  71. package/dist/webpack-stats.json +0 -0
  72. package/package.json +87 -87
  73. package/src/api/classes/animationInterface.ts +10 -10
  74. package/src/api/classes/dottedPath.ts +181 -181
  75. package/src/api/classes/element.ts +690 -692
  76. package/src/api/classes/event.ts +367 -367
  77. package/src/api/classes/eventBroadcaster.ts +52 -52
  78. package/src/api/classes/parameter.ts +474 -405
  79. package/src/api/classes/parameterObservable.ts +100 -100
  80. package/src/api/classes/parameterizable.ts +87 -87
  81. package/src/api/classes/placementAnimation.ts +160 -160
  82. package/src/api/classes/variant.ts +845 -845
  83. package/src/api/classes/variantInstance.ts +97 -97
  84. package/src/api/classes/variantParameterizable.ts +85 -85
  85. package/src/api/classes/viewer.ts +650 -624
  86. package/src/api/classes/viewerLight.ts +334 -334
  87. package/src/api/internal/debugViewer.ts +90 -90
  88. package/src/api/internal/lensRendering.ts +10 -10
  89. package/src/api/internal/sceneSetup.ts +204 -201
  90. package/src/api/manager/animationManager.ts +142 -142
  91. package/src/api/manager/gltfExportManager.ts +191 -191
  92. package/src/api/manager/sceneManager.ts +128 -102
  93. package/src/api/manager/variantInstanceManager.ts +265 -265
  94. package/src/api/store/specStorage.ts +51 -51
  95. package/src/api/util/babylonHelper.ts +628 -538
  96. package/src/api/util/globalTypes.ts +413 -402
  97. package/src/api/util/resourceHelper.ts +189 -173
  98. package/src/api/util/stringHelper.ts +23 -23
  99. package/src/api/util/structureHelper.ts +49 -43
  100. package/src/buildinfo.json +3 -3
  101. package/src/commonjs.tsconfig.json +10 -10
  102. package/src/declaration.tsconfig.json +8 -8
  103. package/src/dev.ts +42 -42
  104. package/src/es6.tsconfig.json +10 -10
  105. package/src/index.ts +94 -94
  106. package/src/pagesconfig.json +77 -73
  107. package/src/tsconfig.json +32 -32
  108. package/src/tsconfig.types.json +9 -9
  109. package/src/types.d.ts +3 -3
@@ -1,538 +1,628 @@
1
- import { HighlightLayer } from '@babylonjs/core/Layers/highlightLayer';
2
- import { Light } from '@babylonjs/core/Lights/light';
3
- import { ShadowGenerator } from '@babylonjs/core/Lights/Shadows/shadowGenerator';
4
- import { Material } from '@babylonjs/core/Materials/material';
5
- import { PBRMaterial } from '@babylonjs/core/Materials/PBR/pbrMaterial';
6
- import { StandardMaterial } from '@babylonjs/core/Materials/standardMaterial';
7
- import { Axis } from '@babylonjs/core/Maths/math.axis';
8
- import { Color3 } from '@babylonjs/core/Maths/math.color';
9
- import { Quaternion, Vector3 } from '@babylonjs/core/Maths/math.vector';
10
- import { AbstractMesh } from '@babylonjs/core/Meshes/abstractMesh';
11
- import { InstancedMesh } from '@babylonjs/core/Meshes/instancedMesh';
12
- import { Mesh } from '@babylonjs/core/Meshes/mesh';
13
- import { TransformNode } from '@babylonjs/core/Meshes/transformNode';
14
- import { Node } from '@babylonjs/core/node';
15
- import { Scene } from '@babylonjs/core/scene';
16
- import { Nullable } from '@babylonjs/core/types';
17
- import { cloneDeep, get, has, merge } from 'lodash-es';
18
- import { DottedPath } from '../classes/dottedPath';
19
-
20
- /**
21
- * @param node
22
- * @return Node
23
- */
24
- const getRootNode = function (node: Node): Node {
25
- let _node = node;
26
- while (_node.parent) {
27
- _node = _node.parent;
28
- }
29
- return _node;
30
- };
31
-
32
- /**
33
- * @param nodes
34
- * @param predicate
35
- * @return Map<DottedPath, T>
36
- */
37
- const mapToDottedNodes = function <T>(nodes: Node[], predicate?: (node: Node) => boolean): Map<DottedPath, T> {
38
- const map = new Map<DottedPath, T>();
39
- const addNodes = function (_node: Node) {
40
- if (predicate && predicate(_node)) {
41
- map.set(_node.metadata.dottedPath, _node as any);
42
- }
43
- _node.getChildren().forEach(child => {
44
- addNodes(child);
45
- });
46
- };
47
- nodes.forEach(node => {
48
- addNodes(node);
49
- });
50
- return map;
51
- };
52
-
53
- /**
54
- * @param node
55
- * @return DottedPath
56
- */
57
- const getDottedPathForNode = function (node: Node): DottedPath {
58
- const dottedPath = DottedPath.create(node.name);
59
- let _parent = node;
60
- while (_parent.parent) {
61
- _parent = _parent.parent;
62
- dottedPath.unshiftPart(_parent.name);
63
- }
64
- return dottedPath;
65
- };
66
-
67
- /**
68
- * @param node
69
- * @param predicate
70
- * @param deep
71
- * @return TransformNode | null
72
- */
73
- const cloneTransformNode = function (
74
- node: TransformNode,
75
- predicate?: (node: TransformNode) => boolean,
76
- deep: boolean = true
77
- ): TransformNode | null {
78
- if (predicate && !predicate(node)) {
79
- return null;
80
- }
81
- const clone = node.clone(node.name, node.parent, true);
82
- if (clone) {
83
- clone.metadata = cloneDeep(node.metadata);
84
- }
85
- if (deep) {
86
- const children = node.getChildTransformNodes(true);
87
- children.forEach(child => {
88
- const clonedChild = cloneTransformNode(child, predicate, deep);
89
- if (clonedChild) {
90
- clonedChild.parent = clone;
91
- }
92
- });
93
- }
94
- return clone;
95
- };
96
-
97
- /**
98
- * @param node
99
- */
100
- const cloneNodeWithParents = function (node: Node | null): Node | null {
101
- let clone = null;
102
- if (node instanceof TransformNode) {
103
- clone = node.clone(node.name, cloneNodeWithParents(node.parent) as Nullable<Node>, true);
104
- } else if (node instanceof Light) {
105
- clone = node.clone(node.name, cloneNodeWithParents(node.parent) as Nullable<Node>);
106
- } else if (node) {
107
- throw new Error(`Cloning of "${node?.constructor.name}" is not implemented (yet).`);
108
- }
109
- return clone;
110
- };
111
-
112
- /**
113
- * @param node
114
- * @param deep
115
- * @param prefix
116
- * @return TransformNode
117
- */
118
- const cloneTransformNodeMaterial = function (
119
- node: TransformNode,
120
- prefix: DottedPathArgument = '',
121
- deep: boolean = true
122
- ): TransformNode {
123
- if (node instanceof AbstractMesh && node.material) {
124
- const newMatName = DottedPath.create(prefix).addParts([node.material.name, 'clone', node.uniqueId.toString()]);
125
- node.material = node.material.clone(newMatName.path);
126
- }
127
- if (deep) {
128
- const children = node.getChildTransformNodes(true);
129
- children.forEach(child => cloneTransformNodeMaterial(child, prefix, deep));
130
- }
131
- return node;
132
- };
133
-
134
- /**
135
- * @param node
136
- * @param deep
137
- * @param metadata
138
- */
139
- const injectNodeMetadata = function (node: Node, metadata: {}, deep: boolean = true) {
140
- node.metadata = merge({}, node.metadata, metadata);
141
- if (deep && node instanceof TransformNode) {
142
- const children = node.getChildTransformNodes(true);
143
- children.forEach(child => injectNodeMetadata(child, metadata, deep));
144
- }
145
- };
146
-
147
- /**
148
- * @param node
149
- * @param assertCallable
150
- * @param callableParameters
151
- * @param deep
152
- */
153
- const assertTransformNode = function (
154
- node: TransformNode,
155
- assertCallable: CallableFunction,
156
- callableParameters: any[] = [],
157
- deep: boolean = true
158
- ) {
159
- assertCallable(node, ...callableParameters);
160
- if (deep) {
161
- const children = node.getChildTransformNodes(true);
162
- children.forEach(child => assertTransformNode(child, assertCallable, callableParameters, deep));
163
- }
164
- };
165
-
166
- /**
167
- * @param node
168
- * @param deep
169
- */
170
- const activateTransformNode = function (node: TransformNode, deep: boolean = true) {
171
- node.setEnabled(true);
172
- /*
173
- if( node instanceof AbstractMesh ) {
174
- node.visibility = 1;
175
- node.isPickable = true;
176
- }
177
- */
178
- if (deep) {
179
- node.getChildTransformNodes(true).forEach(child => activateTransformNode(child, deep));
180
- }
181
- };
182
-
183
- /**
184
- * @param node
185
- * @param deep
186
- */
187
- const deactivateTransformNode = function (node: TransformNode, deep: boolean = true) {
188
- node.setEnabled(false);
189
- /*
190
- if( node instanceof AbstractMesh ) {
191
- node.visibility = 0;
192
- node.isPickable = false;
193
- }
194
- */
195
- if (deep) {
196
- node.getChildTransformNodes(true).forEach(child => deactivateTransformNode(child, deep));
197
- }
198
- };
199
-
200
- /**
201
- * @param node
202
- */
203
- const enableNodeWithParents = function (node: Node) {
204
- node.setEnabled(true);
205
- if (node.parent) {
206
- enableNodeWithParents(node.parent);
207
- }
208
- };
209
-
210
- /**
211
- * @param node
212
- */
213
- const disableNodeWithParents = function (node: Node) {
214
- node.setEnabled(false);
215
- if (node.parent) {
216
- disableNodeWithParents(node.parent);
217
- }
218
- };
219
-
220
- /**
221
- * Applies a {@link TransformationDefinition} consecutively to ensure dependencies in positioning etc.
222
- * @param node
223
- * @param transformation
224
- */
225
- const transformTransformNode = function (node: TransformNode, transformation: TransformationDefinition) {
226
- // scaling
227
- if (!has(node.metadata, 'scaling.initial')) {
228
- injectNodeMetadata(node, { 'scaling.initial': node.scaling }, false);
229
- }
230
- const initialScaling = get(node.metadata, 'scaling.initial') as Vector3;
231
- node.scaling = initialScaling.multiply(transformation.scaling);
232
- // position
233
- if (!has(node.metadata, 'position.initial')) {
234
- injectNodeMetadata(node, { 'position.initial': node.absolutePosition.clone() }, false);
235
- }
236
- const initialPosition = get(node.metadata, 'position.initial') as Vector3;
237
- node.setAbsolutePosition(initialPosition.add(transformation.position).multiply(transformation.scaling));
238
- // rotation
239
- if (!has(node.metadata, 'rotation.initial')) {
240
- let rotationQuaternion = node.rotationQuaternion;
241
- if (!rotationQuaternion) {
242
- rotationQuaternion = Quaternion.RotationYawPitchRoll(node.rotation.x, node.rotation.y, node.rotation.z);
243
- }
244
- injectNodeMetadata(node, { 'rotation.initial': rotationQuaternion.asArray() }, false);
245
- }
246
- const initialRotationQuaternion = Quaternion.FromArray(get(node.metadata, 'rotation.initial') as []);
247
- node.rotationQuaternion = initialRotationQuaternion;
248
- node.rotateAround(Vector3.Zero(), Axis.X, transformation.rotation.x);
249
- node.rotateAround(Vector3.Zero(), Axis.Y, transformation.rotation.y);
250
- node.rotateAround(Vector3.Zero(), Axis.Z, transformation.rotation.z);
251
- node.computeWorldMatrix(true);
252
- };
253
-
254
- /**
255
- * @param node
256
- * @param material
257
- * @param deep
258
- */
259
- const setMaterial = function (node: TransformNode, material: Material, deep: boolean = true) {
260
- if (node instanceof AbstractMesh) {
261
- node.material = material;
262
- }
263
- if (deep) {
264
- node.getChildTransformNodes(true).forEach(child => setMaterial(child, material, deep));
265
- }
266
- };
267
-
268
- /**
269
- * !!! Warning !!!
270
- * This function is not public API. Whilst it can help solving certain problems, it only works reliably in well defined
271
- * situations and can cause unwanted side effects under some conditions. Use carefully at your own risk!
272
- *
273
- * See https://combeenation.myjetbrains.com/youtrack/issue/CB-5906 for further details regarding this warning.
274
- *
275
- * Set material of an instanced meshes source mesh.
276
- * Changes the material of all instanced meshes which have the same source mesh.
277
- *
278
- * @param node
279
- * @param material
280
- * @param deep
281
- *
282
- * @ignore
283
- */
284
- const setSourceNodeMaterial = function (node: TransformNode, material: Material, deep: boolean = true) {
285
- const warn = ` You're using "setSourceNodeMaterial" which is not public API.
286
- Whilst it can help solving certain problems, it only works reliably in well defined situations and can cause unwanted side effects under some conditions.
287
- Use carefully at your own risk!`;
288
- console.warn(`!!! Warning !!!\n${warn}`);
289
-
290
- if (node instanceof InstancedMesh) {
291
- node.sourceMesh.material = material;
292
- }
293
- if (deep) {
294
- node.getChildTransformNodes(true).forEach(child => setSourceNodeMaterial(child, material, deep));
295
- }
296
- };
297
-
298
- /**
299
- * @param node
300
- * @param color
301
- * @param deep
302
- */
303
- const setMaterialColor = function (node: TransformNode, color: Color3, deep: boolean = true) {
304
- if (node instanceof AbstractMesh && node.material) {
305
- const materialCls = node.material.getClassName();
306
- switch (materialCls) {
307
- case 'PBRMaterial':
308
- (node.material as PBRMaterial).albedoColor = color.toLinearSpace();
309
- break;
310
- case 'StandardMaterial':
311
- (node.material as StandardMaterial).diffuseColor = color;
312
- break;
313
- default:
314
- throw new Error(`Setting color for material of instance "${materialCls}" not implemented (yet).`);
315
- }
316
- }
317
- if (deep) {
318
- node.getChildTransformNodes(true).forEach(child => setMaterialColor(child, color, deep));
319
- }
320
- };
321
-
322
- /**
323
- * @param node
324
- * @param texture
325
- * @param deep
326
- */
327
- const setMaterialTexture = function (node: TransformNode, texture: Texture, deep: boolean = true) {
328
- if (node instanceof AbstractMesh && node.material) {
329
- const materialCls = node.material.getClassName();
330
- switch (materialCls) {
331
- case 'PBRMaterial':
332
- (node.material as PBRMaterial).albedoTexture = texture;
333
- break;
334
- case 'StandardMaterial':
335
- (node.material as StandardMaterial).diffuseTexture = texture;
336
- break;
337
- default:
338
- throw new Error(`Setting texture for material of instance "${materialCls}" not implemented (yet).`);
339
- }
340
- }
341
- if (deep) {
342
- node.getChildTransformNodes(true).forEach(child => setMaterialTexture(child, texture, deep));
343
- }
344
- };
345
-
346
- /**
347
- * @param node
348
- * @param metallness
349
- * @param deep
350
- */
351
- const setMaterialMetallness = function (node: TransformNode, metallness: number, deep: boolean = true) {
352
- if (node instanceof AbstractMesh && node.material) {
353
- const materialCls = node.material.getClassName();
354
- switch (materialCls) {
355
- case 'PBRMaterial':
356
- (node.material as PBRMaterial).metallic = metallness;
357
- break;
358
- default:
359
- throw new Error(`Setting metallness for material of instance "${materialCls}" not implemented (yet).`);
360
- }
361
- }
362
- if (deep) {
363
- node.getChildTransformNodes(true).forEach(child => setMaterialMetallness(child, metallness, deep));
364
- }
365
- };
366
-
367
- /**
368
- * @param node
369
- * @param roughness
370
- * @param deep
371
- */
372
- const setMaterialRoughness = function (node: TransformNode, roughness: number, deep: boolean = true) {
373
- if (node instanceof AbstractMesh && node.material) {
374
- const materialCls = node.material.getClassName();
375
- switch (materialCls) {
376
- case 'PBRMaterial':
377
- (node.material as PBRMaterial).roughness = roughness;
378
- break;
379
- case 'StandardMaterial':
380
- (node.material as StandardMaterial).roughness = roughness;
381
- break;
382
- default:
383
- throw new Error(`Setting roughness for material of instance "${materialCls}" not implemented (yet).`);
384
- }
385
- }
386
- if (deep) {
387
- node.getChildTransformNodes(true).forEach(child => setMaterialRoughness(child, roughness, deep));
388
- }
389
- };
390
-
391
- /**
392
- * @param node
393
- * @param layer
394
- * @param color
395
- * @param deep
396
- */
397
- const addToHighlightLayer = function (layer: HighlightLayer, color: Color3, node: TransformNode, deep: boolean = true) {
398
- if (node instanceof AbstractMesh) {
399
- layer.addMesh(node as Mesh, color);
400
- }
401
- if (deep) {
402
- node.getChildTransformNodes(true).forEach(child => addToHighlightLayer(layer, color, child, deep));
403
- }
404
- };
405
-
406
- /**
407
- * @param node
408
- * @param layer
409
- * @param deep
410
- */
411
- const removeFromHighlightLayer = function (layer: HighlightLayer, node: TransformNode, deep: boolean = true) {
412
- if (node instanceof AbstractMesh) {
413
- layer.removeMesh(node as Mesh);
414
- }
415
- if (deep) {
416
- node.getChildTransformNodes(true).forEach(child => removeFromHighlightLayer(layer, child, deep));
417
- }
418
- };
419
-
420
- /**
421
- * @param node
422
- * @param receiveShadows
423
- * @param deep
424
- */
425
- const setReceiveShadows = function (node: TransformNode, receiveShadows: boolean, deep: boolean = true) {
426
- if (node instanceof AbstractMesh) {
427
- node.receiveShadows = receiveShadows;
428
- }
429
- if (deep) {
430
- node.getChildTransformNodes(true).forEach(child => setReceiveShadows(child, receiveShadows, deep));
431
- }
432
- };
433
-
434
- /**
435
- * @param node
436
- * @param generator
437
- * @param deep
438
- */
439
- const addToShadowGenerator = function (generator: ShadowGenerator, node: TransformNode, deep: boolean = true) {
440
- if (node instanceof AbstractMesh) {
441
- // We have to remove the node because there's no duplicate check in babylon
442
- generator.removeShadowCaster(node, false);
443
- generator.addShadowCaster(node, false);
444
- }
445
- if (deep) {
446
- node.getChildTransformNodes(true).forEach(child => addToShadowGenerator(generator, child, deep));
447
- }
448
- };
449
-
450
- /**
451
- * @param node
452
- * @param generator
453
- * @param deep
454
- */
455
- const removeFromShadowGenerator = function (generator: ShadowGenerator, node: TransformNode, deep: boolean = true) {
456
- if (node instanceof AbstractMesh) {
457
- generator.removeShadowCaster(node, false);
458
- }
459
- if (deep) {
460
- node.getChildTransformNodes(true).forEach(child => removeFromShadowGenerator(generator, child, deep));
461
- }
462
- };
463
-
464
- /**
465
- * https://forum.babylonjs.com/t/get-mesh-bounding-box-position-and-size-in-2d-screen-coordinates/1058/3
466
- * @param mesh
467
- * @param scene
468
- * @param canvas
469
- */
470
- const getClientRectFromMesh = function (mesh: AbstractMesh, scene: Scene, canvas: HTMLCanvasElement): ClientRect {
471
- // get bounding box of the mesh
472
- const meshVectors = mesh.getBoundingInfo().boundingBox.vectors;
473
- // get the matrix and viewport needed to project the vectors onto the screen
474
- const worldMatrix = mesh.getWorldMatrix();
475
- const transformMatrix = scene.getTransformMatrix();
476
- const viewport = scene.activeCamera!.viewport;
477
- // loop though all the vectors and project them against the current camera viewport to get a set of coordinates
478
- const coordinates = meshVectors.map(vector => {
479
- const projection = Vector3.Project(vector, worldMatrix, transformMatrix, viewport);
480
- projection.x = projection.x * canvas.clientWidth;
481
- projection.y = projection.y * canvas.clientHeight;
482
- return projection;
483
- });
484
- // get the min and max for all the coordinates so we can calculate the largest possible screen size
485
- const maxX = Math.max.apply(
486
- Math,
487
- coordinates.map(o => o.x)
488
- );
489
- const minX = Math.min.apply(
490
- Math,
491
- coordinates.map(o => o.x)
492
- );
493
- const maxY = Math.max.apply(
494
- Math,
495
- coordinates.map(o => o.y)
496
- );
497
- const minY = Math.min.apply(
498
- Math,
499
- coordinates.map(o => o.y)
500
- );
501
- // return a ClientRect from this
502
- return {
503
- width: maxX - minX,
504
- height: maxY - minY,
505
- left: minX,
506
- top: minY,
507
- right: maxX,
508
- bottom: maxY,
509
- } as ClientRect;
510
- };
511
-
512
- export {
513
- getRootNode,
514
- mapToDottedNodes,
515
- getDottedPathForNode,
516
- cloneTransformNode,
517
- cloneNodeWithParents,
518
- cloneTransformNodeMaterial,
519
- injectNodeMetadata,
520
- assertTransformNode,
521
- activateTransformNode,
522
- deactivateTransformNode,
523
- enableNodeWithParents,
524
- disableNodeWithParents,
525
- transformTransformNode,
526
- setMaterial,
527
- setSourceNodeMaterial,
528
- setMaterialColor,
529
- setMaterialTexture,
530
- setMaterialMetallness,
531
- setMaterialRoughness,
532
- addToHighlightLayer,
533
- removeFromHighlightLayer,
534
- setReceiveShadows,
535
- addToShadowGenerator,
536
- removeFromShadowGenerator,
537
- getClientRectFromMesh,
538
- };
1
+ import { EnvironmentHelper } from '@babylonjs/core/Helpers/environmentHelper';
2
+ import { PhotoDome } from '@babylonjs/core/Helpers/photoDome';
3
+ import { HighlightLayer } from '@babylonjs/core/Layers/highlightLayer';
4
+ import { Light } from '@babylonjs/core/Lights/light';
5
+ import { ShadowGenerator } from '@babylonjs/core/Lights/Shadows/shadowGenerator';
6
+ import { Material } from '@babylonjs/core/Materials/material';
7
+ import { PBRMaterial } from '@babylonjs/core/Materials/PBR/pbrMaterial';
8
+ import { StandardMaterial } from '@babylonjs/core/Materials/standardMaterial';
9
+ import { CubeTexture } from '@babylonjs/core/Materials/Textures/cubeTexture';
10
+ import { Axis } from '@babylonjs/core/Maths/math.axis';
11
+ import { Color3, Color4 } from '@babylonjs/core/Maths/math.color';
12
+ import { Quaternion, Vector3 } from '@babylonjs/core/Maths/math.vector';
13
+ import { AbstractMesh } from '@babylonjs/core/Meshes/abstractMesh';
14
+ import { InstancedMesh } from '@babylonjs/core/Meshes/instancedMesh';
15
+ import { Mesh } from '@babylonjs/core/Meshes/mesh';
16
+ import { TransformNode } from '@babylonjs/core/Meshes/transformNode';
17
+ import { Tools } from '@babylonjs/core/Misc/tools';
18
+ import { Node } from '@babylonjs/core/node';
19
+ import { Scene } from '@babylonjs/core/scene';
20
+ import { Nullable } from '@babylonjs/core/types';
21
+ import { defaultEnvHelperColor, defaultSceneClearColor } from '../internal/sceneSetup';
22
+ import { cloneDeep, get, has, merge } from 'lodash-es';
23
+ import { DottedPath } from '../classes/dottedPath';
24
+
25
+ const backgroundDomeName = 'BackgroundDome_ViewerGenerated';
26
+ const envHelperMetadataName = 'viewerEnvHelper';
27
+
28
+ /**
29
+ * @param node
30
+ * @return Node
31
+ */
32
+ const getRootNode = function (node: Node): Node {
33
+ let _node = node;
34
+ while (_node.parent) {
35
+ _node = _node.parent;
36
+ }
37
+ return _node;
38
+ };
39
+
40
+ /**
41
+ * @param nodes
42
+ * @param predicate
43
+ * @return Map<DottedPath, T>
44
+ */
45
+ const mapToDottedNodes = function <T>(nodes: Node[], predicate?: (node: Node) => boolean): Map<DottedPath, T> {
46
+ const map = new Map<DottedPath, T>();
47
+ const addNodes = function (_node: Node) {
48
+ if (predicate && predicate(_node)) {
49
+ map.set(_node.metadata.dottedPath, _node as any);
50
+ }
51
+ _node.getChildren().forEach(child => {
52
+ addNodes(child);
53
+ });
54
+ };
55
+ nodes.forEach(node => {
56
+ addNodes(node);
57
+ });
58
+ return map;
59
+ };
60
+
61
+ /**
62
+ * @param node
63
+ * @return DottedPath
64
+ */
65
+ const getDottedPathForNode = function (node: Node): DottedPath {
66
+ const dottedPath = DottedPath.create(node.name);
67
+ let _parent = node;
68
+ while (_parent.parent) {
69
+ _parent = _parent.parent;
70
+ dottedPath.unshiftPart(_parent.name);
71
+ }
72
+ return dottedPath;
73
+ };
74
+
75
+ /**
76
+ * @param node
77
+ * @param predicate
78
+ * @param deep
79
+ * @return TransformNode | null
80
+ */
81
+ const cloneTransformNode = function (
82
+ node: TransformNode,
83
+ predicate?: (node: TransformNode) => boolean,
84
+ deep: boolean = true
85
+ ): TransformNode | null {
86
+ if (predicate && !predicate(node)) {
87
+ return null;
88
+ }
89
+ const clone = node.clone(node.name, node.parent, true);
90
+ if (clone) {
91
+ clone.metadata = cloneDeep(node.metadata);
92
+ }
93
+ if (deep) {
94
+ const children = node.getChildTransformNodes(true);
95
+ children.forEach(child => {
96
+ const clonedChild = cloneTransformNode(child, predicate, deep);
97
+ if (clonedChild) {
98
+ clonedChild.parent = clone;
99
+ }
100
+ });
101
+ }
102
+ return clone;
103
+ };
104
+
105
+ /**
106
+ * @param node
107
+ */
108
+ const cloneNodeWithParents = function (node: Node | null): Node | null {
109
+ let clone = null;
110
+ if (node instanceof TransformNode) {
111
+ clone = node.clone(node.name, cloneNodeWithParents(node.parent) as Nullable<Node>, true);
112
+ } else if (node instanceof Light) {
113
+ clone = node.clone(node.name, cloneNodeWithParents(node.parent) as Nullable<Node>);
114
+ } else if (node) {
115
+ throw new Error(`Cloning of "${node?.constructor.name}" is not implemented (yet).`);
116
+ }
117
+ return clone;
118
+ };
119
+
120
+ /**
121
+ * @param node
122
+ * @param deep
123
+ * @param prefix
124
+ * @return TransformNode
125
+ */
126
+ const cloneTransformNodeMaterial = function (
127
+ node: TransformNode,
128
+ prefix: DottedPathArgument = '',
129
+ deep: boolean = true
130
+ ): TransformNode {
131
+ if (node instanceof AbstractMesh && node.material) {
132
+ const newMatName = DottedPath.create(prefix).addParts([node.material.name, 'clone', node.uniqueId.toString()]);
133
+ node.material = node.material.clone(newMatName.path);
134
+ }
135
+ if (deep) {
136
+ const children = node.getChildTransformNodes(true);
137
+ children.forEach(child => cloneTransformNodeMaterial(child, prefix, deep));
138
+ }
139
+ return node;
140
+ };
141
+
142
+ /**
143
+ * @param node
144
+ * @param deep
145
+ * @param metadata
146
+ */
147
+ const injectNodeMetadata = function (node: Node, metadata: {}, deep: boolean = true) {
148
+ node.metadata = merge({}, node.metadata, metadata);
149
+ if (deep && node instanceof TransformNode) {
150
+ const children = node.getChildTransformNodes(true);
151
+ children.forEach(child => injectNodeMetadata(child, metadata, deep));
152
+ }
153
+ };
154
+
155
+ /**
156
+ * @param node
157
+ * @param assertCallable
158
+ * @param callableParameters
159
+ * @param deep
160
+ */
161
+ const assertTransformNode = function (
162
+ node: TransformNode,
163
+ assertCallable: CallableFunction,
164
+ callableParameters: any[] = [],
165
+ deep: boolean = true
166
+ ) {
167
+ assertCallable(node, ...callableParameters);
168
+ if (deep) {
169
+ const children = node.getChildTransformNodes(true);
170
+ children.forEach(child => assertTransformNode(child, assertCallable, callableParameters, deep));
171
+ }
172
+ };
173
+
174
+ /**
175
+ * @param node
176
+ * @param deep
177
+ */
178
+ const activateTransformNode = function (node: TransformNode, deep: boolean = true) {
179
+ node.setEnabled(true);
180
+ /*
181
+ if( node instanceof AbstractMesh ) {
182
+ node.visibility = 1;
183
+ node.isPickable = true;
184
+ }
185
+ */
186
+ if (deep) {
187
+ node.getChildTransformNodes(true).forEach(child => activateTransformNode(child, deep));
188
+ }
189
+ };
190
+
191
+ /**
192
+ * @param node
193
+ * @param deep
194
+ */
195
+ const deactivateTransformNode = function (node: TransformNode, deep: boolean = true) {
196
+ node.setEnabled(false);
197
+ /*
198
+ if( node instanceof AbstractMesh ) {
199
+ node.visibility = 0;
200
+ node.isPickable = false;
201
+ }
202
+ */
203
+ if (deep) {
204
+ node.getChildTransformNodes(true).forEach(child => deactivateTransformNode(child, deep));
205
+ }
206
+ };
207
+
208
+ /**
209
+ * @param node
210
+ */
211
+ const enableNodeWithParents = function (node: Node) {
212
+ node.setEnabled(true);
213
+ if (node.parent) {
214
+ enableNodeWithParents(node.parent);
215
+ }
216
+ };
217
+
218
+ /**
219
+ * @param node
220
+ */
221
+ const disableNodeWithParents = function (node: Node) {
222
+ node.setEnabled(false);
223
+ if (node.parent) {
224
+ disableNodeWithParents(node.parent);
225
+ }
226
+ };
227
+
228
+ /**
229
+ * Applies a {@link TransformationDefinition} consecutively to ensure dependencies in positioning etc.
230
+ * @param node
231
+ * @param transformation
232
+ */
233
+ const transformTransformNode = function (node: TransformNode, transformation: TransformationDefinition) {
234
+ // scaling
235
+ if (!has(node.metadata, 'scaling.initial')) {
236
+ injectNodeMetadata(node, { 'scaling.initial': node.scaling }, false);
237
+ }
238
+ const initialScaling = get(node.metadata, 'scaling.initial') as Vector3;
239
+ node.scaling = initialScaling.multiply(transformation.scaling);
240
+ // position
241
+ if (!has(node.metadata, 'position.initial')) {
242
+ injectNodeMetadata(node, { 'position.initial': node.absolutePosition.clone() }, false);
243
+ }
244
+ const initialPosition = get(node.metadata, 'position.initial') as Vector3;
245
+ node.setAbsolutePosition(initialPosition.add(transformation.position).multiply(transformation.scaling));
246
+ // rotation
247
+ if (!has(node.metadata, 'rotation.initial')) {
248
+ let rotationQuaternion = node.rotationQuaternion;
249
+ if (!rotationQuaternion) {
250
+ rotationQuaternion = Quaternion.RotationYawPitchRoll(node.rotation.x, node.rotation.y, node.rotation.z);
251
+ }
252
+ injectNodeMetadata(node, { 'rotation.initial': rotationQuaternion.asArray() }, false);
253
+ }
254
+ const initialRotationQuaternion = Quaternion.FromArray(get(node.metadata, 'rotation.initial') as []);
255
+ node.rotationQuaternion = initialRotationQuaternion;
256
+ node.rotateAround(Vector3.Zero(), Axis.X, transformation.rotation.x);
257
+ node.rotateAround(Vector3.Zero(), Axis.Y, transformation.rotation.y);
258
+ node.rotateAround(Vector3.Zero(), Axis.Z, transformation.rotation.z);
259
+ node.computeWorldMatrix(true);
260
+ };
261
+
262
+ /**
263
+ * Apply changes of environment (background texture, etc.) consecutively in order to avoid dependency related issues.
264
+ * @param scene
265
+ * @param envDef
266
+ */
267
+ const changeEnvironment = function (scene: Scene, envDef: EnvironmentDefinition) {
268
+ // issue warning if both background texture and usedefault are set
269
+ if (envDef.environmentUseDefault && envDef.environmentBackground) {
270
+ console.warn(
271
+ `!!! Warning !!! Spec parameter \'environment.useDefaultEnvironment\' is being overruled by \'environment.background\'.`
272
+ );
273
+ }
274
+
275
+ const useDefaultEnv = envDef.environmentUseDefault && !envDef.environmentBackground;
276
+
277
+ // 1) set ENVIRONMENT_COLOR
278
+ scene.clearColor = envDef.environmentColor
279
+ ? Color4.FromColor3(envDef.environmentColor)
280
+ : useDefaultEnv
281
+ ? defaultEnvHelperColor
282
+ : defaultSceneClearColor;
283
+
284
+ // 2) dispose existing & set new ENVIRONMENT (==texture)
285
+ const curEnvTexture = scene.environmentTexture as Nullable<CubeTexture>;
286
+ const envTextureChanged = envDef.environment !== curEnvTexture?.url;
287
+
288
+ if (curEnvTexture && (!envDef.environment || envTextureChanged)) {
289
+ curEnvTexture.dispose();
290
+ }
291
+
292
+ const rotation = envDef.environmentRotation !== undefined ? Tools.ToRadians(envDef.environmentRotation) : 0;
293
+ if (envDef.environment && envTextureChanged) {
294
+ const envTexture = CubeTexture.CreateFromPrefilteredData(envDef.environment as string, scene);
295
+ envTexture.rotationY = rotation;
296
+ scene.environmentTexture = envTexture;
297
+ } else if (curEnvTexture && curEnvTexture.rotationY !== rotation) {
298
+ curEnvTexture.rotationY = rotation;
299
+ }
300
+
301
+ // 3) dispose existing & set new ENVIRONMENT_BACKGROUND
302
+ const curDome = scene.getNodeByName(backgroundDomeName) as undefined | PhotoDome;
303
+ const backgroundUrlChanged = envDef.environmentBackground !== curDome?.texture.url;
304
+
305
+ if (curDome && (!envDef.environmentBackground || backgroundUrlChanged)) {
306
+ curDome.dispose();
307
+ }
308
+
309
+ const rotationPhotoDome = -1 * rotation;
310
+ if (envDef.environmentBackground && backgroundUrlChanged) {
311
+ const textureUrl = envDef.environmentBackground;
312
+ const dome = new PhotoDome(backgroundDomeName, textureUrl, { resolution: 32, size: 450 }, scene);
313
+ // Rotate submesh to get them in line with environment texture
314
+ dome.getChildMeshes(true)[0].rotation.y = Tools.ToRadians(90);
315
+ dome.rotation.y = rotationPhotoDome;
316
+ } else if (curDome && curDome.rotation.y !== rotationPhotoDome) {
317
+ curDome.rotation.y = rotationPhotoDome;
318
+ }
319
+
320
+ // 4) dispose existing & set new ENVIRONMENT_USEDEFAULT (only if no background is set)
321
+ const curEnvHelper = scene.metadata?.[envHelperMetadataName] as undefined | EnvironmentHelper;
322
+
323
+ if (curEnvHelper && (!envDef.environmentUseDefault || envDef.environmentBackground)) {
324
+ curEnvHelper.dispose();
325
+ }
326
+
327
+ if (useDefaultEnv && !curEnvHelper) {
328
+ const envHelper = scene.createDefaultEnvironment({ sizeAuto: true });
329
+ envHelper?.setMainColor(Color3.FromArray(scene.clearColor.asArray()));
330
+ if (envHelper) {
331
+ scene.metadata = merge({}, scene.metadata, { [envHelperMetadataName]: envHelper });
332
+ }
333
+ }
334
+
335
+ // 5) set ENVIRONMENT_INTENSITY
336
+ if (envDef.environmentIntensity !== undefined) {
337
+ scene.environmentIntensity = envDef.environmentIntensity;
338
+ }
339
+ };
340
+
341
+ /**
342
+ * @param node
343
+ * @param material
344
+ * @param deep
345
+ */
346
+ const setMaterial = function (node: TransformNode, material: Material, deep: boolean = true) {
347
+ if (node instanceof AbstractMesh) {
348
+ node.material = material;
349
+ }
350
+ if (deep) {
351
+ node.getChildTransformNodes(true).forEach(child => setMaterial(child, material, deep));
352
+ }
353
+ };
354
+
355
+ /**
356
+ * !!! Warning !!!
357
+ * This function is not public API. Whilst it can help solving certain problems, it only works reliably in well defined
358
+ * situations and can cause unwanted side effects under some conditions. Use carefully at your own risk!
359
+ *
360
+ * See https://combeenation.myjetbrains.com/youtrack/issue/CB-5906 for further details regarding this warning.
361
+ *
362
+ * Set material of an instanced meshes source mesh.
363
+ * Changes the material of all instanced meshes which have the same source mesh.
364
+ *
365
+ * @param node
366
+ * @param material
367
+ * @param deep
368
+ *
369
+ * @ignore
370
+ */
371
+ const setSourceNodeMaterial = function (node: TransformNode, material: Material, deep: boolean = true) {
372
+ const warn = ` You're using "setSourceNodeMaterial" which is not public API.
373
+ Whilst it can help solving certain problems, it only works reliably in well defined situations and can cause unwanted side effects under some conditions.
374
+ Use carefully at your own risk!`;
375
+ console.warn(`!!! Warning !!!\n${warn}`);
376
+
377
+ if (node instanceof InstancedMesh) {
378
+ node.sourceMesh.material = material;
379
+ }
380
+ if (deep) {
381
+ node.getChildTransformNodes(true).forEach(child => setSourceNodeMaterial(child, material, deep));
382
+ }
383
+ };
384
+
385
+ /**
386
+ * @param node
387
+ * @param color
388
+ * @param deep
389
+ */
390
+ const setMaterialColor = function (node: TransformNode, color: Color3, deep: boolean = true) {
391
+ if (node instanceof AbstractMesh && node.material) {
392
+ const materialCls = node.material.getClassName();
393
+ switch (materialCls) {
394
+ case 'PBRMaterial':
395
+ (node.material as PBRMaterial).albedoColor = color.toLinearSpace();
396
+ break;
397
+ case 'StandardMaterial':
398
+ (node.material as StandardMaterial).diffuseColor = color;
399
+ break;
400
+ default:
401
+ throw new Error(`Setting color for material of instance "${materialCls}" not implemented (yet).`);
402
+ }
403
+ }
404
+ if (deep) {
405
+ node.getChildTransformNodes(true).forEach(child => setMaterialColor(child, color, deep));
406
+ }
407
+ };
408
+
409
+ /**
410
+ * @param node
411
+ * @param texture
412
+ * @param deep
413
+ */
414
+ const setMaterialTexture = function (node: TransformNode, texture: Texture, deep: boolean = true) {
415
+ if (node instanceof AbstractMesh && node.material) {
416
+ const materialCls = node.material.getClassName();
417
+ switch (materialCls) {
418
+ case 'PBRMaterial':
419
+ (node.material as PBRMaterial).albedoTexture = texture;
420
+ break;
421
+ case 'StandardMaterial':
422
+ (node.material as StandardMaterial).diffuseTexture = texture;
423
+ break;
424
+ default:
425
+ throw new Error(`Setting texture for material of instance "${materialCls}" not implemented (yet).`);
426
+ }
427
+ }
428
+ if (deep) {
429
+ node.getChildTransformNodes(true).forEach(child => setMaterialTexture(child, texture, deep));
430
+ }
431
+ };
432
+
433
+ /**
434
+ * @param node
435
+ * @param metallness
436
+ * @param deep
437
+ */
438
+ const setMaterialMetallness = function (node: TransformNode, metallness: number, deep: boolean = true) {
439
+ if (node instanceof AbstractMesh && node.material) {
440
+ const materialCls = node.material.getClassName();
441
+ switch (materialCls) {
442
+ case 'PBRMaterial':
443
+ (node.material as PBRMaterial).metallic = metallness;
444
+ break;
445
+ default:
446
+ throw new Error(`Setting metallness for material of instance "${materialCls}" not implemented (yet).`);
447
+ }
448
+ }
449
+ if (deep) {
450
+ node.getChildTransformNodes(true).forEach(child => setMaterialMetallness(child, metallness, deep));
451
+ }
452
+ };
453
+
454
+ /**
455
+ * @param node
456
+ * @param roughness
457
+ * @param deep
458
+ */
459
+ const setMaterialRoughness = function (node: TransformNode, roughness: number, deep: boolean = true) {
460
+ if (node instanceof AbstractMesh && node.material) {
461
+ const materialCls = node.material.getClassName();
462
+ switch (materialCls) {
463
+ case 'PBRMaterial':
464
+ (node.material as PBRMaterial).roughness = roughness;
465
+ break;
466
+ case 'StandardMaterial':
467
+ (node.material as StandardMaterial).roughness = roughness;
468
+ break;
469
+ default:
470
+ throw new Error(`Setting roughness for material of instance "${materialCls}" not implemented (yet).`);
471
+ }
472
+ }
473
+ if (deep) {
474
+ node.getChildTransformNodes(true).forEach(child => setMaterialRoughness(child, roughness, deep));
475
+ }
476
+ };
477
+
478
+ /**
479
+ * @param node
480
+ * @param layer
481
+ * @param color
482
+ * @param deep
483
+ */
484
+ const addToHighlightLayer = function (layer: HighlightLayer, color: Color3, node: TransformNode, deep: boolean = true) {
485
+ if (node instanceof AbstractMesh) {
486
+ layer.addMesh(node as Mesh, color);
487
+ }
488
+ if (deep) {
489
+ node.getChildTransformNodes(true).forEach(child => addToHighlightLayer(layer, color, child, deep));
490
+ }
491
+ };
492
+
493
+ /**
494
+ * @param node
495
+ * @param layer
496
+ * @param deep
497
+ */
498
+ const removeFromHighlightLayer = function (layer: HighlightLayer, node: TransformNode, deep: boolean = true) {
499
+ if (node instanceof AbstractMesh) {
500
+ layer.removeMesh(node as Mesh);
501
+ }
502
+ if (deep) {
503
+ node.getChildTransformNodes(true).forEach(child => removeFromHighlightLayer(layer, child, deep));
504
+ }
505
+ };
506
+
507
+ /**
508
+ * @param node
509
+ * @param receiveShadows
510
+ * @param deep
511
+ */
512
+ const setReceiveShadows = function (node: TransformNode, receiveShadows: boolean, deep: boolean = true) {
513
+ if (node instanceof AbstractMesh) {
514
+ node.receiveShadows = receiveShadows;
515
+ }
516
+ if (deep) {
517
+ node.getChildTransformNodes(true).forEach(child => setReceiveShadows(child, receiveShadows, deep));
518
+ }
519
+ };
520
+
521
+ /**
522
+ * @param node
523
+ * @param generator
524
+ * @param deep
525
+ */
526
+ const addToShadowGenerator = function (generator: ShadowGenerator, node: TransformNode, deep: boolean = true) {
527
+ if (node instanceof AbstractMesh) {
528
+ // We have to remove the node because there's no duplicate check in babylon
529
+ generator.removeShadowCaster(node, false);
530
+ generator.addShadowCaster(node, false);
531
+ }
532
+ if (deep) {
533
+ node.getChildTransformNodes(true).forEach(child => addToShadowGenerator(generator, child, deep));
534
+ }
535
+ };
536
+
537
+ /**
538
+ * @param node
539
+ * @param generator
540
+ * @param deep
541
+ */
542
+ const removeFromShadowGenerator = function (generator: ShadowGenerator, node: TransformNode, deep: boolean = true) {
543
+ if (node instanceof AbstractMesh) {
544
+ generator.removeShadowCaster(node, false);
545
+ }
546
+ if (deep) {
547
+ node.getChildTransformNodes(true).forEach(child => removeFromShadowGenerator(generator, child, deep));
548
+ }
549
+ };
550
+
551
+ /**
552
+ * https://forum.babylonjs.com/t/get-mesh-bounding-box-position-and-size-in-2d-screen-coordinates/1058/3
553
+ * @param mesh
554
+ * @param scene
555
+ * @param canvas
556
+ */
557
+ const getClientRectFromMesh = function (mesh: AbstractMesh, scene: Scene, canvas: HTMLCanvasElement): ClientRect {
558
+ // get bounding box of the mesh
559
+ const meshVectors = mesh.getBoundingInfo().boundingBox.vectors;
560
+ // get the matrix and viewport needed to project the vectors onto the screen
561
+ const worldMatrix = mesh.getWorldMatrix();
562
+ const transformMatrix = scene.getTransformMatrix();
563
+ const viewport = scene.activeCamera!.viewport;
564
+ // loop though all the vectors and project them against the current camera viewport to get a set of coordinates
565
+ const coordinates = meshVectors.map(vector => {
566
+ const projection = Vector3.Project(vector, worldMatrix, transformMatrix, viewport);
567
+ projection.x = projection.x * canvas.clientWidth;
568
+ projection.y = projection.y * canvas.clientHeight;
569
+ return projection;
570
+ });
571
+ // get the min and max for all the coordinates so we can calculate the largest possible screen size
572
+ const maxX = Math.max.apply(
573
+ Math,
574
+ coordinates.map(o => o.x)
575
+ );
576
+ const minX = Math.min.apply(
577
+ Math,
578
+ coordinates.map(o => o.x)
579
+ );
580
+ const maxY = Math.max.apply(
581
+ Math,
582
+ coordinates.map(o => o.y)
583
+ );
584
+ const minY = Math.min.apply(
585
+ Math,
586
+ coordinates.map(o => o.y)
587
+ );
588
+ // return a ClientRect from this
589
+ return {
590
+ width: maxX - minX,
591
+ height: maxY - minY,
592
+ left: minX,
593
+ top: minY,
594
+ right: maxX,
595
+ bottom: maxY,
596
+ } as ClientRect;
597
+ };
598
+
599
+ export {
600
+ getRootNode,
601
+ mapToDottedNodes,
602
+ getDottedPathForNode,
603
+ cloneTransformNode,
604
+ cloneNodeWithParents,
605
+ cloneTransformNodeMaterial,
606
+ injectNodeMetadata,
607
+ assertTransformNode,
608
+ activateTransformNode,
609
+ deactivateTransformNode,
610
+ enableNodeWithParents,
611
+ disableNodeWithParents,
612
+ transformTransformNode,
613
+ setMaterial,
614
+ setSourceNodeMaterial,
615
+ setMaterialColor,
616
+ setMaterialTexture,
617
+ setMaterialMetallness,
618
+ setMaterialRoughness,
619
+ addToHighlightLayer,
620
+ removeFromHighlightLayer,
621
+ setReceiveShadows,
622
+ addToShadowGenerator,
623
+ removeFromShadowGenerator,
624
+ getClientRectFromMesh,
625
+ changeEnvironment,
626
+ backgroundDomeName,
627
+ envHelperMetadataName
628
+ };