@combeenation/3d-viewer 14.0.1-rc1 → 15.0.0

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 (81) hide show
  1. package/README.md +9 -9
  2. package/dist/lib-cjs/buildinfo.json +3 -3
  3. package/dist/lib-cjs/commonjs.tsconfig.tsbuildinfo +1 -1
  4. package/dist/lib-cjs/index.d.ts +51 -62
  5. package/dist/lib-cjs/index.js +84 -94
  6. package/dist/lib-cjs/index.js.map +1 -1
  7. package/dist/lib-cjs/internal/cbn-custom-babylon-loader-plugin.d.ts +10 -10
  8. package/dist/lib-cjs/internal/cbn-custom-babylon-loader-plugin.js +131 -131
  9. package/dist/lib-cjs/internal/cbn-custom-babylon-loader-plugin.js.map +1 -1
  10. package/dist/lib-cjs/internal/cloning-helper.d.ts +19 -19
  11. package/dist/lib-cjs/internal/cloning-helper.js +163 -163
  12. package/dist/lib-cjs/internal/device-helper.d.ts +9 -9
  13. package/dist/lib-cjs/internal/device-helper.js +24 -24
  14. package/dist/lib-cjs/internal/geometry-helper.d.ts +21 -21
  15. package/dist/lib-cjs/internal/geometry-helper.js +145 -145
  16. package/dist/lib-cjs/internal/metadata-helper.d.ts +26 -26
  17. package/dist/lib-cjs/internal/metadata-helper.js +50 -50
  18. package/dist/lib-cjs/internal/paintable-helper.d.ts +40 -40
  19. package/dist/lib-cjs/internal/paintable-helper.js +234 -286
  20. package/dist/lib-cjs/internal/paintable-helper.js.map +1 -1
  21. package/dist/lib-cjs/internal/svg-helper.d.ts +4 -0
  22. package/dist/lib-cjs/internal/svg-helper.js +67 -0
  23. package/dist/lib-cjs/internal/svg-helper.js.map +1 -0
  24. package/dist/lib-cjs/internal/tags-helper.d.ts +12 -12
  25. package/dist/lib-cjs/internal/tags-helper.js +39 -37
  26. package/dist/lib-cjs/internal/tags-helper.js.map +1 -1
  27. package/dist/lib-cjs/internal/texture-parameter-helper.d.ts +37 -0
  28. package/dist/lib-cjs/internal/texture-parameter-helper.js +287 -0
  29. package/dist/lib-cjs/internal/texture-parameter-helper.js.map +1 -0
  30. package/dist/lib-cjs/manager/camera-manager.d.ts +110 -110
  31. package/dist/lib-cjs/manager/camera-manager.js +209 -206
  32. package/dist/lib-cjs/manager/camera-manager.js.map +1 -1
  33. package/dist/lib-cjs/manager/debug-manager.d.ts +60 -60
  34. package/dist/lib-cjs/manager/debug-manager.js +217 -217
  35. package/dist/lib-cjs/manager/event-manager.d.ts +52 -52
  36. package/dist/lib-cjs/manager/event-manager.js +71 -71
  37. package/dist/lib-cjs/manager/gltf-export-manager.d.ts +75 -84
  38. package/dist/lib-cjs/manager/gltf-export-manager.js +286 -290
  39. package/dist/lib-cjs/manager/gltf-export-manager.js.map +1 -1
  40. package/dist/lib-cjs/manager/material-manager.d.ts +35 -35
  41. package/dist/lib-cjs/manager/material-manager.js +125 -125
  42. package/dist/lib-cjs/manager/model-manager.d.ts +145 -145
  43. package/dist/lib-cjs/manager/model-manager.js +382 -382
  44. package/dist/lib-cjs/manager/parameter-manager.d.ts +228 -210
  45. package/dist/lib-cjs/manager/parameter-manager.js +573 -514
  46. package/dist/lib-cjs/manager/parameter-manager.js.map +1 -1
  47. package/dist/lib-cjs/manager/scene-manager.d.ts +45 -45
  48. package/dist/lib-cjs/manager/scene-manager.js +64 -64
  49. package/dist/lib-cjs/manager/texture-manager.d.ts +12 -12
  50. package/dist/lib-cjs/manager/texture-manager.js +43 -43
  51. package/dist/lib-cjs/viewer-error.d.ts +49 -48
  52. package/dist/lib-cjs/viewer-error.js +61 -60
  53. package/dist/lib-cjs/viewer-error.js.map +1 -1
  54. package/dist/lib-cjs/viewer.d.ts +115 -115
  55. package/dist/lib-cjs/viewer.js +217 -217
  56. package/dist/lib-cjs/viewer.js.map +1 -1
  57. package/package.json +94 -91
  58. package/src/buildinfo.json +3 -3
  59. package/src/dev.ts +47 -47
  60. package/src/global-types.d.ts +39 -39
  61. package/src/index.ts +71 -81
  62. package/src/internal/cbn-custom-babylon-loader-plugin.ts +159 -159
  63. package/src/internal/cloning-helper.ts +225 -225
  64. package/src/internal/device-helper.ts +25 -25
  65. package/src/internal/geometry-helper.ts +181 -181
  66. package/src/internal/metadata-helper.ts +63 -63
  67. package/src/internal/paintable-helper.ts +258 -310
  68. package/src/internal/svg-helper.ts +52 -0
  69. package/src/internal/tags-helper.ts +43 -41
  70. package/src/internal/texture-parameter-helper.ts +353 -0
  71. package/src/manager/camera-manager.ts +368 -365
  72. package/src/manager/debug-manager.ts +245 -245
  73. package/src/manager/event-manager.ts +72 -72
  74. package/src/manager/gltf-export-manager.ts +356 -357
  75. package/src/manager/material-manager.ts +135 -135
  76. package/src/manager/model-manager.ts +458 -458
  77. package/src/manager/parameter-manager.ts +730 -652
  78. package/src/manager/scene-manager.ts +101 -101
  79. package/src/manager/texture-manager.ts +32 -32
  80. package/src/viewer-error.ts +69 -68
  81. package/src/viewer.ts +290 -290
@@ -1,291 +1,287 @@
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 index_1 = require("../index");
14
- const device_helper_1 = require("../internal/device-helper");
15
- const geometry_helper_1 = require("../internal/geometry-helper");
16
- const geometry_helper_2 = require("../internal/geometry-helper");
17
- const metadata_helper_1 = require("../internal/metadata-helper");
18
- /**
19
- * Manager for gltf export and augmented reality features
20
- */
21
- class GltfExportManager {
22
- /** @internal */
23
- constructor(viewer) {
24
- this.viewer = viewer;
25
- /**
26
- * Animation groups which have been removed from the scene before export for AR and which need to be re-added
27
- * afterwards.
28
- *
29
- * AR does not work on Android (i.e. the modelviewer) when animation groups are present in the scene.
30
- * See CB-10055 for more details.
31
- */
32
- this._animationGroupsToRestore = [];
33
- // store initial max texture size, so that we can restore it in the post processing
34
- this._maxTextureSize = viewer.engine.getCaps().maxTextureSize;
35
- }
36
- /**
37
- * Defines options for the export.
38
- * We don't allow the user to overwrite certain settings, since we rely on properties like `removeNoopRootNodes` to
39
- * stay `true` in order to make the AR export work.
40
- * We could theoretically allow it if AR optimization is not desired, but this may confuse the user.
41
- */
42
- static _gltfExportOptions(optimizeForAR, excluded) {
43
- return {
44
- shouldExportNode: function (node) {
45
- if (optimizeForAR) {
46
- // we explicitely marked nodes, that should be exported in AR mode
47
- return (0, metadata_helper_1.getInternalMetadataValue)(node, 'exportNode');
48
- }
49
- else {
50
- // use the default export node check (enabled state, exclusion list, etc...)
51
- return GltfExportManager._shouldExportNode(node, excluded);
52
- }
53
- },
54
- };
55
- }
56
- /**
57
- * Checks if a node should be available in the export
58
- */
59
- static _shouldExportNode(node, excluded) {
60
- if (!(node instanceof index_1.TransformNode)) {
61
- return false;
62
- }
63
- // TODO WTT: think of adding "BackgroundHelper" and nodes with "infiniteDistance" here as well, at least in AR mode
64
- if (!node.isEnabled()) {
65
- return false;
66
- }
67
- if (excluded && (0, geometry_helper_2.isNodeExcluded)(node, excluded)) {
68
- return false;
69
- }
70
- return true;
71
- }
72
- /**
73
- * Creates a clone of the material which should be used for the export.
74
- * This is mostly required for recreating textures with lower sizes.
75
- * CAUTION: Material exchanging is not supported for materials that contain certain texture types:
76
- * - Dynamic textures (Paintables): Cloning dynamic textures doesn't clone the canvas context
77
- * => so the clone is just empty
78
- * - Render target textures: Disposing the clone will leave the scene in a "not ready" state
79
- * => this scenario is not fully analyzed yet, but it's not really worth the effort right now, since this kind of
80
- * of texture is not really used ATM
81
- */
82
- static _exchangeMaterial(material) {
83
- const baseTextures = material.getActiveTextures();
84
- const hasDynamicTextures = baseTextures.some(texture => texture instanceof index_1.DynamicTexture);
85
- const hasRenderTargetTextures = baseTextures.some(texture => texture instanceof index_1.RenderTargetTexture);
86
- if (hasDynamicTextures || hasRenderTargetTextures) {
87
- const textureTypesString = [
88
- hasDynamicTextures ? 'Dynamic Textures' : '',
89
- hasRenderTargetTextures ? 'Render Target Textures' : '',
90
- ]
91
- .filter(Boolean)
92
- .join();
93
- 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.`);
94
- return;
95
- }
96
- const newName = `${material.name}_clone`;
97
- const clonedMaterial = material.clone(newName);
98
- (0, metadata_helper_1.cloneInternalMetadata)(material, clonedMaterial);
99
- const clonedTextures = clonedMaterial.getActiveTextures();
100
- // mark all exported textures, so that they will be deleted after the export
101
- clonedTextures.forEach(texture => (0, metadata_helper_1.setInternalMetadataValue)(texture, 'deleteAfterExport', true));
102
- (0, metadata_helper_1.setInternalMetadataValue)(material, 'exchangeMaterialWith', clonedMaterial.uniqueId);
103
- (0, metadata_helper_1.setInternalMetadataValue)(clonedMaterial, 'deleteAfterExport', true);
104
- }
105
- /**
106
- * Exports selected nodes to a file.
107
- * @param filename Optional name of the exported .GLB file.
108
- * @param optimizeForAR Adjusts the exported GLB so that known issues get automatically fixed, this
109
- * is mostly targeting Apples .usdz format.
110
- * @param excluded Optional list of geometry (meshes, elements, variants,...) to be excluded from the export.
111
- */
112
- exportGlb(filename = 'glb-export.glb', optimizeForAR = false, excluded) {
113
- return __awaiter(this, void 0, void 0, function* () {
114
- yield this._exportPreProcess(optimizeForAR, excluded);
115
- const glbData = yield index_1.GLTF2Export.GLBAsync(this.viewer.scene, 'dummy', GltfExportManager._gltfExportOptions(optimizeForAR, excluded));
116
- yield this._exportPostProcess(optimizeForAR);
117
- const resBlob = glbData.glTFFiles['dummy.glb'];
118
- // check if result is valid, according to the typings this could also be a string
119
- if (resBlob instanceof Blob) {
120
- if (!filename.endsWith('.glb')) {
121
- filename += '.glb';
122
- }
123
- return new File([resBlob], filename);
124
- }
125
- else {
126
- // result was not a valid blob
127
- return undefined;
128
- }
129
- });
130
- }
131
- /**
132
- * Exports selected nodes to GLTF. This may result in more than one file, since textures are exported seperately.
133
- * @param filename Name of the main (text-based) .GLTF file referring to separate texture files.
134
- * @param optimizeForAR Adjusts the exported GLB so that known issues get automatically fixed, this
135
- * is mostly targeting Apples .usdz format.
136
- * @param excluded Optional list of geometry (meshes, elements, variants,...) to be excluded from the export.
137
- */
138
- exportGltfToFile(filename, optimizeForAR = false, excluded) {
139
- return __awaiter(this, void 0, void 0, function* () {
140
- yield this._exportPreProcess(optimizeForAR, excluded);
141
- const gltf = yield index_1.GLTF2Export.GLTFAsync(this.viewer.scene, filename, GltfExportManager._gltfExportOptions(optimizeForAR, excluded));
142
- gltf.downloadFiles();
143
- this._exportPostProcess(optimizeForAR);
144
- });
145
- }
146
- /**
147
- * Exports selected nodes to GLB. This results in one binary file.
148
- * @param filename Name of the main (text-based) .GLTF file referring to seperate texture files.
149
- * @param optimizeForAR Adjusts the exported GLB so that known issues get automatically fixed, this
150
- * is mostly targeting Apples .usdz format.
151
- * @param excluded Optional list of geometry (meshes, elements, variants,...) to be excluded from the export.
152
- */
153
- exportGlbToFile(filename, optimizeForAR = false, excluded) {
154
- return __awaiter(this, void 0, void 0, function* () {
155
- yield this._exportPreProcess(optimizeForAR, excluded);
156
- const glb = yield index_1.GLTF2Export.GLBAsync(this.viewer.scene, filename, GltfExportManager._gltfExportOptions(optimizeForAR, excluded));
157
- glb.downloadFiles();
158
- yield this._exportPostProcess(optimizeForAR);
159
- });
160
- }
161
- /**
162
- * Prepares scene for GLB export.
163
- * This is very important for AR exports, since we have to do a lot of conversions to satisfy Apples .usdz format.
164
- */
165
- _exportPreProcess(optimizeForAR, excluded) {
166
- return __awaiter(this, void 0, void 0, function* () {
167
- if (!optimizeForAR) {
168
- // actually nothing to do if AR optimization is not required
169
- return;
170
- }
171
- // pause rendering, since we are altering the active scene, which should not be visible to the user
172
- this.viewer.pauseRendering();
173
- this._animationGroupsToRestore = [...this.viewer.scene.animationGroups];
174
- this._animationGroupsToRestore.forEach(x => this.viewer.scene.removeAnimationGroup(x));
175
- // exchange materials if required
176
- // the AR export should never contain textures larger than 1024 px:
177
- // - iOS devices will crash most likely when trying to access AR endpoints with such files
178
- // - file size will be reduced, which leads to faster loading times
179
- // - textures > 1024 px shouldn't make a difference on mobiles anyway
180
- // we don't have to rescale anything if are already on a downscaled device, since the textures are already <= 1024
181
- // also we have to be very cautios with copying textures on these devices, since we are potentially very limited
182
- // with the available memory
183
- const isScaledDownDevice = (0, device_helper_1.getIsScaledDownDevice)(this.viewer.viewerSettings.limitTextureSize);
184
- if (!isScaledDownDevice) {
185
- // the idea is to re-create all textures with a smaller texture size
186
- // we have to exchange all materials for this to work
187
- this.viewer.engine.clearInternalTexturesCache();
188
- this.viewer.engine.getCaps().maxTextureSize = 1024;
189
- this.viewer.scene.materials
190
- .filter(material => material instanceof index_1.PBRMaterial)
191
- .forEach(material => GltfExportManager._exchangeMaterial(material));
192
- }
193
- // since Babylon.js v6 the conversion to right handed GLB coordinate system is done differently
194
- // previously the geometry itself has been altered, now they negate the scaling of all root nodes
195
- // this is an issue for us, since we will receive this negated scalings in the exported GLB, which leads to issues
196
- // on iOS devices
197
- // we fix that by adding a top level root node with a negative scaling as well
198
- // the exporter just removes this node as he detects a "noop root node" (implementation details of Babylon.js)
199
- // everything beneath this node remains untouched
200
- // TODO BJS Update: Test AR export on iPhones as well and double check if we still need this special logic
201
- const exportRootNode = new index_1.TransformNode(GltfExportManager._EXPORT_ROOT_NAME, this.viewer.scene);
202
- exportRootNode.scaling = new index_1.Vector3(-1, 1, 1);
203
- (0, metadata_helper_1.setInternalMetadataValue)(exportRootNode, 'exportNode', true);
204
- (0, metadata_helper_1.setInternalMetadataValue)(exportRootNode, 'deleteAfterExport', true);
205
- // create clones of each node (recursively), optionally exchange with cloned materials and mark these nodes for the
206
- // export
207
- this.viewer.scene.rootNodes
208
- .filter(rootNode => rootNode.name !== GltfExportManager._EXPORT_ROOT_NAME)
209
- .forEach(rootNode => this._prepareNodeForExport(rootNode, exportRootNode, excluded));
210
- // bake transformation of all meshes, so that no negative scalings are left
211
- // it's important that this is done AFTER instanced meshes have been converted (_prepareNodeForExport)
212
- this._getNodesMarkedForExport(true).forEach(mesh => (0, geometry_helper_1.bakeGeometryOfMesh)(mesh));
213
- // reset transformation of all "TransformNodes", which couldn't be handled by the geometry baking algorithm
214
- // it's important that this is done AFTER all geometries have been baked
215
- this._getNodesMarkedForExport().forEach(node => (0, geometry_helper_1.resetTransformation)(node));
216
- });
217
- }
218
- /**
219
- * Cleans up scene after export
220
- */
221
- _exportPostProcess(optimizeForAR) {
222
- return __awaiter(this, void 0, void 0, function* () {
223
- if (!optimizeForAR) {
224
- // nothing to do, since no changes have been made without AR optimizations
225
- return;
226
- }
227
- this._animationGroupsToRestore.forEach(x => this.viewer.scene.addAnimationGroup(x));
228
- this._animationGroupsToRestore = [];
229
- // dispose all nodes, materials and textures that have only been created for the export
230
- this.viewer.scene.rootNodes
231
- .filter(rootNode => (0, metadata_helper_1.getInternalMetadataValue)(rootNode, 'deleteAfterExport'))
232
- .forEach(rootNode => rootNode.dispose());
233
- this.viewer.scene.materials
234
- .filter(mat => (0, metadata_helper_1.getInternalMetadataValue)(mat, 'deleteAfterExport'))
235
- .forEach(material => material.dispose(false, false));
236
- this.viewer.scene.textures
237
- .filter(texture => (0, metadata_helper_1.getInternalMetadataValue)(texture, 'deleteAfterExport'))
238
- .forEach(texture => texture.dispose());
239
- // reset engines max texture size and resume rendering
240
- this.viewer.engine.getCaps().maxTextureSize = this._maxTextureSize;
241
- this.viewer.resumeRendering();
242
- });
243
- }
244
- /**
245
- * Creates a clone of the node which should be used for the export.
246
- * Also switches to the cloned material if required.
247
- */
248
- _prepareNodeForExport(node, clonedParent, excluded) {
249
- if (!GltfExportManager._shouldExportNode(node, excluded)) {
250
- return;
251
- }
252
- // from here on we only have TransformNodes
253
- const transformNode = node;
254
- // clone original node and create unique name (via uniqueId) for the export
255
- const clonedNodeName = `${transformNode.name}_${transformNode.uniqueId}`;
256
- const clonedNode = transformNode instanceof index_1.InstancedMesh
257
- ? (0, geometry_helper_1.createMeshFromInstancedMesh)(transformNode, clonedNodeName, clonedParent)
258
- : transformNode.clone(clonedNodeName, clonedParent, true);
259
- (0, metadata_helper_1.cloneInternalMetadata)(transformNode, clonedNode);
260
- // exchange material
261
- if (clonedNode instanceof index_1.Mesh) {
262
- const exchangeWithMaterial = clonedNode.material && (0, metadata_helper_1.getInternalMetadataValue)(clonedNode.material, 'exchangeMaterialWith');
263
- if (exchangeWithMaterial) {
264
- clonedNode.material = this.viewer.scene.getMaterialByUniqueID(exchangeWithMaterial);
265
- }
266
- }
267
- // signalize that this is a cloned node
268
- (0, metadata_helper_1.setInternalMetadataValue)(clonedNode, 'exportNode', true);
269
- (0, metadata_helper_1.setInternalMetadataValue)(clonedNode, 'deleteAfterExport', true);
270
- // handle children
271
- const childs = transformNode.getChildTransformNodes(true);
272
- childs.forEach(child => this._prepareNodeForExport(child, clonedNode, excluded));
273
- }
274
- /**
275
- * Help function for receiving all nodes that are marked for the export
276
- */
277
- _getNodesMarkedForExport(meshesOnly) {
278
- const nodes = [...this.viewer.scene.meshes];
279
- if (!meshesOnly) {
280
- nodes.push(...this.viewer.scene.transformNodes);
281
- }
282
- const filteredNodes = nodes.filter(node => (0, metadata_helper_1.getInternalMetadataValue)(node, 'exportNode') &&
283
- // in the desired use cases we want to exclude the export root node
284
- // maybe add a parameter if we have to include it in certain scenarios in the future
285
- node.name !== GltfExportManager._EXPORT_ROOT_NAME);
286
- return filteredNodes;
287
- }
288
- }
289
- exports.GltfExportManager = GltfExportManager;
290
- 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 index_1 = require("../index");
14
+ const device_helper_1 = require("../internal/device-helper");
15
+ const geometry_helper_1 = require("../internal/geometry-helper");
16
+ const geometry_helper_2 = require("../internal/geometry-helper");
17
+ const metadata_helper_1 = require("../internal/metadata-helper");
18
+ /**
19
+ * Manager for gltf export and augmented reality features
20
+ */
21
+ class GltfExportManager {
22
+ /** @internal */
23
+ constructor(viewer) {
24
+ this.viewer = viewer;
25
+ // store initial max texture size, so that we can restore it in the post processing
26
+ this._maxTextureSize = viewer.engine.getCaps().maxTextureSize;
27
+ }
28
+ /**
29
+ * Defines options for the export.
30
+ * We don't allow the user to overwrite certain settings, since we rely on properties like `removeNoopRootNodes` to
31
+ * stay `true` in order to make the AR export work.
32
+ * We could theoretically allow it if AR optimization is not desired, but this may confuse the user.
33
+ */
34
+ static _gltfExportOptions(optimizeForAR, excluded) {
35
+ return {
36
+ shouldExportNode: function (node) {
37
+ if (optimizeForAR) {
38
+ // we explicitely marked nodes, that should be exported in AR mode
39
+ return (0, metadata_helper_1.getInternalMetadataValue)(node, 'exportNode');
40
+ }
41
+ else {
42
+ // use the default export node check (enabled state, exclusion list, etc...)
43
+ return GltfExportManager._shouldExportNode(node, excluded);
44
+ }
45
+ },
46
+ shouldExportAnimation: (animation) => !optimizeForAR,
47
+ };
48
+ }
49
+ /**
50
+ * Checks if a node should be available in the export
51
+ */
52
+ static _shouldExportNode(node, excluded) {
53
+ if (!(node instanceof index_1.TransformNode)) {
54
+ return false;
55
+ }
56
+ // TODO WTT: think of adding "BackgroundHelper" and nodes with "infiniteDistance" here as well, at least in AR mode
57
+ if (!node.isEnabled()) {
58
+ return false;
59
+ }
60
+ if (excluded && (0, geometry_helper_2.isNodeExcluded)(node, excluded)) {
61
+ return false;
62
+ }
63
+ return true;
64
+ }
65
+ /**
66
+ * Creates a clone of the material which should be used for the export.
67
+ * This is mostly required for recreating textures with lower sizes.
68
+ * CAUTION: Material exchanging is not supported for materials that contain certain texture types:
69
+ * - Dynamic textures (Paintables): Cloning dynamic textures doesn't clone the canvas context
70
+ * => so the clone is just empty
71
+ * - Render target textures: Disposing the clone will leave the scene in a "not ready" state
72
+ * => this scenario is not fully analyzed yet, but it's not really worth the effort right now, since this kind of
73
+ * of texture is not really used ATM
74
+ */
75
+ static _exchangeMaterial(material) {
76
+ const baseTextures = material.getActiveTextures();
77
+ const hasDynamicTextures = baseTextures.some(texture => texture instanceof index_1.DynamicTexture);
78
+ const hasRenderTargetTextures = baseTextures.some(texture => texture instanceof index_1.RenderTargetTexture);
79
+ if (hasDynamicTextures || hasRenderTargetTextures) {
80
+ const textureTypesString = [
81
+ hasDynamicTextures ? 'Dynamic Textures' : '',
82
+ hasRenderTargetTextures ? 'Render Target Textures' : '',
83
+ ]
84
+ .filter(Boolean)
85
+ .join();
86
+ 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.`);
87
+ return;
88
+ }
89
+ const newName = `${material.name}_clone`;
90
+ const clonedMaterial = material.clone(newName);
91
+ // internal metadata may contain large data which slows down the export (CB-10094)
92
+ // it wasn't an issue for materials yet, but still this is safer than to make a deep clone
93
+ clonedMaterial._internalMetadata = null;
94
+ const clonedTextures = clonedMaterial.getActiveTextures();
95
+ // mark all exported textures, so that they will be deleted after the export
96
+ clonedTextures.forEach(texture => (0, metadata_helper_1.setInternalMetadataValue)(texture, 'deleteAfterExport', true));
97
+ (0, metadata_helper_1.setInternalMetadataValue)(material, 'exchangeMaterialWith', clonedMaterial.uniqueId);
98
+ (0, metadata_helper_1.setInternalMetadataValue)(clonedMaterial, 'deleteAfterExport', true);
99
+ }
100
+ /**
101
+ * Exports selected nodes to a file.
102
+ * @param filename Optional name of the exported .GLB file.
103
+ * @param optimizeForAR Adjusts the exported GLB so that known issues get automatically fixed, this
104
+ * is mostly targeting Apples .usdz format.
105
+ * @param excluded Optional list of geometry (meshes, elements, variants,...) to be excluded from the export.
106
+ */
107
+ exportGlb(filename = 'glb-export.glb', optimizeForAR = false, excluded) {
108
+ return __awaiter(this, void 0, void 0, function* () {
109
+ yield this._exportPreProcess(optimizeForAR, excluded);
110
+ const glbData = yield index_1.GLTF2Export.GLBAsync(this.viewer.scene, 'dummy', GltfExportManager._gltfExportOptions(optimizeForAR, excluded));
111
+ yield this._exportPostProcess(optimizeForAR);
112
+ const resBlob = glbData.glTFFiles['dummy.glb'];
113
+ // check if result is valid, according to the typings this could also be a string
114
+ if (resBlob instanceof Blob) {
115
+ if (!filename.endsWith('.glb')) {
116
+ filename += '.glb';
117
+ }
118
+ return new File([resBlob], filename);
119
+ }
120
+ else {
121
+ // result was not a valid blob
122
+ return undefined;
123
+ }
124
+ });
125
+ }
126
+ /**
127
+ * Exports selected nodes to GLTF. This may result in more than one file, since textures are exported seperately.
128
+ * @param filename Name of the main (text-based) .GLTF file referring to separate texture files.
129
+ * @param optimizeForAR Adjusts the exported GLB so that known issues get automatically fixed, this
130
+ * is mostly targeting Apples .usdz format.
131
+ * @param excluded Optional list of geometry (meshes, elements, variants,...) to be excluded from the export.
132
+ */
133
+ exportGltfToFile(filename, optimizeForAR = false, excluded) {
134
+ return __awaiter(this, void 0, void 0, function* () {
135
+ yield this._exportPreProcess(optimizeForAR, excluded);
136
+ const gltf = yield index_1.GLTF2Export.GLTFAsync(this.viewer.scene, filename, GltfExportManager._gltfExportOptions(optimizeForAR, excluded));
137
+ gltf.downloadFiles();
138
+ this._exportPostProcess(optimizeForAR);
139
+ });
140
+ }
141
+ /**
142
+ * Exports selected nodes to GLB. This results in one binary file.
143
+ * @param filename Name of the main (text-based) .GLTF file referring to seperate texture files.
144
+ * @param optimizeForAR Adjusts the exported GLB so that known issues get automatically fixed, this
145
+ * is mostly targeting Apples .usdz format.
146
+ * @param excluded Optional list of geometry (meshes, elements, variants,...) to be excluded from the export.
147
+ */
148
+ exportGlbToFile(filename, optimizeForAR = false, excluded) {
149
+ return __awaiter(this, void 0, void 0, function* () {
150
+ yield this._exportPreProcess(optimizeForAR, excluded);
151
+ const glb = yield index_1.GLTF2Export.GLBAsync(this.viewer.scene, filename, GltfExportManager._gltfExportOptions(optimizeForAR, excluded));
152
+ glb.downloadFiles();
153
+ yield this._exportPostProcess(optimizeForAR);
154
+ });
155
+ }
156
+ /**
157
+ * Prepares scene for GLB export.
158
+ * This is very important for AR exports, since we have to do a lot of conversions to satisfy Apples .usdz format.
159
+ */
160
+ _exportPreProcess(optimizeForAR, excluded) {
161
+ return __awaiter(this, void 0, void 0, function* () {
162
+ if (!optimizeForAR) {
163
+ // actually nothing to do if AR optimization is not required
164
+ return;
165
+ }
166
+ // pause rendering, since we are altering the active scene, which should not be visible to the user
167
+ this.viewer.pauseRendering();
168
+ // exchange materials if required
169
+ // the AR export should never contain textures larger than 1024 px:
170
+ // - iOS devices will crash most likely when trying to access AR endpoints with such files
171
+ // - file size will be reduced, which leads to faster loading times
172
+ // - textures > 1024 px shouldn't make a difference on mobiles anyway
173
+ // we don't have to rescale anything if are already on a downscaled device, since the textures are already <= 1024
174
+ // also we have to be very cautios with copying textures on these devices, since we are potentially very limited
175
+ // with the available memory
176
+ const isScaledDownDevice = (0, device_helper_1.getIsScaledDownDevice)(this.viewer.viewerSettings.limitTextureSize);
177
+ if (!isScaledDownDevice) {
178
+ // the idea is to re-create all textures with a smaller texture size
179
+ // we have to exchange all materials for this to work
180
+ this.viewer.engine.clearInternalTexturesCache();
181
+ this.viewer.engine.getCaps().maxTextureSize = 1024;
182
+ this.viewer.scene.materials
183
+ .filter(material => material instanceof index_1.PBRMaterial)
184
+ .forEach(material => GltfExportManager._exchangeMaterial(material));
185
+ }
186
+ // since Babylon.js v6 the conversion to right handed GLB coordinate system is done differently
187
+ // previously the geometry itself has been altered, now they negate the scaling of all root nodes
188
+ // this is an issue for us, since we will receive this negated scalings in the exported GLB, which leads to issues
189
+ // on iOS devices
190
+ // we fix that by adding a top level root node with a negative scaling as well
191
+ // the exporter just removes this node as he detects a "noop root node" (implementation details of Babylon.js)
192
+ // everything beneath this node remains untouched
193
+ // TODO BJS Update: Test AR export on iPhones as well and double check if we still need this special logic
194
+ const exportRootNode = new index_1.TransformNode(GltfExportManager._EXPORT_ROOT_NAME, this.viewer.scene);
195
+ exportRootNode.scaling = new index_1.Vector3(-1, 1, 1);
196
+ (0, metadata_helper_1.setInternalMetadataValue)(exportRootNode, 'exportNode', true);
197
+ (0, metadata_helper_1.setInternalMetadataValue)(exportRootNode, 'deleteAfterExport', true);
198
+ // create clones of each node (recursively), optionally exchange with cloned materials and mark these nodes for the
199
+ // export
200
+ this.viewer.scene.rootNodes
201
+ .filter(rootNode => rootNode.name !== GltfExportManager._EXPORT_ROOT_NAME)
202
+ .forEach(rootNode => this._prepareNodeForExport(rootNode, exportRootNode, excluded));
203
+ // bake transformation of all meshes, so that no negative scalings are left
204
+ // it's important that this is done AFTER instanced meshes have been converted (_prepareNodeForExport)
205
+ this._getNodesMarkedForExport(true).forEach(mesh => (0, geometry_helper_1.bakeGeometryOfMesh)(mesh));
206
+ // reset transformation of all "TransformNodes", which couldn't be handled by the geometry baking algorithm
207
+ // it's important that this is done AFTER all geometries have been baked
208
+ this._getNodesMarkedForExport().forEach(node => (0, geometry_helper_1.resetTransformation)(node));
209
+ });
210
+ }
211
+ /**
212
+ * Cleans up scene after export
213
+ */
214
+ _exportPostProcess(optimizeForAR) {
215
+ return __awaiter(this, void 0, void 0, function* () {
216
+ if (!optimizeForAR) {
217
+ // nothing to do, since no changes have been made without AR optimizations
218
+ return;
219
+ }
220
+ // dispose all nodes, materials and textures that have only been created for the export
221
+ this.viewer.scene.rootNodes
222
+ .filter(rootNode => (0, metadata_helper_1.getInternalMetadataValue)(rootNode, 'deleteAfterExport'))
223
+ .forEach(rootNode => rootNode.dispose());
224
+ this.viewer.scene.materials
225
+ .filter(material => (0, metadata_helper_1.getInternalMetadataValue)(material, 'deleteAfterExport'))
226
+ .forEach(material => material.dispose(false, false));
227
+ // clean up temporary material exchange key for the rest of materials
228
+ this.viewer.scene.materials.forEach(material => (0, metadata_helper_1.clearInternalMetadataValue)(material, 'exchangeMaterialWith'));
229
+ this.viewer.scene.textures
230
+ .filter(texture => (0, metadata_helper_1.getInternalMetadataValue)(texture, 'deleteAfterExport'))
231
+ .forEach(texture => texture.dispose());
232
+ // reset engines max texture size and resume rendering
233
+ this.viewer.engine.getCaps().maxTextureSize = this._maxTextureSize;
234
+ this.viewer.resumeRendering();
235
+ });
236
+ }
237
+ /**
238
+ * Creates a clone of the node which should be used for the export.
239
+ * Also switches to the cloned material if required.
240
+ */
241
+ _prepareNodeForExport(node, clonedParent, excluded) {
242
+ if (!GltfExportManager._shouldExportNode(node, excluded)) {
243
+ return;
244
+ }
245
+ // from here on we only have TransformNodes
246
+ const transformNode = node;
247
+ // clone original node and create unique name (via uniqueId) for the export
248
+ const clonedNodeName = `${transformNode.name}_${transformNode.uniqueId}`;
249
+ const clonedNode = transformNode instanceof index_1.InstancedMesh
250
+ ? (0, geometry_helper_1.createMeshFromInstancedMesh)(transformNode, clonedNodeName, clonedParent)
251
+ : transformNode.clone(clonedNodeName, clonedParent, true);
252
+ // nodes with node geometry have very large internal metadata, this leads to long export times (CB-10094)
253
+ // existing internal metadata is not required for the export so we can just delete it
254
+ // internal metadata will be set some lines beyond!
255
+ clonedNode._internalMetadata = null;
256
+ // exchange material
257
+ if (clonedNode instanceof index_1.Mesh) {
258
+ const exchangeWithMaterial = clonedNode.material && (0, metadata_helper_1.getInternalMetadataValue)(clonedNode.material, 'exchangeMaterialWith');
259
+ if (exchangeWithMaterial) {
260
+ clonedNode.material = this.viewer.scene.getMaterialByUniqueID(exchangeWithMaterial);
261
+ }
262
+ }
263
+ // signalize that this is a cloned node
264
+ (0, metadata_helper_1.setInternalMetadataValue)(clonedNode, 'exportNode', true);
265
+ (0, metadata_helper_1.setInternalMetadataValue)(clonedNode, 'deleteAfterExport', true);
266
+ // handle children
267
+ const childs = transformNode.getChildTransformNodes(true);
268
+ childs.forEach(child => this._prepareNodeForExport(child, clonedNode, excluded));
269
+ }
270
+ /**
271
+ * Help function for receiving all nodes that are marked for the export
272
+ */
273
+ _getNodesMarkedForExport(meshesOnly) {
274
+ const nodes = [...this.viewer.scene.meshes];
275
+ if (!meshesOnly) {
276
+ nodes.push(...this.viewer.scene.transformNodes);
277
+ }
278
+ const filteredNodes = nodes.filter(node => (0, metadata_helper_1.getInternalMetadataValue)(node, 'exportNode') &&
279
+ // in the desired use cases we want to exclude the export root node
280
+ // maybe add a parameter if we have to include it in certain scenarios in the future
281
+ node.name !== GltfExportManager._EXPORT_ROOT_NAME);
282
+ return filteredNodes;
283
+ }
284
+ }
285
+ exports.GltfExportManager = GltfExportManager;
286
+ GltfExportManager._EXPORT_ROOT_NAME = '__export_root__';
291
287
  //# sourceMappingURL=gltf-export-manager.js.map