@combeenation/3d-viewer 12.4.1 → 12.4.3

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 (114) hide show
  1. package/README.md +9 -9
  2. package/dist/lib-cjs/api/classes/animationInterface.d.ts +8 -8
  3. package/dist/lib-cjs/api/classes/animationInterface.js +2 -2
  4. package/dist/lib-cjs/api/classes/dottedPath.d.ts +79 -79
  5. package/dist/lib-cjs/api/classes/dottedPath.js +166 -166
  6. package/dist/lib-cjs/api/classes/element.d.ts +153 -153
  7. package/dist/lib-cjs/api/classes/element.js +702 -702
  8. package/dist/lib-cjs/api/classes/event.d.ts +401 -401
  9. package/dist/lib-cjs/api/classes/event.js +424 -424
  10. package/dist/lib-cjs/api/classes/eventBroadcaster.d.ts +26 -26
  11. package/dist/lib-cjs/api/classes/eventBroadcaster.js +49 -49
  12. package/dist/lib-cjs/api/classes/fuzzyMap.d.ts +7 -7
  13. package/dist/lib-cjs/api/classes/fuzzyMap.js +21 -21
  14. package/dist/lib-cjs/api/classes/parameter.d.ts +410 -410
  15. package/dist/lib-cjs/api/classes/parameter.js +642 -642
  16. package/dist/lib-cjs/api/classes/parameterObservable.d.ts +36 -36
  17. package/dist/lib-cjs/api/classes/parameterObservable.js +72 -72
  18. package/dist/lib-cjs/api/classes/parameterizable.d.ts +15 -15
  19. package/dist/lib-cjs/api/classes/parameterizable.js +102 -102
  20. package/dist/lib-cjs/api/classes/placementAnimation.d.ts +45 -45
  21. package/dist/lib-cjs/api/classes/placementAnimation.js +176 -176
  22. package/dist/lib-cjs/api/classes/variant.d.ts +261 -261
  23. package/dist/lib-cjs/api/classes/variant.js +872 -872
  24. package/dist/lib-cjs/api/classes/variantInstance.d.ts +53 -53
  25. package/dist/lib-cjs/api/classes/variantInstance.js +125 -125
  26. package/dist/lib-cjs/api/classes/variantParameterizable.d.ts +17 -17
  27. package/dist/lib-cjs/api/classes/variantParameterizable.js +86 -86
  28. package/dist/lib-cjs/api/classes/viewer.d.ts +215 -215
  29. package/dist/lib-cjs/api/classes/viewer.js +708 -708
  30. package/dist/lib-cjs/api/classes/viewerError.d.ts +43 -43
  31. package/dist/lib-cjs/api/classes/viewerError.js +55 -55
  32. package/dist/lib-cjs/api/classes/viewerLight.d.ts +66 -66
  33. package/dist/lib-cjs/api/classes/viewerLight.js +344 -344
  34. package/dist/lib-cjs/api/internal/lensRendering.d.ts +8 -8
  35. package/dist/lib-cjs/api/internal/lensRendering.js +11 -11
  36. package/dist/lib-cjs/api/internal/sceneSetup.d.ts +13 -13
  37. package/dist/lib-cjs/api/internal/sceneSetup.js +227 -227
  38. package/dist/lib-cjs/api/manager/animationManager.d.ts +30 -30
  39. package/dist/lib-cjs/api/manager/animationManager.js +126 -126
  40. package/dist/lib-cjs/api/manager/gltfExportManager.d.ts +80 -80
  41. package/dist/lib-cjs/api/manager/gltfExportManager.js +300 -299
  42. package/dist/lib-cjs/api/manager/gltfExportManager.js.map +1 -1
  43. package/dist/lib-cjs/api/manager/sceneManager.d.ts +33 -33
  44. package/dist/lib-cjs/api/manager/sceneManager.js +128 -128
  45. package/dist/lib-cjs/api/manager/tagManager.d.ts +118 -118
  46. package/dist/lib-cjs/api/manager/tagManager.js +530 -530
  47. package/dist/lib-cjs/api/manager/textureLoadManager.d.ts +22 -22
  48. package/dist/lib-cjs/api/manager/textureLoadManager.js +107 -107
  49. package/dist/lib-cjs/api/manager/variantInstanceManager.d.ts +106 -106
  50. package/dist/lib-cjs/api/manager/variantInstanceManager.js +290 -290
  51. package/dist/lib-cjs/api/store/specStorage.d.ts +32 -32
  52. package/dist/lib-cjs/api/store/specStorage.js +65 -65
  53. package/dist/lib-cjs/api/util/babylonHelper.d.ts +238 -238
  54. package/dist/lib-cjs/api/util/babylonHelper.js +825 -825
  55. package/dist/lib-cjs/api/util/debugHelper.d.ts +9 -9
  56. package/dist/lib-cjs/api/util/debugHelper.js +93 -93
  57. package/dist/lib-cjs/api/util/deviceHelper.d.ts +9 -9
  58. package/dist/lib-cjs/api/util/deviceHelper.js +28 -28
  59. package/dist/lib-cjs/api/util/geometryHelper.d.ts +17 -17
  60. package/dist/lib-cjs/api/util/geometryHelper.js +112 -112
  61. package/dist/lib-cjs/api/util/globalTypes.d.ts +490 -490
  62. package/dist/lib-cjs/api/util/globalTypes.js +1 -1
  63. package/dist/lib-cjs/api/util/resourceHelper.d.ts +58 -58
  64. package/dist/lib-cjs/api/util/resourceHelper.js +214 -214
  65. package/dist/lib-cjs/api/util/sceneLoaderHelper.d.ts +58 -58
  66. package/dist/lib-cjs/api/util/sceneLoaderHelper.js +228 -228
  67. package/dist/lib-cjs/api/util/stringHelper.d.ts +13 -13
  68. package/dist/lib-cjs/api/util/stringHelper.js +32 -32
  69. package/dist/lib-cjs/api/util/structureHelper.d.ts +9 -9
  70. package/dist/lib-cjs/api/util/structureHelper.js +57 -57
  71. package/dist/lib-cjs/buildinfo.json +3 -3
  72. package/dist/lib-cjs/commonjs.tsconfig.tsbuildinfo +1 -1
  73. package/dist/lib-cjs/index.d.ts +63 -63
  74. package/dist/lib-cjs/index.js +128 -128
  75. package/package.json +93 -92
  76. package/src/api/classes/animationInterface.ts +10 -10
  77. package/src/api/classes/dottedPath.ts +181 -181
  78. package/src/api/classes/element.ts +766 -766
  79. package/src/api/classes/event.ts +457 -457
  80. package/src/api/classes/eventBroadcaster.ts +52 -52
  81. package/src/api/classes/fuzzyMap.ts +21 -21
  82. package/src/api/classes/parameter.ts +686 -686
  83. package/src/api/classes/parameterObservable.ts +73 -73
  84. package/src/api/classes/parameterizable.ts +87 -87
  85. package/src/api/classes/placementAnimation.ts +162 -162
  86. package/src/api/classes/variant.ts +965 -965
  87. package/src/api/classes/variantInstance.ts +123 -123
  88. package/src/api/classes/variantParameterizable.ts +83 -83
  89. package/src/api/classes/viewer.ts +751 -751
  90. package/src/api/classes/viewerError.ts +63 -63
  91. package/src/api/classes/viewerLight.ts +335 -335
  92. package/src/api/internal/debugViewer.ts +90 -90
  93. package/src/api/internal/lensRendering.ts +9 -9
  94. package/src/api/internal/sceneSetup.ts +208 -208
  95. package/src/api/manager/animationManager.ts +143 -143
  96. package/src/api/manager/gltfExportManager.ts +337 -334
  97. package/src/api/manager/sceneManager.ts +134 -134
  98. package/src/api/manager/tagManager.ts +572 -572
  99. package/src/api/manager/textureLoadManager.ts +107 -107
  100. package/src/api/manager/variantInstanceManager.ts +306 -306
  101. package/src/api/store/specStorage.ts +68 -68
  102. package/src/api/util/babylonHelper.ts +915 -915
  103. package/src/api/util/debugHelper.ts +121 -121
  104. package/src/api/util/deviceHelper.ts +31 -31
  105. package/src/api/util/geometryHelper.ts +142 -142
  106. package/src/api/util/globalTypes.ts +566 -566
  107. package/src/api/util/resourceHelper.ts +201 -201
  108. package/src/api/util/sceneLoaderHelper.ts +247 -247
  109. package/src/api/util/stringHelper.ts +30 -30
  110. package/src/api/util/structureHelper.ts +62 -62
  111. package/src/buildinfo.json +3 -3
  112. package/src/dev.ts +70 -70
  113. package/src/index.ts +116 -116
  114. package/src/types.d.ts +49 -49
@@ -1,300 +1,301 @@
1
- "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.GltfExportManager = void 0;
13
- const babylonHelper_1 = require("../util/babylonHelper");
14
- const deviceHelper_1 = require("../util/deviceHelper");
15
- const geometryHelper_1 = require("../util/geometryHelper");
16
- const structureHelper_1 = require("../util/structureHelper");
17
- const pbrMaterial_1 = require("@babylonjs/core/Materials/PBR/pbrMaterial");
18
- const dynamicTexture_1 = require("@babylonjs/core/Materials/Textures/dynamicTexture");
19
- const renderTargetTexture_1 = require("@babylonjs/core/Materials/Textures/renderTargetTexture");
20
- const math_vector_1 = require("@babylonjs/core/Maths/math.vector");
21
- const instancedMesh_1 = require("@babylonjs/core/Meshes/instancedMesh");
22
- const mesh_1 = require("@babylonjs/core/Meshes/mesh");
23
- const transformNode_1 = require("@babylonjs/core/Meshes/transformNode");
24
- require("@babylonjs/serializers/glTF/2.0/Extensions/KHR_texture_transform");
25
- const glTFSerializer_1 = require("@babylonjs/serializers/glTF/2.0/glTFSerializer");
26
- class GltfExportManager {
27
- constructor(viewer) {
28
- this.viewer = viewer;
29
- // store initial max texture size, so that we can restore it in the post processing
30
- this._maxTextureSize = viewer.engine.getCaps().maxTextureSize;
31
- }
32
- static create(viewer) {
33
- return __awaiter(this, void 0, void 0, function* () {
34
- return new GltfExportManager(viewer);
35
- });
36
- }
37
- /**
38
- * Exports selected nodes to a file.
39
- * @param filename Optional name of the exported .GLB file.
40
- * @param optimizeForAR Adjusts the exported GLB so that known issues get automatically fixed, this
41
- * is mostly targeting Apples .usdz format.
42
- * @param excluded Optional list of geometry (meshes, elements, variants,...) to be excluded from the export.
43
- */
44
- exportGlb(filename = 'glb-export.glb', optimizeForAR = false, excluded) {
45
- return __awaiter(this, void 0, void 0, function* () {
46
- yield this._exportPreProcess(optimizeForAR, excluded);
47
- const glbData = yield glTFSerializer_1.GLTF2Export.GLBAsync(this.viewer.scene, 'dummy', GltfExportManager._gltfExportOptions(optimizeForAR, excluded));
48
- yield this._exportPostProcess(optimizeForAR);
49
- const resBlob = glbData.glTFFiles['dummy.glb'];
50
- // check if result is valid, according to the typings this could also be a string
51
- if (resBlob instanceof Blob) {
52
- if (!filename.endsWith('.glb')) {
53
- filename += '.glb';
54
- }
55
- return new File([resBlob], filename);
56
- }
57
- else {
58
- // result was not a valid blob
59
- return undefined;
60
- }
61
- });
62
- }
63
- /**
64
- * Exports selected nodes to GLTF. This may result in more than one file, since textures are exported seperately.
65
- * @param filename Name of the main (text-based) .GLTF file referring to separate texture files.
66
- * @param optimizeForAR Adjusts the exported GLB so that known issues get automatically fixed, this
67
- * is mostly targeting Apples .usdz format.
68
- * @param excluded Optional list of geometry (meshes, elements, variants,...) to be excluded from the export.
69
- */
70
- exportGltfToFile(filename, optimizeForAR = false, excluded) {
71
- return __awaiter(this, void 0, void 0, function* () {
72
- yield this._exportPreProcess(optimizeForAR, excluded);
73
- const gltf = yield glTFSerializer_1.GLTF2Export.GLTFAsync(this.viewer.scene, filename, GltfExportManager._gltfExportOptions(optimizeForAR, excluded));
74
- gltf.downloadFiles();
75
- this._exportPostProcess(optimizeForAR);
76
- });
77
- }
78
- /**
79
- * Exports selected nodes to GLB. This results in one binary file.
80
- * @param filename Name of the main (text-based) .GLTF file referring to seperate texture files.
81
- * @param optimizeForAR Adjusts the exported GLB so that known issues get automatically fixed, this
82
- * is mostly targeting Apples .usdz format.
83
- * @param excluded Optional list of geometry (meshes, elements, variants,...) to be excluded from the export.
84
- */
85
- exportGlbToFile(filename, optimizeForAR = false, excluded) {
86
- return __awaiter(this, void 0, void 0, function* () {
87
- yield this._exportPreProcess(optimizeForAR, excluded);
88
- const glb = yield glTFSerializer_1.GLTF2Export.GLBAsync(this.viewer.scene, filename, GltfExportManager._gltfExportOptions(optimizeForAR, excluded));
89
- glb.downloadFiles();
90
- yield this._exportPostProcess(optimizeForAR);
91
- });
92
- }
93
- /**
94
- * Prepares scene for GLB export.
95
- * This is very important for AR exports, since we have to do a lot of conversions to satisfy Apples .usdz format.
96
- */
97
- _exportPreProcess(optimizeForAR, excluded) {
98
- return __awaiter(this, void 0, void 0, function* () {
99
- if (!optimizeForAR) {
100
- // actually nothing to do if AR optimization is not required
101
- return;
102
- }
103
- // pause rendering, since we are altering the active scene, which should not be visible to the user
104
- this.viewer.pauseRendering();
105
- // exchange materials if required
106
- // the AR export should never contain textures larger than 1024 px:
107
- // - iOS devices will crash most likely when trying to access AR endpoints with such files
108
- // - file size will be reduced, which leads to faster loading times
109
- // - textures > 1024 px shouldn't make a difference on mobiles anyway
110
- // we don't have to rescale anything if are already on a downscaled device, since the textures are already <= 1024
111
- // also we have to be very cautios with copying textures on these devices, since we are potentially very limited
112
- // with the available memory
113
- const isScaledDownDevice = (0, deviceHelper_1.getIsScaledDownDevice)();
114
- if (!isScaledDownDevice) {
115
- // the idea is to re-create all textures with a smaller texture size
116
- // we have to exchange all materials for this to work
117
- this.viewer.engine.clearInternalTexturesCache();
118
- this.viewer.engine.getCaps().maxTextureSize = 1024;
119
- this.viewer.scene.materials
120
- .filter(material => material instanceof pbrMaterial_1.PBRMaterial)
121
- .forEach(material => GltfExportManager._exchangeMaterial(material));
122
- }
123
- // since Babylon.js v6 the conversion to right handed GLB coordinate system is done differently
124
- // previously the geometry itself has been altered, now they negate the scaling of all root nodes
125
- // this is an issue for us, since we will receive this negated scalings in the exported GLB, which leads to issues
126
- // on iOS devices
127
- // we fix that by adding a top level root node with a negative scaling as well
128
- // the exporter just removes this node as he detects a "noop root node" (implementation details of Babylon.js)
129
- // everything beneath this node remains untouched
130
- // TODO BJS Update: Test AR export on iPhones as well and double check if we still need this special logic
131
- const exportRootNode = new transformNode_1.TransformNode(GltfExportManager._EXPORT_ROOT_NAME, this.viewer.scene);
132
- exportRootNode.scaling = new math_vector_1.Vector3(-1, 1, 1);
133
- (0, babylonHelper_1.injectMetadata)(exportRootNode, {
134
- [GltfExportManager._METADATA_PROPS.exportNode]: true,
135
- [GltfExportManager._METADATA_PROPS.deleteAfterExport]: true,
136
- });
137
- // create clones of each node (recursively), optionally exchange with cloned materials and mark these nodes for the
138
- // export
139
- this.viewer.scene.rootNodes
140
- .filter(rootNode => rootNode.name !== GltfExportManager._EXPORT_ROOT_NAME)
141
- .forEach(rootNode => this._prepareNodeForExport(rootNode, exportRootNode, excluded));
142
- // bake transformation of all meshes, so that no negative scalings are left
143
- // it's important that this is done AFTER instanced meshes have been converted (_prepareNodeForExport)
144
- this._getNodesMarkedForExport(true).forEach(mesh => (0, geometryHelper_1.bakeGeometryOfMesh)(mesh));
145
- // reset transformation of all "TransformNodes", which couldn't be handled by the geometry baking algorithm
146
- // it's important that this is done AFTER all geometries have been baked
147
- this._getNodesMarkedForExport().forEach(node => (0, geometryHelper_1.resetTransformation)(node));
148
- });
149
- }
150
- /**
151
- * Cleans up scene after export
152
- */
153
- _exportPostProcess(optimizeForAR) {
154
- return __awaiter(this, void 0, void 0, function* () {
155
- if (!optimizeForAR) {
156
- // nothing to do, since no changes have been made without AR optimizations
157
- return;
158
- }
159
- // dispose all nodes, materials and textures that have only been created for the export
160
- this.viewer.scene.rootNodes
161
- .filter(rootNode => { var _a; return (_a = rootNode.metadata) === null || _a === void 0 ? void 0 : _a[GltfExportManager._METADATA_PROPS.deleteAfterExport]; })
162
- .forEach(rootNode => rootNode.dispose());
163
- this.viewer.scene.materials
164
- .filter(mat => { var _a; return !!((_a = mat.metadata) === null || _a === void 0 ? void 0 : _a[GltfExportManager._METADATA_PROPS.deleteAfterExport]); })
165
- .forEach(material => material.dispose(false, false));
166
- this.viewer.scene.textures
167
- .filter(texture => { var _a; return !!((_a = texture.metadata) === null || _a === void 0 ? void 0 : _a[GltfExportManager._METADATA_PROPS.deleteAfterExport]); })
168
- .forEach(texture => texture.dispose());
169
- // reset engines max texture size and resume rendering
170
- this.viewer.engine.getCaps().maxTextureSize = this._maxTextureSize;
171
- this.viewer.resumeRendering();
172
- });
173
- }
174
- /**
175
- * Creates a clone of the node which should be used for the export.
176
- * Also switches to the cloned material if required.
177
- */
178
- _prepareNodeForExport(node, clonedParent, excluded) {
179
- var _a, _b;
180
- if (!GltfExportManager._shouldExportNode(node, excluded)) {
181
- return;
182
- }
183
- // from here on we only have TransformNodes
184
- const transformNode = node;
185
- // clone original node and create unique name (via uniqueId) for the export
186
- const clonedNodeName = `${transformNode.name}_${transformNode.uniqueId}`;
187
- const clonedNode = transformNode instanceof instancedMesh_1.InstancedMesh
188
- ? (0, geometryHelper_1.createMeshFromInstancedMesh)(transformNode, clonedNodeName, clonedParent)
189
- : transformNode.clone(clonedNodeName, clonedParent, true);
190
- // exchange material
191
- if (clonedNode instanceof mesh_1.Mesh) {
192
- const exchangeWithMaterial = (_b = (_a = clonedNode.material) === null || _a === void 0 ? void 0 : _a.metadata) === null || _b === void 0 ? void 0 : _b[GltfExportManager._METADATA_PROPS.exchangeMaterialWith];
193
- if (exchangeWithMaterial) {
194
- clonedNode.material = this.viewer.scene.getMaterialByUniqueID(exchangeWithMaterial);
195
- }
196
- }
197
- // signalize that this is a cloned node
198
- (0, babylonHelper_1.injectMetadata)(clonedNode, {
199
- [GltfExportManager._METADATA_PROPS.exportNode]: true,
200
- [GltfExportManager._METADATA_PROPS.deleteAfterExport]: true,
201
- });
202
- // handle children
203
- const childs = transformNode.getChildTransformNodes(true);
204
- childs.forEach(child => this._prepareNodeForExport(child, clonedNode, excluded));
205
- }
206
- /**
207
- * Help function for receiving all nodes that are marked for the export
208
- */
209
- _getNodesMarkedForExport(meshesOnly) {
210
- const nodes = [...this.viewer.scene.meshes];
211
- if (!meshesOnly) {
212
- nodes.push(...this.viewer.scene.transformNodes);
213
- }
214
- const filteredNodes = nodes.filter(node => {
215
- var _a;
216
- return !!((_a = node.metadata) === null || _a === void 0 ? void 0 : _a[GltfExportManager._METADATA_PROPS.exportNode]) &&
217
- // in the desired use cases we want to exclude the export root node
218
- // maybe add a parameter if we have to include it in certain scenarios in the future
219
- node.name !== GltfExportManager._EXPORT_ROOT_NAME;
220
- });
221
- return filteredNodes;
222
- }
223
- /**
224
- * Defines options for the export.
225
- * We don't allow the user to overwrite certain settings, since we rely on properties like `removeNoopRootNodes` to
226
- * stay `true` in order to make the AR export work.
227
- * We could theoretically allow it if AR optimization is not desired, but this may confuse the user.
228
- */
229
- static _gltfExportOptions(optimizeForAR, excluded) {
230
- return {
231
- shouldExportNode: function (node) {
232
- var _a;
233
- if (optimizeForAR) {
234
- // we explicitely marked nodes, that should be exported in AR mode
235
- return !!((_a = node.metadata) === null || _a === void 0 ? void 0 : _a[GltfExportManager._METADATA_PROPS.exportNode]);
236
- }
237
- else {
238
- // use the default export node check (enabled state, exclusion list, etc...)
239
- return GltfExportManager._shouldExportNode(node, excluded);
240
- }
241
- },
242
- };
243
- }
244
- /**
245
- * Checks if a node should be available in the export
246
- */
247
- static _shouldExportNode(node, excluded) {
248
- if (!(node instanceof transformNode_1.TransformNode)) {
249
- return false;
250
- }
251
- // TODO: think of adding "BackgroundHelper" and nodes with "infiniteDistance" here as well, at least in AR mode
252
- if (!node.isEnabled()) {
253
- return false;
254
- }
255
- if (excluded && (0, structureHelper_1.isNodeIncludedInExclusionList)(node, excluded)) {
256
- return false;
257
- }
258
- return true;
259
- }
260
- /**
261
- * Creates a clone of the material which should be used for the export.
262
- * This is mostly required for recreating textures with lower sizes.
263
- * CAUTION: Material exchanging is not supported for materials that contain certain texture types:
264
- * - Dynamic textures (Paintables): Cloning dynamic textures doesn't clone the canvas context
265
- * => so the clone is just empty
266
- * - Render target textures: Disposing the clone will leave the scene in a "not ready" state
267
- * => this scenario is not fully analyzed yet, but it's not really worth the effort right now, since this kind of
268
- * of texture is not really used ATM
269
- */
270
- static _exchangeMaterial(material) {
271
- const baseTextures = material.getActiveTextures();
272
- const hasDynamicTextures = baseTextures.some(texture => texture instanceof dynamicTexture_1.DynamicTexture);
273
- const hasRenderTargetTextures = baseTextures.some(texture => texture instanceof renderTargetTexture_1.RenderTargetTexture);
274
- if (hasDynamicTextures || hasRenderTargetTextures) {
275
- const textureTypesString = [
276
- hasDynamicTextures ? 'Dynamic Textures' : '',
277
- hasRenderTargetTextures ? 'Render Target Textures' : '',
278
- ]
279
- .filter(Boolean)
280
- .join();
281
- console.warn(`Couldn't exchange material "${material.name}" in GLB export, as it contains unsupported texture type(s) (${textureTypesString}). The export will still work, but the textures of this material will keep their original size.`);
282
- return;
283
- }
284
- const newName = `${material.name}_clone`;
285
- const clonedMaterial = material.clone(newName);
286
- const clonedTextures = clonedMaterial.getActiveTextures();
287
- // mark all exported textures, so that they will be deleted after the export
288
- clonedTextures.forEach(texture => (0, babylonHelper_1.injectMetadata)(texture, { [GltfExportManager._METADATA_PROPS.deleteAfterExport]: true }));
289
- (0, babylonHelper_1.injectMetadata)(material, { [GltfExportManager._METADATA_PROPS.exchangeMaterialWith]: clonedMaterial.uniqueId });
290
- (0, babylonHelper_1.injectMetadata)(clonedMaterial, { [GltfExportManager._METADATA_PROPS.deleteAfterExport]: true });
291
- }
292
- }
293
- exports.GltfExportManager = GltfExportManager;
294
- GltfExportManager._METADATA_PROPS = {
295
- exportNode: 'exportNode',
296
- deleteAfterExport: 'deleteAfterExport',
297
- exchangeMaterialWith: 'exchangeMaterialWith',
298
- };
299
- GltfExportManager._EXPORT_ROOT_NAME = '__export_root__';
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.GltfExportManager = void 0;
13
+ const babylonHelper_1 = require("../util/babylonHelper");
14
+ const deviceHelper_1 = require("../util/deviceHelper");
15
+ const geometryHelper_1 = require("../util/geometryHelper");
16
+ const structureHelper_1 = require("../util/structureHelper");
17
+ const pbrMaterial_1 = require("@babylonjs/core/Materials/PBR/pbrMaterial");
18
+ const dynamicTexture_1 = require("@babylonjs/core/Materials/Textures/dynamicTexture");
19
+ const renderTargetTexture_1 = require("@babylonjs/core/Materials/Textures/renderTargetTexture");
20
+ const math_vector_1 = require("@babylonjs/core/Maths/math.vector");
21
+ const instancedMesh_1 = require("@babylonjs/core/Meshes/instancedMesh");
22
+ const mesh_1 = require("@babylonjs/core/Meshes/mesh");
23
+ const transformNode_1 = require("@babylonjs/core/Meshes/transformNode");
24
+ require("@babylonjs/serializers/glTF/2.0/Extensions/KHR_texture_transform");
25
+ const glTFSerializer_1 = require("@babylonjs/serializers/glTF/2.0/glTFSerializer");
26
+ class GltfExportManager {
27
+ constructor(viewer) {
28
+ this.viewer = viewer;
29
+ // store initial max texture size, so that we can restore it in the post processing
30
+ this._maxTextureSize = viewer.engine.getCaps().maxTextureSize;
31
+ }
32
+ static create(viewer) {
33
+ return __awaiter(this, void 0, void 0, function* () {
34
+ return new GltfExportManager(viewer);
35
+ });
36
+ }
37
+ /**
38
+ * Exports selected nodes to a file.
39
+ * @param filename Optional name of the exported .GLB file.
40
+ * @param optimizeForAR Adjusts the exported GLB so that known issues get automatically fixed, this
41
+ * is mostly targeting Apples .usdz format.
42
+ * @param excluded Optional list of geometry (meshes, elements, variants,...) to be excluded from the export.
43
+ */
44
+ exportGlb(filename = 'glb-export.glb', optimizeForAR = false, excluded) {
45
+ return __awaiter(this, void 0, void 0, function* () {
46
+ yield this._exportPreProcess(optimizeForAR, excluded);
47
+ const glbData = yield glTFSerializer_1.GLTF2Export.GLBAsync(this.viewer.scene, 'dummy', GltfExportManager._gltfExportOptions(optimizeForAR, excluded));
48
+ yield this._exportPostProcess(optimizeForAR);
49
+ const resBlob = glbData.glTFFiles['dummy.glb'];
50
+ // check if result is valid, according to the typings this could also be a string
51
+ if (resBlob instanceof Blob) {
52
+ if (!filename.endsWith('.glb')) {
53
+ filename += '.glb';
54
+ }
55
+ return new File([resBlob], filename);
56
+ }
57
+ else {
58
+ // result was not a valid blob
59
+ return undefined;
60
+ }
61
+ });
62
+ }
63
+ /**
64
+ * Exports selected nodes to GLTF. This may result in more than one file, since textures are exported seperately.
65
+ * @param filename Name of the main (text-based) .GLTF file referring to separate texture files.
66
+ * @param optimizeForAR Adjusts the exported GLB so that known issues get automatically fixed, this
67
+ * is mostly targeting Apples .usdz format.
68
+ * @param excluded Optional list of geometry (meshes, elements, variants,...) to be excluded from the export.
69
+ */
70
+ exportGltfToFile(filename, optimizeForAR = false, excluded) {
71
+ return __awaiter(this, void 0, void 0, function* () {
72
+ yield this._exportPreProcess(optimizeForAR, excluded);
73
+ const gltf = yield glTFSerializer_1.GLTF2Export.GLTFAsync(this.viewer.scene, filename, GltfExportManager._gltfExportOptions(optimizeForAR, excluded));
74
+ gltf.downloadFiles();
75
+ this._exportPostProcess(optimizeForAR);
76
+ });
77
+ }
78
+ /**
79
+ * Exports selected nodes to GLB. This results in one binary file.
80
+ * @param filename Name of the main (text-based) .GLTF file referring to seperate texture files.
81
+ * @param optimizeForAR Adjusts the exported GLB so that known issues get automatically fixed, this
82
+ * is mostly targeting Apples .usdz format.
83
+ * @param excluded Optional list of geometry (meshes, elements, variants,...) to be excluded from the export.
84
+ */
85
+ exportGlbToFile(filename, optimizeForAR = false, excluded) {
86
+ return __awaiter(this, void 0, void 0, function* () {
87
+ yield this._exportPreProcess(optimizeForAR, excluded);
88
+ const glb = yield glTFSerializer_1.GLTF2Export.GLBAsync(this.viewer.scene, filename, GltfExportManager._gltfExportOptions(optimizeForAR, excluded));
89
+ glb.downloadFiles();
90
+ yield this._exportPostProcess(optimizeForAR);
91
+ });
92
+ }
93
+ /**
94
+ * Prepares scene for GLB export.
95
+ * This is very important for AR exports, since we have to do a lot of conversions to satisfy Apples .usdz format.
96
+ */
97
+ _exportPreProcess(optimizeForAR, excluded) {
98
+ return __awaiter(this, void 0, void 0, function* () {
99
+ if (!optimizeForAR) {
100
+ // actually nothing to do if AR optimization is not required
101
+ return;
102
+ }
103
+ // pause rendering, since we are altering the active scene, which should not be visible to the user
104
+ this.viewer.pauseRendering();
105
+ // exchange materials if required
106
+ // the AR export should never contain textures larger than 1024 px:
107
+ // - iOS devices will crash most likely when trying to access AR endpoints with such files
108
+ // - file size will be reduced, which leads to faster loading times
109
+ // - textures > 1024 px shouldn't make a difference on mobiles anyway
110
+ // we don't have to rescale anything if are already on a downscaled device, since the textures are already <= 1024
111
+ // also we have to be very cautios with copying textures on these devices, since we are potentially very limited
112
+ // with the available memory
113
+ const isScaledDownDevice = (0, deviceHelper_1.getIsScaledDownDevice)();
114
+ if (!isScaledDownDevice) {
115
+ // the idea is to re-create all textures with a smaller texture size
116
+ // we have to exchange all materials for this to work
117
+ this.viewer.engine.clearInternalTexturesCache();
118
+ this.viewer.engine.getCaps().maxTextureSize = 1024;
119
+ this.viewer.scene.materials
120
+ .filter(material => material instanceof pbrMaterial_1.PBRMaterial)
121
+ .forEach(material => GltfExportManager._exchangeMaterial(material));
122
+ }
123
+ // since Babylon.js v6 the conversion to right handed GLB coordinate system is done differently
124
+ // previously the geometry itself has been altered, now they negate the scaling of all root nodes
125
+ // this is an issue for us, since we will receive this negated scalings in the exported GLB, which leads to issues
126
+ // on iOS devices
127
+ // we fix that by adding a top level root node with a negative scaling as well
128
+ // the exporter just removes this node as he detects a "noop root node" (implementation details of Babylon.js)
129
+ // everything beneath this node remains untouched
130
+ // TODO BJS Update: Test AR export on iPhones as well and double check if we still need this special logic
131
+ const exportRootNode = new transformNode_1.TransformNode(GltfExportManager._EXPORT_ROOT_NAME, this.viewer.scene);
132
+ exportRootNode.scaling = new math_vector_1.Vector3(-1, 1, 1);
133
+ (0, babylonHelper_1.injectMetadata)(exportRootNode, {
134
+ [GltfExportManager._METADATA_PROPS.exportNode]: true,
135
+ [GltfExportManager._METADATA_PROPS.deleteAfterExport]: true,
136
+ });
137
+ // create clones of each node (recursively), optionally exchange with cloned materials and mark these nodes for the
138
+ // export
139
+ this.viewer.scene.rootNodes
140
+ .filter(rootNode => rootNode.name !== GltfExportManager._EXPORT_ROOT_NAME)
141
+ .forEach(rootNode => this._prepareNodeForExport(rootNode, exportRootNode, excluded));
142
+ // bake transformation of all meshes, so that no negative scalings are left
143
+ // it's important that this is done AFTER instanced meshes have been converted (_prepareNodeForExport)
144
+ this._getNodesMarkedForExport(true).forEach(mesh => (0, geometryHelper_1.bakeGeometryOfMesh)(mesh));
145
+ // reset transformation of all "TransformNodes", which couldn't be handled by the geometry baking algorithm
146
+ // it's important that this is done AFTER all geometries have been baked
147
+ this._getNodesMarkedForExport().forEach(node => (0, geometryHelper_1.resetTransformation)(node));
148
+ });
149
+ }
150
+ /**
151
+ * Cleans up scene after export
152
+ */
153
+ _exportPostProcess(optimizeForAR) {
154
+ return __awaiter(this, void 0, void 0, function* () {
155
+ if (!optimizeForAR) {
156
+ // nothing to do, since no changes have been made without AR optimizations
157
+ return;
158
+ }
159
+ // dispose all nodes, materials and textures that have only been created for the export
160
+ this.viewer.scene.rootNodes
161
+ .filter(rootNode => { var _a; return (_a = rootNode.metadata) === null || _a === void 0 ? void 0 : _a[GltfExportManager._METADATA_PROPS.deleteAfterExport]; })
162
+ .forEach(rootNode => rootNode.dispose());
163
+ this.viewer.scene.materials
164
+ .filter(mat => { var _a; return !!((_a = mat.metadata) === null || _a === void 0 ? void 0 : _a[GltfExportManager._METADATA_PROPS.deleteAfterExport]); })
165
+ .forEach(material => material.dispose(false, false));
166
+ this.viewer.scene.textures
167
+ .filter(texture => { var _a; return !!((_a = texture.metadata) === null || _a === void 0 ? void 0 : _a[GltfExportManager._METADATA_PROPS.deleteAfterExport]); })
168
+ .forEach(texture => texture.dispose());
169
+ // reset engines max texture size and resume rendering
170
+ this.viewer.engine.getCaps().maxTextureSize = this._maxTextureSize;
171
+ this.viewer.resumeRendering();
172
+ });
173
+ }
174
+ /**
175
+ * Creates a clone of the node which should be used for the export.
176
+ * Also switches to the cloned material if required.
177
+ */
178
+ _prepareNodeForExport(node, clonedParent, excluded) {
179
+ var _a, _b;
180
+ if (!GltfExportManager._shouldExportNode(node, excluded)) {
181
+ return;
182
+ }
183
+ // from here on we only have TransformNodes
184
+ const transformNode = node;
185
+ // clone original node and create unique name (via uniqueId) for the export
186
+ const clonedNodeName = `${transformNode.name}_${transformNode.uniqueId}`;
187
+ const clonedNode = transformNode instanceof instancedMesh_1.InstancedMesh
188
+ ? (0, geometryHelper_1.createMeshFromInstancedMesh)(transformNode, clonedNodeName, clonedParent)
189
+ : transformNode.clone(clonedNodeName, clonedParent, true);
190
+ // exchange material
191
+ if (clonedNode instanceof mesh_1.Mesh) {
192
+ const exchangeWithMaterial = (_b = (_a = clonedNode.material) === null || _a === void 0 ? void 0 : _a.metadata) === null || _b === void 0 ? void 0 : _b[GltfExportManager._METADATA_PROPS.exchangeMaterialWith];
193
+ if (exchangeWithMaterial) {
194
+ clonedNode.material = this.viewer.scene.getMaterialByUniqueID(exchangeWithMaterial);
195
+ }
196
+ }
197
+ // signalize that this is a cloned node
198
+ (0, babylonHelper_1.injectMetadata)(clonedNode, {
199
+ [GltfExportManager._METADATA_PROPS.exportNode]: true,
200
+ [GltfExportManager._METADATA_PROPS.deleteAfterExport]: true,
201
+ });
202
+ // handle children
203
+ const childs = transformNode.getChildTransformNodes(true);
204
+ childs.forEach(child => this._prepareNodeForExport(child, clonedNode, excluded));
205
+ }
206
+ /**
207
+ * Help function for receiving all nodes that are marked for the export
208
+ */
209
+ _getNodesMarkedForExport(meshesOnly) {
210
+ const nodes = [...this.viewer.scene.meshes];
211
+ if (!meshesOnly) {
212
+ nodes.push(...this.viewer.scene.transformNodes);
213
+ }
214
+ const filteredNodes = nodes.filter(node => {
215
+ var _a;
216
+ return !!((_a = node.metadata) === null || _a === void 0 ? void 0 : _a[GltfExportManager._METADATA_PROPS.exportNode]) &&
217
+ // in the desired use cases we want to exclude the export root node
218
+ // maybe add a parameter if we have to include it in certain scenarios in the future
219
+ node.name !== GltfExportManager._EXPORT_ROOT_NAME;
220
+ });
221
+ return filteredNodes;
222
+ }
223
+ /**
224
+ * Defines options for the export.
225
+ * We don't allow the user to overwrite certain settings, since we rely on properties like `removeNoopRootNodes` to
226
+ * stay `true` in order to make the AR export work.
227
+ * We could theoretically allow it if AR optimization is not desired, but this may confuse the user.
228
+ */
229
+ static _gltfExportOptions(optimizeForAR, excluded) {
230
+ return {
231
+ shouldExportNode: function (node) {
232
+ var _a;
233
+ if (optimizeForAR) {
234
+ // we explicitely marked nodes, that should be exported in AR mode
235
+ return !!((_a = node.metadata) === null || _a === void 0 ? void 0 : _a[GltfExportManager._METADATA_PROPS.exportNode]);
236
+ }
237
+ else {
238
+ // use the default export node check (enabled state, exclusion list, etc...)
239
+ return GltfExportManager._shouldExportNode(node, excluded);
240
+ }
241
+ },
242
+ shouldExportAnimation: (animation) => !optimizeForAR,
243
+ };
244
+ }
245
+ /**
246
+ * Checks if a node should be available in the export
247
+ */
248
+ static _shouldExportNode(node, excluded) {
249
+ if (!(node instanceof transformNode_1.TransformNode)) {
250
+ return false;
251
+ }
252
+ // TODO: think of adding "BackgroundHelper" and nodes with "infiniteDistance" here as well, at least in AR mode
253
+ if (!node.isEnabled()) {
254
+ return false;
255
+ }
256
+ if (excluded && (0, structureHelper_1.isNodeIncludedInExclusionList)(node, excluded)) {
257
+ return false;
258
+ }
259
+ return true;
260
+ }
261
+ /**
262
+ * Creates a clone of the material which should be used for the export.
263
+ * This is mostly required for recreating textures with lower sizes.
264
+ * CAUTION: Material exchanging is not supported for materials that contain certain texture types:
265
+ * - Dynamic textures (Paintables): Cloning dynamic textures doesn't clone the canvas context
266
+ * => so the clone is just empty
267
+ * - Render target textures: Disposing the clone will leave the scene in a "not ready" state
268
+ * => this scenario is not fully analyzed yet, but it's not really worth the effort right now, since this kind of
269
+ * of texture is not really used ATM
270
+ */
271
+ static _exchangeMaterial(material) {
272
+ const baseTextures = material.getActiveTextures();
273
+ const hasDynamicTextures = baseTextures.some(texture => texture instanceof dynamicTexture_1.DynamicTexture);
274
+ const hasRenderTargetTextures = baseTextures.some(texture => texture instanceof renderTargetTexture_1.RenderTargetTexture);
275
+ if (hasDynamicTextures || hasRenderTargetTextures) {
276
+ const textureTypesString = [
277
+ hasDynamicTextures ? 'Dynamic Textures' : '',
278
+ hasRenderTargetTextures ? 'Render Target Textures' : '',
279
+ ]
280
+ .filter(Boolean)
281
+ .join();
282
+ console.warn(`Couldn't exchange material "${material.name}" in GLB export, as it contains unsupported texture type(s) (${textureTypesString}). The export will still work, but the textures of this material will keep their original size.`);
283
+ return;
284
+ }
285
+ const newName = `${material.name}_clone`;
286
+ const clonedMaterial = material.clone(newName);
287
+ const clonedTextures = clonedMaterial.getActiveTextures();
288
+ // mark all exported textures, so that they will be deleted after the export
289
+ clonedTextures.forEach(texture => (0, babylonHelper_1.injectMetadata)(texture, { [GltfExportManager._METADATA_PROPS.deleteAfterExport]: true }));
290
+ (0, babylonHelper_1.injectMetadata)(material, { [GltfExportManager._METADATA_PROPS.exchangeMaterialWith]: clonedMaterial.uniqueId });
291
+ (0, babylonHelper_1.injectMetadata)(clonedMaterial, { [GltfExportManager._METADATA_PROPS.deleteAfterExport]: true });
292
+ }
293
+ }
294
+ exports.GltfExportManager = GltfExportManager;
295
+ GltfExportManager._METADATA_PROPS = {
296
+ exportNode: 'exportNode',
297
+ deleteAfterExport: 'deleteAfterExport',
298
+ exchangeMaterialWith: 'exchangeMaterialWith',
299
+ };
300
+ GltfExportManager._EXPORT_ROOT_NAME = '__export_root__';
300
301
  //# sourceMappingURL=gltfExportManager.js.map