@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,334 +1,334 @@
1
- import { PointLight } from '@babylonjs/core/Lights/pointLight';
2
- import { HemisphericLight } from '@babylonjs/core/Lights/hemisphericLight';
3
- import { Light } from '@babylonjs/core/Lights/light';
4
- import { ShadowLight } from '@babylonjs/core/Lights/shadowLight';
5
- import { ShadowGenerator } from '@babylonjs/core/Lights/Shadows/shadowGenerator';
6
- import '@babylonjs/core/Lights/Shadows/shadowGeneratorSceneComponent';
7
- import { Vector3 } from '@babylonjs/core/Maths/math.vector';
8
- import { TransformNode } from '@babylonjs/core/Meshes/transformNode';
9
- import '@babylonjs/loaders/glTF/2.0/Extensions/KHR_lights_punctual';
10
- import { get, isEmpty, isString, set } from 'lodash-es';
11
- import {
12
- cloneNodeWithParents,
13
- disableNodeWithParents,
14
- enableNodeWithParents,
15
- getRootNode,
16
- injectNodeMetadata,
17
- transformTransformNode,
18
- } from './../util/babylonHelper';
19
- import { DottedPath } from './dottedPath';
20
- import { Parameter } from './parameter';
21
- import { Variant } from './variant';
22
- import { VariantParameterizable } from './variantParameterizable';
23
-
24
- /**
25
- * A {@link ViewerLight} of a {@link Variant}. Acts as a container for BabylonJS lights. Lives only in the context of a
26
- * {@link Variant}.
27
- */
28
- export class ViewerLight extends VariantParameterizable {
29
- protected _light: Light | undefined;
30
-
31
- /**
32
- * Constructor.
33
- */
34
- protected constructor(public readonly variant: Variant, public readonly name: string) {
35
- super(variant, name);
36
- this.addParameterObservers();
37
- }
38
-
39
- /**
40
- * Creates a {@link ViewerLight} with given name.
41
- */
42
- public static async create(variant: Variant, name: string): Promise<ViewerLight> {
43
- const viewerLight = new ViewerLight(variant, name);
44
- viewerLight._light = await viewerLight.createBabylonLightFromDefinition(viewerLight.definition);
45
- return viewerLight;
46
- }
47
-
48
- /**
49
- * The wrapped Light.
50
- */
51
- get light(): Light {
52
- if (!this._light) {
53
- throw new Error(`Light for ViewerLight "${this.name}" has not been properly initialized.`);
54
- }
55
- return this._light!;
56
- }
57
-
58
- /**
59
- * The {@link DottedPath} in the built tree of {@link ViewerLight}s.
60
- * E.g. "_.top-1.sub-2.sub-sub-3.el-1"
61
- */
62
- get dottedPath(): DottedPath {
63
- return DottedPath.create(this.variant.dottedPath).addPart(this.name);
64
- }
65
-
66
- /**
67
- * The id representing a {@link DottedPath}.
68
- */
69
- get id(): string {
70
- const dottedPath = DottedPath.create(this.dottedPath);
71
- dottedPath.shiftPart(); // remove root
72
- return dottedPath.path;
73
- }
74
-
75
- /**
76
- * The {@link LightDefinition} of the {@link ViewerLight}.
77
- */
78
- get definition(): LightDefinition {
79
- const definition = this.variant.structureJson.lights![this.name];
80
- if (isString(definition)) {
81
- return {
82
- type: 'baked',
83
- path: definition,
84
- } as LightDefinition;
85
- }
86
- return definition as LightDefinition;
87
- }
88
-
89
- /**
90
- * The type of the {@link ViewerLight}'s light.
91
- */
92
- get type(): string {
93
- return this.light.constructor.name.replace(/light/i, '').toLowerCase();
94
- }
95
-
96
- /**
97
- * @see {@link VariantParameterizable.commitParameters}
98
- * @emit {@link Event.VIEWER_LIGHT_PARAMETER_COMMITTED}
99
- */
100
- public async commitParameters(parameters?: ParameterBag): Promise<VariantParameterizable> {
101
- return super.commitParameters(parameters);
102
- }
103
-
104
- /**
105
- * Adds the default {@link ParameterObserver}s which are called every time {@link commitParameters} is called.
106
- */
107
- protected addParameterObservers(): ViewerLight {
108
- this._parameterObservers.set(Parameter.VISIBLE, [
109
- async (light: ViewerLight, oldValue: ParameterValue, newValue: ParameterValue) => {
110
- let visible;
111
- try {
112
- visible = Parameter.parseBoolean(newValue);
113
- } catch (e) {
114
- return;
115
- }
116
- if (visible === true) {
117
- enableNodeWithParents(light.light);
118
- } else if (visible === false) {
119
- disableNodeWithParents(light.light);
120
- }
121
- },
122
- ]);
123
- this._parameterObservers.set(Parameter.INTENSITY, [
124
- async (light: ViewerLight, oldValue: ParameterValue, newValue: ParameterValue) => {
125
- set(light.light, 'intensity', Parameter.parseNumber(newValue));
126
- },
127
- ]);
128
- this._parameterObservers.set(Parameter.SCALING, [
129
- async (light: ViewerLight, oldValue: ParameterValue, newValue: ParameterValue) => {
130
- // we have to deal just with root nodes here due to relative impacts in a node tree
131
- const rootNode = getRootNode(light.light);
132
- if (rootNode instanceof TransformNode) {
133
- transformTransformNode(rootNode, {
134
- scaling: Parameter.parseScaling(newValue),
135
- position: Parameter.parseVector(light.inheritedParameters[Parameter.POSITION] || '(0, 0, 0)'),
136
- rotation: Parameter.parseRotation(light.inheritedParameters[Parameter.ROTATION] || '(0, 0, 0)'),
137
- });
138
- }
139
- },
140
- ]);
141
- this._parameterObservers.set(Parameter.POSITION, [
142
- async (light: ViewerLight, oldValue: ParameterValue, newValue: ParameterValue) => {
143
- // we have to deal just with root nodes here due to relative impacts in a node tree
144
- const rootNode = getRootNode(light.light);
145
- if (rootNode instanceof TransformNode) {
146
- transformTransformNode(rootNode, {
147
- scaling: Parameter.parseVector(light.inheritedParameters[Parameter.SCALING] || '(1, 1, 1)'),
148
- position: Parameter.parseVector(newValue),
149
- rotation: Parameter.parseRotation(light.inheritedParameters[Parameter.ROTATION] || '(0, 0, 0)'),
150
- });
151
- }
152
- },
153
- ]);
154
- this._parameterObservers.set(Parameter.ROTATION, [
155
- async (light: ViewerLight, oldValue: ParameterValue, newValue: ParameterValue) => {
156
- // we have to deal just with root nodes here due to relative impacts in a node tree
157
- const rootNode = getRootNode(light.light);
158
- if (rootNode instanceof TransformNode) {
159
- transformTransformNode(rootNode, {
160
- scaling: Parameter.parseVector(light.inheritedParameters[Parameter.SCALING] || '(1, 1, 1)'),
161
- position: Parameter.parseVector(light.inheritedParameters[Parameter.POSITION] || '(0, 0, 0)'),
162
- rotation: Parameter.parseRotation(newValue),
163
- });
164
- }
165
- },
166
- ]);
167
- this._parameterObservers.set(Parameter.DIRECTION, [
168
- async (light: ViewerLight, oldValue: ParameterValue, newValue: ParameterValue) => {
169
- if (
170
- (light.light instanceof ShadowLight && !(light.light instanceof PointLight)) ||
171
- light.light instanceof HemisphericLight
172
- ) {
173
- set(light.light, 'direction', Parameter.parseVector(newValue));
174
- }
175
- },
176
- ]);
177
- this._parameterObservers.set(Parameter.ANGLE, [
178
- async (light: ViewerLight, oldValue: ParameterValue, newValue: ParameterValue) => {
179
- if (light.light.getClassName() === 'SpotLight') {
180
- set(light.light, 'angle', Parameter.parseNumber(newValue));
181
- }
182
- },
183
- ]);
184
- this._parameterObservers.set(Parameter.EXPONENT, [
185
- async (light: ViewerLight, oldValue: ParameterValue, newValue: ParameterValue) => {
186
- if (light.light.getClassName() === 'SpotLight') {
187
- set(light.light, 'exponent', Parameter.parseNumber(newValue));
188
- }
189
- },
190
- ]);
191
- this._parameterObservers.set(Parameter.DIFFUSE, [
192
- async (light: ViewerLight, oldValue: ParameterValue, newValue: ParameterValue) => {
193
- set(light.light, 'diffuse', Parameter.parseColor(newValue));
194
- },
195
- ]);
196
- this._parameterObservers.set(Parameter.SPECULAR, [
197
- async (light: ViewerLight, oldValue: ParameterValue, newValue: ParameterValue) => {
198
- set(light.light, 'specular', Parameter.parseColor(newValue));
199
- },
200
- ]);
201
- return this;
202
- }
203
-
204
- /**
205
- * @param definition
206
- * @protected
207
- */
208
- protected async createBabylonLightFromDefinition(definition: LightDefinition): Promise<Light> {
209
- const parameters = Parameter.parseFromDeclarations(Parameter.declarations, this.inheritedParameters);
210
- const scene = this.variant.viewer.scene;
211
- let lightId = this.id;
212
- let babylonLight;
213
- switch (definition.type) {
214
- case 'baked':
215
- if (!definition['path']) {
216
- throw new Error(`The light "${lightId}" of type "${definition.type}" needs a "path".`);
217
- }
218
- const bakedLight = this.variant.inheritedLights.find(l => l.metadata.dottedPath.path === definition['path']);
219
- if (bakedLight) {
220
- lightId = bakedLight.metadata.dottedPath.clone().unshiftPart(this.id).path;
221
- babylonLight = cloneNodeWithParents(bakedLight) as Light;
222
- babylonLight!.name = lightId;
223
- babylonLight!.id = lightId;
224
- } else {
225
- throw new Error(`No light found for path "${definition['path']}" in ViewerLight "${lightId}".`);
226
- }
227
- break;
228
- case 'hemispheric':
229
- if (!parameters['direction']) {
230
- throw new Error(`The ViewerLight "${lightId}" of type "${definition.type}" needs a "direction".`);
231
- }
232
- // @ts-ignore
233
- const hemisphericLightModule = await import(
234
- /* webpackChunkName: "hemispheric-light" */ '@babylonjs/core/Lights/hemisphericLight'
235
- );
236
- babylonLight = new hemisphericLightModule.HemisphericLight(lightId, parameters['direction'], scene);
237
- break;
238
- case 'point':
239
- // @ts-ignore
240
- const pointLightModule = await import(
241
- /* webpackChunkName: "point-light" */ '@babylonjs/core/Lights/pointLight'
242
- );
243
- babylonLight = new pointLightModule.PointLight(
244
- lightId,
245
- Vector3.Zero(), // position is set via parent TransformNode
246
- scene
247
- );
248
- break;
249
- case 'directional':
250
- if (!parameters['direction']) {
251
- throw new Error(`The ViewerLight "${lightId}" of type "${definition.type}" needs a "direction".`);
252
- }
253
- // @ts-ignore
254
- const directionalLightModule = await import(
255
- /* webpackChunkName: "directional-light" */ '@babylonjs/core/Lights/directionalLight'
256
- );
257
- babylonLight = new directionalLightModule.DirectionalLight(lightId, parameters['direction'], scene);
258
- break;
259
- case 'spot':
260
- if (!parameters['direction']) {
261
- throw new Error(`The ViewerLight "${lightId}" of type "${definition.type}" needs a "direction".`);
262
- }
263
- if (!parameters['angle']) {
264
- throw new Error(`A ViewerLight of type "${definition.type}" needs an "angle".`);
265
- }
266
- if (!parameters['exponent']) {
267
- throw new Error(`The ViewerLight "${lightId}" of type "${definition.type}" needs an "exponent".`);
268
- }
269
- // @ts-ignore
270
- const spotLightModule = await import(/* webpackChunkName: "spot-light" */ '@babylonjs/core/Lights/spotLight');
271
- babylonLight = new spotLightModule.SpotLight(
272
- lightId,
273
- Vector3.Zero(), // position is set via parent TransformNode
274
- parameters['direction'],
275
- parameters['angle'],
276
- parameters['exponent'],
277
- scene
278
- );
279
- break;
280
- default:
281
- throw new Error(`The type "${definition.type}" for ViewerLight "${lightId}" is not implemented (yet).`);
282
- }
283
- if (!babylonLight) {
284
- throw new Error(
285
- `The Light for ViewerLight "${lightId}" of type "${definition.type}" could no be created ` + `or found.`
286
- );
287
- }
288
- if (!babylonLight.parent) {
289
- // Create pseudo parent since lights do not implement mutations like "rotation" by itself.
290
- babylonLight.parent = new TransformNode('__light__', this.variant.viewer.scene, true);
291
- }
292
- injectNodeMetadata(babylonLight.parent, {
293
- variant: this.variant,
294
- variantParameterizable: this,
295
- });
296
- // disable/hide by default
297
- disableNodeWithParents(babylonLight);
298
- // process shadow generator
299
- const shadowGeneratorDefinition = get(definition, 'shadowGenerator') as ShadowGeneratorDefinition;
300
- if (!isEmpty(shadowGeneratorDefinition)) {
301
- if (!(babylonLight instanceof ShadowLight)) {
302
- throw new Error(
303
- `Using a ShadowGenerator with light type "${definition.type}" is not supported for ` +
304
- `"${lightId}". Use lights deriving from ShadowLight.`
305
- );
306
- }
307
- await this.processShadowGenerator(babylonLight, shadowGeneratorDefinition);
308
- }
309
- return babylonLight;
310
- }
311
-
312
- /**
313
- * @param babylonLight
314
- * @param definition
315
- * @protected
316
- */
317
- protected async processShadowGenerator(
318
- babylonLight: ShadowLight,
319
- definition: ShadowGeneratorDefinition
320
- ): Promise<ShadowGenerator> {
321
- const parameterDeclarations: ParameterDeclarations = {};
322
- // define declarations here if needed in future
323
- const parameterBag = definition as {} as ParameterBag;
324
- const parameters = Parameter.parseFromDeclarations(parameterDeclarations, parameterBag);
325
- const shadowGenerator = new ShadowGenerator(parameters['mapSize'], babylonLight);
326
- for (const parameter in parameters) {
327
- if (parameter === 'mapSize') {
328
- continue;
329
- }
330
- set(shadowGenerator, parameter, get(parameters, parameter));
331
- }
332
- return shadowGenerator;
333
- }
334
- }
1
+ import { PointLight } from '@babylonjs/core/Lights/pointLight';
2
+ import { HemisphericLight } from '@babylonjs/core/Lights/hemisphericLight';
3
+ import { Light } from '@babylonjs/core/Lights/light';
4
+ import { ShadowLight } from '@babylonjs/core/Lights/shadowLight';
5
+ import { ShadowGenerator } from '@babylonjs/core/Lights/Shadows/shadowGenerator';
6
+ import '@babylonjs/core/Lights/Shadows/shadowGeneratorSceneComponent';
7
+ import { Vector3 } from '@babylonjs/core/Maths/math.vector';
8
+ import { TransformNode } from '@babylonjs/core/Meshes/transformNode';
9
+ import '@babylonjs/loaders/glTF/2.0/Extensions/KHR_lights_punctual';
10
+ import { get, isEmpty, isString, set } from 'lodash-es';
11
+ import {
12
+ cloneNodeWithParents,
13
+ disableNodeWithParents,
14
+ enableNodeWithParents,
15
+ getRootNode,
16
+ injectNodeMetadata,
17
+ transformTransformNode,
18
+ } from './../util/babylonHelper';
19
+ import { DottedPath } from './dottedPath';
20
+ import { Parameter } from './parameter';
21
+ import { Variant } from './variant';
22
+ import { VariantParameterizable } from './variantParameterizable';
23
+
24
+ /**
25
+ * A {@link ViewerLight} of a {@link Variant}. Acts as a container for BabylonJS lights. Lives only in the context of a
26
+ * {@link Variant}.
27
+ */
28
+ export class ViewerLight extends VariantParameterizable {
29
+ protected _light: Light | undefined;
30
+
31
+ /**
32
+ * Constructor.
33
+ */
34
+ protected constructor(public readonly variant: Variant, public readonly name: string) {
35
+ super(variant, name);
36
+ this.addParameterObservers();
37
+ }
38
+
39
+ /**
40
+ * Creates a {@link ViewerLight} with given name.
41
+ */
42
+ public static async create(variant: Variant, name: string): Promise<ViewerLight> {
43
+ const viewerLight = new ViewerLight(variant, name);
44
+ viewerLight._light = await viewerLight.createBabylonLightFromDefinition(viewerLight.definition);
45
+ return viewerLight;
46
+ }
47
+
48
+ /**
49
+ * The wrapped Light.
50
+ */
51
+ get light(): Light {
52
+ if (!this._light) {
53
+ throw new Error(`Light for ViewerLight "${this.name}" has not been properly initialized.`);
54
+ }
55
+ return this._light!;
56
+ }
57
+
58
+ /**
59
+ * The {@link DottedPath} in the built tree of {@link ViewerLight}s.
60
+ * E.g. "_.top-1.sub-2.sub-sub-3.el-1"
61
+ */
62
+ get dottedPath(): DottedPath {
63
+ return DottedPath.create(this.variant.dottedPath).addPart(this.name);
64
+ }
65
+
66
+ /**
67
+ * The id representing a {@link DottedPath}.
68
+ */
69
+ get id(): string {
70
+ const dottedPath = DottedPath.create(this.dottedPath);
71
+ dottedPath.shiftPart(); // remove root
72
+ return dottedPath.path;
73
+ }
74
+
75
+ /**
76
+ * The {@link LightDefinition} of the {@link ViewerLight}.
77
+ */
78
+ get definition(): LightDefinition {
79
+ const definition = this.variant.structureJson.lights![this.name];
80
+ if (isString(definition)) {
81
+ return {
82
+ type: 'baked',
83
+ path: definition,
84
+ } as LightDefinition;
85
+ }
86
+ return definition as LightDefinition;
87
+ }
88
+
89
+ /**
90
+ * The type of the {@link ViewerLight}'s light.
91
+ */
92
+ get type(): string {
93
+ return this.light.constructor.name.replace(/light/i, '').toLowerCase();
94
+ }
95
+
96
+ /**
97
+ * @see {@link VariantParameterizable.commitParameters}
98
+ * @emit {@link Event.VIEWER_LIGHT_PARAMETER_COMMITTED}
99
+ */
100
+ public async commitParameters(parameters?: ParameterBag): Promise<VariantParameterizable> {
101
+ return super.commitParameters(parameters);
102
+ }
103
+
104
+ /**
105
+ * Adds the default {@link ParameterObserver}s which are called every time {@link commitParameters} is called.
106
+ */
107
+ protected addParameterObservers(): ViewerLight {
108
+ this._parameterObservers.set(Parameter.VISIBLE, [
109
+ async (light: ViewerLight, oldValue: ParameterValue, newValue: ParameterValue) => {
110
+ let visible;
111
+ try {
112
+ visible = Parameter.parseBoolean(newValue);
113
+ } catch (e) {
114
+ return;
115
+ }
116
+ if (visible === true) {
117
+ enableNodeWithParents(light.light);
118
+ } else if (visible === false) {
119
+ disableNodeWithParents(light.light);
120
+ }
121
+ },
122
+ ]);
123
+ this._parameterObservers.set(Parameter.INTENSITY, [
124
+ async (light: ViewerLight, oldValue: ParameterValue, newValue: ParameterValue) => {
125
+ set(light.light, 'intensity', Parameter.parseNumber(newValue));
126
+ },
127
+ ]);
128
+ this._parameterObservers.set(Parameter.SCALING, [
129
+ async (light: ViewerLight, oldValue: ParameterValue, newValue: ParameterValue) => {
130
+ // we have to deal just with root nodes here due to relative impacts in a node tree
131
+ const rootNode = getRootNode(light.light);
132
+ if (rootNode instanceof TransformNode) {
133
+ transformTransformNode(rootNode, {
134
+ scaling: Parameter.parseScaling(newValue),
135
+ position: Parameter.parseVector(light.inheritedParameters[Parameter.POSITION] || '(0, 0, 0)'),
136
+ rotation: Parameter.parseRotation(light.inheritedParameters[Parameter.ROTATION] || '(0, 0, 0)'),
137
+ });
138
+ }
139
+ },
140
+ ]);
141
+ this._parameterObservers.set(Parameter.POSITION, [
142
+ async (light: ViewerLight, oldValue: ParameterValue, newValue: ParameterValue) => {
143
+ // we have to deal just with root nodes here due to relative impacts in a node tree
144
+ const rootNode = getRootNode(light.light);
145
+ if (rootNode instanceof TransformNode) {
146
+ transformTransformNode(rootNode, {
147
+ scaling: Parameter.parseVector(light.inheritedParameters[Parameter.SCALING] || '(1, 1, 1)'),
148
+ position: Parameter.parseVector(newValue),
149
+ rotation: Parameter.parseRotation(light.inheritedParameters[Parameter.ROTATION] || '(0, 0, 0)'),
150
+ });
151
+ }
152
+ },
153
+ ]);
154
+ this._parameterObservers.set(Parameter.ROTATION, [
155
+ async (light: ViewerLight, oldValue: ParameterValue, newValue: ParameterValue) => {
156
+ // we have to deal just with root nodes here due to relative impacts in a node tree
157
+ const rootNode = getRootNode(light.light);
158
+ if (rootNode instanceof TransformNode) {
159
+ transformTransformNode(rootNode, {
160
+ scaling: Parameter.parseVector(light.inheritedParameters[Parameter.SCALING] || '(1, 1, 1)'),
161
+ position: Parameter.parseVector(light.inheritedParameters[Parameter.POSITION] || '(0, 0, 0)'),
162
+ rotation: Parameter.parseRotation(newValue),
163
+ });
164
+ }
165
+ },
166
+ ]);
167
+ this._parameterObservers.set(Parameter.DIRECTION, [
168
+ async (light: ViewerLight, oldValue: ParameterValue, newValue: ParameterValue) => {
169
+ if (
170
+ (light.light instanceof ShadowLight && !(light.light instanceof PointLight)) ||
171
+ light.light instanceof HemisphericLight
172
+ ) {
173
+ set(light.light, 'direction', Parameter.parseVector(newValue));
174
+ }
175
+ },
176
+ ]);
177
+ this._parameterObservers.set(Parameter.ANGLE, [
178
+ async (light: ViewerLight, oldValue: ParameterValue, newValue: ParameterValue) => {
179
+ if (light.light.getClassName() === 'SpotLight') {
180
+ set(light.light, 'angle', Parameter.parseNumber(newValue));
181
+ }
182
+ },
183
+ ]);
184
+ this._parameterObservers.set(Parameter.EXPONENT, [
185
+ async (light: ViewerLight, oldValue: ParameterValue, newValue: ParameterValue) => {
186
+ if (light.light.getClassName() === 'SpotLight') {
187
+ set(light.light, 'exponent', Parameter.parseNumber(newValue));
188
+ }
189
+ },
190
+ ]);
191
+ this._parameterObservers.set(Parameter.DIFFUSE, [
192
+ async (light: ViewerLight, oldValue: ParameterValue, newValue: ParameterValue) => {
193
+ set(light.light, 'diffuse', Parameter.parseColor(newValue));
194
+ },
195
+ ]);
196
+ this._parameterObservers.set(Parameter.SPECULAR, [
197
+ async (light: ViewerLight, oldValue: ParameterValue, newValue: ParameterValue) => {
198
+ set(light.light, 'specular', Parameter.parseColor(newValue));
199
+ },
200
+ ]);
201
+ return this;
202
+ }
203
+
204
+ /**
205
+ * @param definition
206
+ * @protected
207
+ */
208
+ protected async createBabylonLightFromDefinition(definition: LightDefinition): Promise<Light> {
209
+ const parameters = Parameter.parseFromDeclarations(Parameter.declarations, this.inheritedParameters);
210
+ const scene = this.variant.viewer.scene;
211
+ let lightId = this.id;
212
+ let babylonLight;
213
+ switch (definition.type) {
214
+ case 'baked':
215
+ if (!definition['path']) {
216
+ throw new Error(`The light "${lightId}" of type "${definition.type}" needs a "path".`);
217
+ }
218
+ const bakedLight = this.variant.inheritedLights.find(l => l.metadata.dottedPath.path === definition['path']);
219
+ if (bakedLight) {
220
+ lightId = bakedLight.metadata.dottedPath.clone().unshiftPart(this.id).path;
221
+ babylonLight = cloneNodeWithParents(bakedLight) as Light;
222
+ babylonLight!.name = lightId;
223
+ babylonLight!.id = lightId;
224
+ } else {
225
+ throw new Error(`No light found for path "${definition['path']}" in ViewerLight "${lightId}".`);
226
+ }
227
+ break;
228
+ case 'hemispheric':
229
+ if (!parameters['direction']) {
230
+ throw new Error(`The ViewerLight "${lightId}" of type "${definition.type}" needs a "direction".`);
231
+ }
232
+ // @ts-ignore
233
+ const hemisphericLightModule = await import(
234
+ /* webpackChunkName: "hemispheric-light" */ '@babylonjs/core/Lights/hemisphericLight'
235
+ );
236
+ babylonLight = new hemisphericLightModule.HemisphericLight(lightId, parameters['direction'], scene);
237
+ break;
238
+ case 'point':
239
+ // @ts-ignore
240
+ const pointLightModule = await import(
241
+ /* webpackChunkName: "point-light" */ '@babylonjs/core/Lights/pointLight'
242
+ );
243
+ babylonLight = new pointLightModule.PointLight(
244
+ lightId,
245
+ Vector3.Zero(), // position is set via parent TransformNode
246
+ scene
247
+ );
248
+ break;
249
+ case 'directional':
250
+ if (!parameters['direction']) {
251
+ throw new Error(`The ViewerLight "${lightId}" of type "${definition.type}" needs a "direction".`);
252
+ }
253
+ // @ts-ignore
254
+ const directionalLightModule = await import(
255
+ /* webpackChunkName: "directional-light" */ '@babylonjs/core/Lights/directionalLight'
256
+ );
257
+ babylonLight = new directionalLightModule.DirectionalLight(lightId, parameters['direction'], scene);
258
+ break;
259
+ case 'spot':
260
+ if (!parameters['direction']) {
261
+ throw new Error(`The ViewerLight "${lightId}" of type "${definition.type}" needs a "direction".`);
262
+ }
263
+ if (!parameters['angle']) {
264
+ throw new Error(`A ViewerLight of type "${definition.type}" needs an "angle".`);
265
+ }
266
+ if (!parameters['exponent']) {
267
+ throw new Error(`The ViewerLight "${lightId}" of type "${definition.type}" needs an "exponent".`);
268
+ }
269
+ // @ts-ignore
270
+ const spotLightModule = await import(/* webpackChunkName: "spot-light" */ '@babylonjs/core/Lights/spotLight');
271
+ babylonLight = new spotLightModule.SpotLight(
272
+ lightId,
273
+ Vector3.Zero(), // position is set via parent TransformNode
274
+ parameters['direction'],
275
+ parameters['angle'],
276
+ parameters['exponent'],
277
+ scene
278
+ );
279
+ break;
280
+ default:
281
+ throw new Error(`The type "${definition.type}" for ViewerLight "${lightId}" is not implemented (yet).`);
282
+ }
283
+ if (!babylonLight) {
284
+ throw new Error(
285
+ `The Light for ViewerLight "${lightId}" of type "${definition.type}" could no be created ` + `or found.`
286
+ );
287
+ }
288
+ if (!babylonLight.parent) {
289
+ // Create pseudo parent since lights do not implement mutations like "rotation" by itself.
290
+ babylonLight.parent = new TransformNode('__light__', this.variant.viewer.scene, true);
291
+ }
292
+ injectNodeMetadata(babylonLight.parent, {
293
+ variant: this.variant,
294
+ variantParameterizable: this,
295
+ });
296
+ // disable/hide by default
297
+ disableNodeWithParents(babylonLight);
298
+ // process shadow generator
299
+ const shadowGeneratorDefinition = get(definition, 'shadowGenerator') as ShadowGeneratorDefinition;
300
+ if (!isEmpty(shadowGeneratorDefinition)) {
301
+ if (!(babylonLight instanceof ShadowLight)) {
302
+ throw new Error(
303
+ `Using a ShadowGenerator with light type "${definition.type}" is not supported for ` +
304
+ `"${lightId}". Use lights deriving from ShadowLight.`
305
+ );
306
+ }
307
+ await this.processShadowGenerator(babylonLight, shadowGeneratorDefinition);
308
+ }
309
+ return babylonLight;
310
+ }
311
+
312
+ /**
313
+ * @param babylonLight
314
+ * @param definition
315
+ * @protected
316
+ */
317
+ protected async processShadowGenerator(
318
+ babylonLight: ShadowLight,
319
+ definition: ShadowGeneratorDefinition
320
+ ): Promise<ShadowGenerator> {
321
+ const parameterDeclarations: ParameterDeclarations = {};
322
+ // define declarations here if needed in future
323
+ const parameterBag = definition as {} as ParameterBag;
324
+ const parameters = Parameter.parseFromDeclarations(parameterDeclarations, parameterBag);
325
+ const shadowGenerator = new ShadowGenerator(parameters['mapSize'], babylonLight);
326
+ for (const parameter in parameters) {
327
+ if (parameter === 'mapSize') {
328
+ continue;
329
+ }
330
+ set(shadowGenerator, parameter, get(parameters, parameter));
331
+ }
332
+ return shadowGenerator;
333
+ }
334
+ }