@combeenation/3d-viewer 18.2.0 → 18.3.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 (33) hide show
  1. package/dist/lib-cjs/buildinfo.json +1 -1
  2. package/dist/lib-cjs/commonjs.tsconfig.tsbuildinfo +1 -1
  3. package/dist/lib-cjs/index.d.ts +1 -0
  4. package/dist/lib-cjs/index.js +1 -0
  5. package/dist/lib-cjs/index.js.map +1 -1
  6. package/dist/lib-cjs/internal/export-helper.d.ts +34 -0
  7. package/dist/lib-cjs/internal/export-helper.js +306 -0
  8. package/dist/lib-cjs/internal/export-helper.js.map +1 -0
  9. package/dist/lib-cjs/internal/node-helper.js +2 -2
  10. package/dist/lib-cjs/internal/node-helper.js.map +1 -1
  11. package/dist/lib-cjs/manager/camera-manager.js +2 -6
  12. package/dist/lib-cjs/manager/camera-manager.js.map +1 -1
  13. package/dist/lib-cjs/manager/dxf-export-manager.d.ts +39 -0
  14. package/dist/lib-cjs/manager/dxf-export-manager.js +116 -0
  15. package/dist/lib-cjs/manager/dxf-export-manager.js.map +1 -0
  16. package/dist/lib-cjs/manager/gltf-export-manager.d.ts +19 -39
  17. package/dist/lib-cjs/manager/gltf-export-manager.js +38 -179
  18. package/dist/lib-cjs/manager/gltf-export-manager.js.map +1 -1
  19. package/dist/lib-cjs/viewer.d.ts +3 -1
  20. package/dist/lib-cjs/viewer.js +4 -0
  21. package/dist/lib-cjs/viewer.js.map +1 -1
  22. package/package.json +3 -2
  23. package/src/index.ts +1 -0
  24. package/src/internal/export-helper.ts +378 -0
  25. package/src/internal/node-helper.ts +2 -2
  26. package/src/manager/camera-manager.ts +2 -6
  27. package/src/manager/dxf-export-manager.ts +123 -0
  28. package/src/manager/gltf-export-manager.ts +38 -231
  29. package/src/viewer.ts +6 -0
  30. package/dist/lib-cjs/internal/geometry-helper.d.ts +0 -14
  31. package/dist/lib-cjs/internal/geometry-helper.js +0 -114
  32. package/dist/lib-cjs/internal/geometry-helper.js.map +0 -1
  33. package/src/internal/geometry-helper.ts +0 -144
@@ -1,27 +1,25 @@
1
+ import { Animation, GLTF2Export, IExportOptions, Node, NodeDescription, Viewer } from '../index';
1
2
  import {
2
- Animation,
3
- DynamicTexture,
4
- GLTF2Export,
5
- IExportOptions,
6
- InstancedMesh,
7
- Material,
8
- Mesh,
9
- Node,
10
- NodeDescription,
11
- PBRMaterial,
12
- RenderTargetTexture,
13
- TransformNode,
14
- Viewer,
15
- } from '../index';
16
- import { getIsScaledDownDevice } from '../internal/device-helper';
17
- import { bakeGeometryOfMesh, createMeshFromInstancedMesh, resetTransformation } from '../internal/geometry-helper';
18
- import {
19
- clearInternalMetadataValue,
20
- cloneInternalMetadata,
21
- getInternalMetadataValue,
22
- setInternalMetadataValue,
23
- } from '../internal/metadata-helper';
24
- import { nodeMatchesAnyCriteria } from '../internal/node-helper';
3
+ exportPostProcess,
4
+ exportPreProcess,
5
+ isExportableTransformNode,
6
+ normalizeFileName,
7
+ } from '../internal/export-helper';
8
+ import { getInternalMetadataValue } from '../internal/metadata-helper';
9
+
10
+ /**
11
+ * Interface TODOS
12
+ * ===============
13
+ * - create settings object instead of individual input parameters (optimizeForAR, excludeNodes, fileName)
14
+ * - see `DxfExportManager`
15
+ * - much more flexible when adding new parameters
16
+ * - rename functions to create/download, instead of suffixing "ToFile"
17
+ * - also see `DxfExportManager`
18
+ *
19
+ * Viewer control is directly accessing these functions, so introducing breaking changes here is really annoying, as we
20
+ * have to add another version switch in the source code of the viewer control.
21
+ * Maybe there is a chance to update the interface when re-creating the viewer control in the new cfgr editor.
22
+ */
25
23
 
26
24
  /**
27
25
  * Manager for gltf export and augmented reality features
@@ -43,7 +41,7 @@ export class GltfExportManager {
43
41
  return !!getInternalMetadataValue(node, 'exportNode');
44
42
  } else {
45
43
  // use the default export node check (enabled state, exclusion list, etc...)
46
- return GltfExportManager._shouldExportNode(node, excludeNodes);
44
+ return isExportableTransformNode(node, excludeNodes);
47
45
  }
48
46
  },
49
47
 
@@ -51,64 +49,6 @@ export class GltfExportManager {
51
49
  };
52
50
  }
53
51
 
54
- /**
55
- * Checks if a node should be available in the export
56
- */
57
- protected static _shouldExportNode(node: Node, excludeNodes?: NodeDescription[]): boolean {
58
- if (!(node instanceof TransformNode)) {
59
- return false;
60
- }
61
-
62
- // maybe add some other criterias like "hasInfiniteDistance" and "isGeneratedBackgroundMesh" here as well
63
- const isExcluded = nodeMatchesAnyCriteria(node, {
64
- isInList: excludeNodes,
65
- isDisabled: true,
66
- isHtmlAnchorMesh: true,
67
- });
68
-
69
- return !isExcluded;
70
- }
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
- protected static _exchangeMaterial(material: Material): void {
83
- const baseTextures = material.getActiveTextures();
84
- const hasDynamicTextures = baseTextures.some(texture => texture instanceof DynamicTexture);
85
- const hasRenderTargetTextures = baseTextures.some(texture => texture instanceof 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(
94
- `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.`
95
- );
96
-
97
- return;
98
- }
99
-
100
- const newName = `${material.name}_clone`;
101
- const clonedMaterial = material.clone(newName)!;
102
- cloneInternalMetadata(material, clonedMaterial);
103
- const clonedTextures = clonedMaterial.getActiveTextures();
104
-
105
- // mark all exported textures, so that they will be deleted after the export
106
- clonedTextures.forEach(texture => setInternalMetadataValue(texture, 'deleteAfterExport', true));
107
-
108
- setInternalMetadataValue(material, 'exchangeMaterialWith', clonedMaterial.uniqueId);
109
- setInternalMetadataValue(clonedMaterial, 'deleteAfterExport', true);
110
- }
111
-
112
52
  /** @internal */
113
53
  public constructor(protected viewer: Viewer) {
114
54
  // store initial max texture size, so that we can restore it in the post processing
@@ -117,17 +57,17 @@ export class GltfExportManager {
117
57
 
118
58
  /**
119
59
  * Exports selected nodes to a file.
120
- * @param filename Optional name of the exported .GLB file.
60
+ * @param fileName Optional name of the exported .GLB file.
121
61
  * @param optimizeForAR Adjusts the exported GLB so that known issues get automatically fixed, this
122
62
  * is mostly targeting Apples .usdz format.
123
63
  * @param excludeNodes Optional list of nodes to be excluded from the export.
124
64
  */
125
65
  public async exportGlb(
126
- filename = 'glb-export.glb',
66
+ fileName?: string,
127
67
  optimizeForAR: boolean = false,
128
68
  excludeNodes?: NodeDescription[]
129
69
  ): Promise<File | undefined> {
130
- await this._exportPreProcess(optimizeForAR, excludeNodes);
70
+ if (optimizeForAR) await exportPreProcess(this.viewer, { excludeNodes, scaleDownTextures: true });
131
71
 
132
72
  const glbData = await GLTF2Export.GLBAsync(
133
73
  this.viewer.scene,
@@ -135,15 +75,13 @@ export class GltfExportManager {
135
75
  GltfExportManager._gltfExportOptions(optimizeForAR, excludeNodes)
136
76
  );
137
77
 
138
- await this._exportPostProcess(optimizeForAR);
78
+ if (optimizeForAR) await exportPostProcess(this.viewer);
139
79
 
140
80
  const resBlob = glbData.glTFFiles['dummy.glb'];
141
81
  // check if result is valid, according to the typings this could also be a string
142
82
  if (resBlob instanceof Blob) {
143
- if (!filename.endsWith('.glb')) {
144
- filename += '.glb';
145
- }
146
- return new File([resBlob], filename);
83
+ const normalizedFileName = normalizeFileName(fileName, 'glb', 'glb-export');
84
+ return new File([resBlob], normalizedFileName);
147
85
  } else {
148
86
  // result was not a valid blob
149
87
  return undefined;
@@ -158,175 +96,44 @@ export class GltfExportManager {
158
96
  * @param excludeNodes Optional list of nodes to be excluded from the export.
159
97
  */
160
98
  public async exportGltfToFile(
161
- filename: string,
99
+ fileName: string,
162
100
  optimizeForAR: boolean = false,
163
101
  excludeNodes?: NodeDescription[]
164
102
  ): Promise<void> {
165
- await this._exportPreProcess(optimizeForAR, excludeNodes);
103
+ if (optimizeForAR) await exportPreProcess(this.viewer, { excludeNodes, scaleDownTextures: true });
166
104
 
167
105
  const gltf = await GLTF2Export.GLTFAsync(
168
106
  this.viewer.scene,
169
- filename,
107
+ // no need to add .glb, as Babylon.js does that internally
108
+ fileName,
170
109
  GltfExportManager._gltfExportOptions(optimizeForAR, excludeNodes)
171
110
  );
172
111
  gltf.downloadFiles();
173
112
 
174
- this._exportPostProcess(optimizeForAR);
113
+ if (optimizeForAR) await exportPostProcess(this.viewer);
175
114
  }
176
115
 
177
116
  /**
178
117
  * Exports selected nodes to GLB. This results in one binary file.
179
- * @param filename Name of the main (text-based) .GLTF file referring to seperate texture files.
118
+ * @param fileName Name of the main (text-based) .GLTF file referring to seperate texture files.
180
119
  * @param optimizeForAR Adjusts the exported GLB so that known issues get automatically fixed, this
181
120
  * is mostly targeting Apples .usdz format.
182
121
  * @param excludeNodes Optional list of nodes to be excluded from the export.
183
122
  */
184
123
  public async exportGlbToFile(
185
- filename: string,
124
+ fileName: string,
186
125
  optimizeForAR: boolean = false,
187
126
  excludeNodes?: NodeDescription[]
188
127
  ): Promise<void> {
189
- await this._exportPreProcess(optimizeForAR, excludeNodes);
128
+ if (optimizeForAR) await exportPreProcess(this.viewer, { excludeNodes, scaleDownTextures: true });
190
129
 
191
130
  const glb = await GLTF2Export.GLBAsync(
192
131
  this.viewer.scene,
193
- filename,
132
+ fileName,
194
133
  GltfExportManager._gltfExportOptions(optimizeForAR, excludeNodes)
195
134
  );
196
135
  glb.downloadFiles();
197
136
 
198
- await this._exportPostProcess(optimizeForAR);
199
- }
200
-
201
- /**
202
- * Prepares scene for GLB export.
203
- * This is very important for AR exports, since we have to do a lot of conversions to satisfy Apples .usdz format.
204
- */
205
- protected async _exportPreProcess(optimizeForAR: boolean, excludeNodes?: NodeDescription[]): Promise<void> {
206
- if (!optimizeForAR) {
207
- // actually nothing to do if AR optimization is not required
208
- return;
209
- }
210
-
211
- // pause rendering, since we are altering the active scene, which should not be visible to the user
212
- this.viewer.pauseRendering();
213
-
214
- // exchange materials if required
215
- // the AR export should never contain textures larger than 1024 px:
216
- // - iOS devices will crash most likely when trying to access AR endpoints with such files
217
- // - file size will be reduced, which leads to faster loading times
218
- // - textures > 1024 px shouldn't make a difference on mobiles anyway
219
- // we don't have to rescale anything if are already on a downscaled device, since the textures are already <= 1024
220
- // also we have to be very cautios with copying textures on these devices, since we are potentially very limited
221
- // with the available memory
222
- const isScaledDownDevice = getIsScaledDownDevice(this.viewer.viewerSettings.limitTextureSize);
223
- if (!isScaledDownDevice) {
224
- // the idea is to re-create all textures with a smaller texture size
225
- // we have to exchange all materials for this to work
226
- this.viewer.engine.clearInternalTexturesCache();
227
- this.viewer.engine.getCaps().maxTextureSize = 1024;
228
-
229
- this.viewer.scene.materials
230
- .filter(material => material instanceof PBRMaterial)
231
- .forEach(material => GltfExportManager._exchangeMaterial(material as PBRMaterial));
232
- }
233
-
234
- // create clones of each node (recursively), optionally exchange with cloned materials and mark these nodes for the
235
- // export
236
- this.viewer.scene.rootNodes
237
- // .filter(rootNode => rootNode.name !== GltfExportManager._EXPORT_ROOT_NAME)
238
- .forEach(rootNode => this._prepareNodeForExport(rootNode, null, excludeNodes));
239
-
240
- // bake transformation of all meshes, so that no negative scalings are left
241
- // it's important that this is done AFTER instanced meshes have been converted (_prepareNodeForExport)
242
- this._getNodesMarkedForExport(true).forEach(mesh => bakeGeometryOfMesh(mesh as Mesh));
243
-
244
- // reset transformation of all "TransformNodes", which couldn't be handled by the geometry baking algorithm
245
- // it's important that this is done AFTER all geometries have been baked
246
- this._getNodesMarkedForExport().forEach(node => resetTransformation(node as TransformNode));
247
- }
248
-
249
- /**
250
- * Cleans up scene after export
251
- */
252
- protected async _exportPostProcess(optimizeForAR: boolean): Promise<void> {
253
- if (!optimizeForAR) {
254
- // nothing to do, since no changes have been made without AR optimizations
255
- return;
256
- }
257
-
258
- // dispose all nodes, materials and textures that have only been created for the export
259
- this.viewer.scene.rootNodes
260
- .filter(rootNode => getInternalMetadataValue(rootNode, 'deleteAfterExport'))
261
- .forEach(rootNode => rootNode.dispose());
262
-
263
- this.viewer.scene.materials
264
- .filter(material => getInternalMetadataValue(material, 'deleteAfterExport'))
265
- .forEach(material => material.dispose(false, false));
266
- // clean up temporary material exchange key for the rest of materials
267
- this.viewer.scene.materials.forEach(material => clearInternalMetadataValue(material, 'exchangeMaterialWith'));
268
-
269
- this.viewer.scene.textures
270
- .filter(texture => getInternalMetadataValue(texture, 'deleteAfterExport'))
271
- .forEach(texture => texture.dispose());
272
-
273
- // reset engines max texture size and resume rendering
274
- this.viewer.engine.getCaps().maxTextureSize = this._maxTextureSize;
275
- this.viewer.resumeRendering();
276
- }
277
-
278
- /**
279
- * Creates a clone of the node which should be used for the export.
280
- * Also switches to the cloned material if required.
281
- */
282
- protected _prepareNodeForExport(
283
- node: Node,
284
- clonedParent: TransformNode | null,
285
- excludeNodes?: NodeDescription[]
286
- ): void {
287
- if (!GltfExportManager._shouldExportNode(node, excludeNodes)) {
288
- return;
289
- }
290
-
291
- // from here on we only have TransformNodes
292
- const transformNode = node as TransformNode;
293
-
294
- // clone original node and create unique name (via uniqueId) for the export
295
- const clonedNodeName = `${transformNode.name}_${transformNode.uniqueId}`;
296
- const clonedNode =
297
- transformNode instanceof InstancedMesh
298
- ? createMeshFromInstancedMesh(transformNode, clonedNodeName, clonedParent)
299
- : transformNode.clone(clonedNodeName, clonedParent, true)!;
300
- cloneInternalMetadata(transformNode, clonedNode);
301
-
302
- // exchange material
303
- if (clonedNode instanceof Mesh) {
304
- const exchangeWithMaterial =
305
- clonedNode.material && getInternalMetadataValue(clonedNode.material, 'exchangeMaterialWith');
306
- if (exchangeWithMaterial) {
307
- clonedNode.material = this.viewer.scene.getMaterialByUniqueID(exchangeWithMaterial as number);
308
- }
309
- }
310
-
311
- // signalize that this is a cloned node
312
- setInternalMetadataValue(clonedNode, 'exportNode', true);
313
- setInternalMetadataValue(clonedNode, 'deleteAfterExport', true);
314
-
315
- // handle children
316
- const childs = transformNode.getChildTransformNodes(true);
317
- childs.forEach(child => this._prepareNodeForExport(child, clonedNode, excludeNodes));
318
- }
319
-
320
- /**
321
- * Help function for receiving all nodes that are marked for the export
322
- */
323
- protected _getNodesMarkedForExport(meshesOnly?: boolean): TransformNode[] {
324
- const nodes: TransformNode[] = [...this.viewer.scene.meshes];
325
- if (!meshesOnly) {
326
- nodes.push(...this.viewer.scene.transformNodes);
327
- }
328
-
329
- const filteredNodes = nodes.filter(node => getInternalMetadataValue(node, 'exportNode'));
330
- return filteredNodes;
137
+ if (optimizeForAR) await exportPostProcess(this.viewer);
331
138
  }
332
139
  }
package/src/viewer.ts CHANGED
@@ -6,6 +6,7 @@ import {
6
6
  DebugManager,
7
7
  DefaultSceneSettings,
8
8
  DimensionLineManager,
9
+ DxfExportManager,
9
10
  Engine,
10
11
  EngineOptions,
11
12
  EventManager,
@@ -84,6 +85,7 @@ export class Viewer {
84
85
  protected _cameraManager!: CameraManager;
85
86
  protected _debugManager!: DebugManager;
86
87
  protected _dimensionLineManager!: DimensionLineManager;
88
+ protected _dxfExportManager!: DxfExportManager;
87
89
  protected _eventManager!: EventManager;
88
90
  protected _gltfExportManager!: GltfExportManager;
89
91
  protected _htmlAnchorManager!: HtmlAnchorManager;
@@ -127,6 +129,9 @@ export class Viewer {
127
129
  get dimensionLineManager(): DimensionLineManager {
128
130
  return this._dimensionLineManager;
129
131
  }
132
+ get dxfExportManager(): DxfExportManager {
133
+ return this._dxfExportManager;
134
+ }
130
135
  get eventManager(): EventManager {
131
136
  return this._eventManager;
132
137
  }
@@ -249,6 +254,7 @@ export class Viewer {
249
254
  this._cameraManager = new CameraManager(this);
250
255
  this._debugManager = new DebugManager(this);
251
256
  this._dimensionLineManager = new DimensionLineManager(this);
257
+ this._dxfExportManager = new DxfExportManager(this);
252
258
  this._eventManager = new EventManager(this);
253
259
  this._gltfExportManager = new GltfExportManager(this);
254
260
  this._htmlAnchorManager = new HtmlAnchorManager(this);
@@ -1,14 +0,0 @@
1
- import { InstancedMesh, Mesh, TransformNode } from '../index';
2
- /**
3
- * Creates a "standard" mesh from an instanced mesh, by cloning the source mesh and applying transformation data
4
- */
5
- export declare function createMeshFromInstancedMesh(instancedMesh: InstancedMesh, newName: string, clonedParent: TransformNode | null): Mesh;
6
- /**
7
- * Removes transformation data from the mesh and stores it in the geometry, which is called "baking".
8
- * Also considers the geometry change from morph targets.
9
- */
10
- export declare function bakeGeometryOfMesh(mesh: Mesh): void;
11
- /**
12
- * Resets transformation to initial state
13
- */
14
- export declare function resetTransformation(node: TransformNode): void;
@@ -1,114 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.resetTransformation = exports.bakeGeometryOfMesh = exports.createMeshFromInstancedMesh = void 0;
4
- const index_1 = require("../index");
5
- const metadata_helper_1 = require("./metadata-helper");
6
- /**
7
- * Creates a "standard" mesh from an instanced mesh, by cloning the source mesh and applying transformation data
8
- */
9
- function createMeshFromInstancedMesh(instancedMesh, newName, clonedParent) {
10
- // first create a clone of the source mesh
11
- const newMesh = instancedMesh.sourceMesh.clone(newName, clonedParent, true);
12
- (0, metadata_helper_1.cloneInternalMetadata)(instancedMesh.sourceMesh, newMesh);
13
- // apply the transformation data, it's important to create clones of the transformations to not touch the original
14
- // transformation when applying changes (eg: geometry baking)
15
- newMesh.position = instancedMesh.position.clone();
16
- newMesh.rotation = instancedMesh.rotation.clone();
17
- newMesh.scaling = instancedMesh.scaling.clone();
18
- // rotation quaternion is optional
19
- if (instancedMesh.rotationQuaternion) {
20
- newMesh.rotationQuaternion = instancedMesh.rotationQuaternion.clone();
21
- }
22
- // also sync the enabled state from the original instanced mesh
23
- newMesh.setEnabled(instancedMesh.isEnabled(false));
24
- return newMesh;
25
- }
26
- exports.createMeshFromInstancedMesh = createMeshFromInstancedMesh;
27
- /**
28
- * Removes transformation data from the mesh and stores it in the geometry, which is called "baking".
29
- * Also considers the geometry change from morph targets.
30
- */
31
- function bakeGeometryOfMesh(mesh) {
32
- if (!mesh.geometry) {
33
- // no geometry available, nothing to do
34
- return;
35
- }
36
- // geometries can be shared across multiple meshes, first make them unique to avoid side-effects
37
- mesh.makeGeometryUnique();
38
- // Babylon.js already provides a function for baking the current skeleton changes into the geometry
39
- if (mesh.skeleton) {
40
- mesh.applySkeleton(mesh.skeleton);
41
- mesh.skeleton = null;
42
- }
43
- // NOTE: in difference to skeletons and transformations there is no baking function for morph targets (yet)
44
- // however another approach could be to re-apply the position and normals data, as there are nice functions for it
45
- // - `getPositionData(applySkeleton: boolean = false, applyMorph: boolean = false)`
46
- // - `getNormalsData(applySkeleton: boolean = false, applyMorph: boolean = false)`
47
- // you can decide if skeletons and morph targets can be added, which is exactly what we want
48
- // I'm still hesitant to use it because "tangent" and "UV" kinds are not supported, whereas I'm not sure if it's
49
- // required
50
- // => try it out when there is enough time for detailed regression tests!
51
- const morphTargetManager = mesh.morphTargetManager;
52
- const geometry = mesh.geometry;
53
- if (morphTargetManager === null || morphTargetManager === void 0 ? void 0 : morphTargetManager.numTargets) {
54
- // apply morph target vertices data to mesh geometry
55
- // mostly only the "PositionKind" is implemented
56
- _bakeMorphTargetManagerIntoVertices(index_1.VertexBuffer.PositionKind, morphTargetManager, geometry);
57
- _bakeMorphTargetManagerIntoVertices(index_1.VertexBuffer.NormalKind, morphTargetManager, geometry);
58
- _bakeMorphTargetManagerIntoVertices(index_1.VertexBuffer.TangentKind, morphTargetManager, geometry);
59
- _bakeMorphTargetManagerIntoVertices(index_1.VertexBuffer.UVKind, morphTargetManager, geometry);
60
- // remove morph target manager with all it's morph targets
61
- mesh.morphTargetManager = null;
62
- }
63
- // bake the transformation data in the mesh geometry, fortunately there is already a help function from Babylon.js
64
- mesh.bakeCurrentTransformIntoVertices();
65
- }
66
- exports.bakeGeometryOfMesh = bakeGeometryOfMesh;
67
- /**
68
- * Resets transformation to initial state
69
- */
70
- function resetTransformation(node) {
71
- node.position = new index_1.Vector3(0, 0, 0);
72
- node.rotation = new index_1.Vector3(0, 0, 0);
73
- node.rotationQuaternion = null;
74
- node.scaling = new index_1.Vector3(1, 1, 1);
75
- }
76
- exports.resetTransformation = resetTransformation;
77
- /**
78
- * @param kind morph targets can affect various vertices kinds, whereas "position" is the most common one
79
- * still other kinds (like normals or tangents) can be affected as well and can be provided on this input
80
- */
81
- function _bakeMorphTargetManagerIntoVertices(kind, morphTargetManager, geometry) {
82
- const origVerticesData = geometry.getVerticesData(kind);
83
- if (!origVerticesData) {
84
- // no vertices data for this kind availabe on the mesh geometry
85
- return;
86
- }
87
- let verticesData = [...origVerticesData];
88
- for (let i = 0; i < morphTargetManager.numTargets; i++) {
89
- const target = morphTargetManager.getTarget(i);
90
- const targetVerticesData = _getVerticesDataFromMorphTarget(kind, target);
91
- if (targetVerticesData) {
92
- // vertices data of this kind are implemented on the morph target
93
- // add the influence of this morph target to the vertices data
94
- // formula is taken from: https://doc.babylonjs.com/features/featuresDeepDive/mesh/morphTargets#basics
95
- verticesData = verticesData.map((oldVal, idx) => oldVal + (targetVerticesData[idx] - origVerticesData[idx]) * target.influence);
96
- }
97
- }
98
- // apply the updated vertices data
99
- geometry.setVerticesData(kind, verticesData);
100
- }
101
- function _getVerticesDataFromMorphTarget(kind, morphTarget) {
102
- switch (kind) {
103
- case index_1.VertexBuffer.PositionKind:
104
- return morphTarget.getPositions();
105
- case index_1.VertexBuffer.NormalKind:
106
- return morphTarget.getNormals();
107
- case index_1.VertexBuffer.TangentKind:
108
- return morphTarget.getTangents();
109
- case index_1.VertexBuffer.UVKind:
110
- return morphTarget.getUVs();
111
- }
112
- return null;
113
- }
114
- //# sourceMappingURL=geometry-helper.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"geometry-helper.js","sourceRoot":"","sources":["../../../src/internal/geometry-helper.ts"],"names":[],"mappings":"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"}
@@ -1,144 +0,0 @@
1
- import {
2
- FloatArray,
3
- Geometry,
4
- InstancedMesh,
5
- Mesh,
6
- MorphTarget,
7
- MorphTargetManager,
8
- TransformNode,
9
- Vector3,
10
- VertexBuffer,
11
- } from '../index';
12
- import { cloneInternalMetadata } from './metadata-helper';
13
-
14
- /**
15
- * Creates a "standard" mesh from an instanced mesh, by cloning the source mesh and applying transformation data
16
- */
17
- export function createMeshFromInstancedMesh(
18
- instancedMesh: InstancedMesh,
19
- newName: string,
20
- clonedParent: TransformNode | null
21
- ): Mesh {
22
- // first create a clone of the source mesh
23
- const newMesh = instancedMesh.sourceMesh.clone(newName, clonedParent, true);
24
- cloneInternalMetadata(instancedMesh.sourceMesh, newMesh);
25
- // apply the transformation data, it's important to create clones of the transformations to not touch the original
26
- // transformation when applying changes (eg: geometry baking)
27
- newMesh.position = instancedMesh.position.clone();
28
- newMesh.rotation = instancedMesh.rotation.clone();
29
- newMesh.scaling = instancedMesh.scaling.clone();
30
-
31
- // rotation quaternion is optional
32
- if (instancedMesh.rotationQuaternion) {
33
- newMesh.rotationQuaternion = instancedMesh.rotationQuaternion.clone();
34
- }
35
-
36
- // also sync the enabled state from the original instanced mesh
37
- newMesh.setEnabled(instancedMesh.isEnabled(false));
38
-
39
- return newMesh;
40
- }
41
-
42
- /**
43
- * Removes transformation data from the mesh and stores it in the geometry, which is called "baking".
44
- * Also considers the geometry change from morph targets.
45
- */
46
- export function bakeGeometryOfMesh(mesh: Mesh): void {
47
- if (!mesh.geometry) {
48
- // no geometry available, nothing to do
49
- return;
50
- }
51
-
52
- // geometries can be shared across multiple meshes, first make them unique to avoid side-effects
53
- mesh.makeGeometryUnique();
54
-
55
- // Babylon.js already provides a function for baking the current skeleton changes into the geometry
56
- if (mesh.skeleton) {
57
- mesh.applySkeleton(mesh.skeleton);
58
- mesh.skeleton = null;
59
- }
60
-
61
- // NOTE: in difference to skeletons and transformations there is no baking function for morph targets (yet)
62
- // however another approach could be to re-apply the position and normals data, as there are nice functions for it
63
- // - `getPositionData(applySkeleton: boolean = false, applyMorph: boolean = false)`
64
- // - `getNormalsData(applySkeleton: boolean = false, applyMorph: boolean = false)`
65
- // you can decide if skeletons and morph targets can be added, which is exactly what we want
66
- // I'm still hesitant to use it because "tangent" and "UV" kinds are not supported, whereas I'm not sure if it's
67
- // required
68
- // => try it out when there is enough time for detailed regression tests!
69
- const morphTargetManager = mesh.morphTargetManager;
70
- const geometry = mesh.geometry;
71
-
72
- if (morphTargetManager?.numTargets) {
73
- // apply morph target vertices data to mesh geometry
74
- // mostly only the "PositionKind" is implemented
75
- _bakeMorphTargetManagerIntoVertices(VertexBuffer.PositionKind, morphTargetManager, geometry);
76
- _bakeMorphTargetManagerIntoVertices(VertexBuffer.NormalKind, morphTargetManager, geometry);
77
- _bakeMorphTargetManagerIntoVertices(VertexBuffer.TangentKind, morphTargetManager, geometry);
78
- _bakeMorphTargetManagerIntoVertices(VertexBuffer.UVKind, morphTargetManager, geometry);
79
-
80
- // remove morph target manager with all it's morph targets
81
- mesh.morphTargetManager = null;
82
- }
83
-
84
- // bake the transformation data in the mesh geometry, fortunately there is already a help function from Babylon.js
85
- mesh.bakeCurrentTransformIntoVertices();
86
- }
87
-
88
- /**
89
- * Resets transformation to initial state
90
- */
91
- export function resetTransformation(node: TransformNode): void {
92
- node.position = new Vector3(0, 0, 0);
93
- node.rotation = new Vector3(0, 0, 0);
94
- node.rotationQuaternion = null;
95
- node.scaling = new Vector3(1, 1, 1);
96
- }
97
-
98
- /**
99
- * @param kind morph targets can affect various vertices kinds, whereas "position" is the most common one
100
- * still other kinds (like normals or tangents) can be affected as well and can be provided on this input
101
- */
102
- function _bakeMorphTargetManagerIntoVertices(
103
- kind: string,
104
- morphTargetManager: MorphTargetManager,
105
- geometry: Geometry
106
- ): void {
107
- const origVerticesData = geometry.getVerticesData(kind);
108
- if (!origVerticesData) {
109
- // no vertices data for this kind availabe on the mesh geometry
110
- return;
111
- }
112
-
113
- let verticesData = [...origVerticesData];
114
- for (let i = 0; i < morphTargetManager.numTargets; i++) {
115
- const target = morphTargetManager.getTarget(i);
116
- const targetVerticesData = _getVerticesDataFromMorphTarget(kind, target);
117
- if (targetVerticesData) {
118
- // vertices data of this kind are implemented on the morph target
119
- // add the influence of this morph target to the vertices data
120
- // formula is taken from: https://doc.babylonjs.com/features/featuresDeepDive/mesh/morphTargets#basics
121
- verticesData = verticesData.map(
122
- (oldVal, idx) => oldVal + (targetVerticesData[idx] - origVerticesData[idx]) * target.influence
123
- );
124
- }
125
- }
126
-
127
- // apply the updated vertices data
128
- geometry.setVerticesData(kind, verticesData);
129
- }
130
-
131
- function _getVerticesDataFromMorphTarget(kind: string, morphTarget: MorphTarget): FloatArray | null {
132
- switch (kind) {
133
- case VertexBuffer.PositionKind:
134
- return morphTarget.getPositions();
135
- case VertexBuffer.NormalKind:
136
- return morphTarget.getNormals();
137
- case VertexBuffer.TangentKind:
138
- return morphTarget.getTangents();
139
- case VertexBuffer.UVKind:
140
- return morphTarget.getUVs();
141
- }
142
-
143
- return null;
144
- }