@combeenation/3d-viewer 11.0.0 → 12.0.0-alpha1

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@combeenation/3d-viewer",
3
- "version": "11.0.0",
3
+ "version": "12.0.0-alpha1",
4
4
  "description": "Combeenation 3D Viewer",
5
5
  "homepage": "https://github.com/Combeenation/3d-viewer#readme",
6
6
  "bugs": {
@@ -1,58 +1,31 @@
1
- import { bakeGeometryOfAllMeshes } from '..//util/geometryHelper';
1
+ import { Node as BjsNode, Color3, InstancedMesh, PBRMaterial } from '../../index';
2
2
  import { Viewer } from '../classes/viewer';
3
3
  import { injectMetadata } from '../util/babylonHelper';
4
+ import { bakeGeometryOfMesh, createMeshFromInstancedMesh, resetTransformation } from '../util/geometryHelper';
4
5
  import { isNodeIncludedInExclusionList } from '../util/structureHelper';
5
- import { Engine } from '@babylonjs/core/Engines/engine';
6
- import { EngineStore } from '@babylonjs/core/Engines/engineStore';
7
- import { SceneLoader } from '@babylonjs/core/Loading/sceneLoader';
8
- import { PBRMaterial } from '@babylonjs/core/Materials/PBR/pbrMaterial';
9
- import { Color3 } from '@babylonjs/core/Maths/math.color';
10
- import { AbstractMesh } from '@babylonjs/core/Meshes/abstractMesh';
6
+ import { Mesh } from '@babylonjs/core/Meshes/mesh';
11
7
  import { TransformNode } from '@babylonjs/core/Meshes/transformNode';
12
- import { SceneSerializer } from '@babylonjs/core/Misc/sceneSerializer';
13
- import { Scene } from '@babylonjs/core/scene';
14
- import { GLTF2Export, IExportOptions } from '@babylonjs/serializers/glTF/2.0';
15
- import { has, merge } from 'lodash-es';
8
+ import { GLTF2Export } from '@babylonjs/serializers/glTF/2.0/glTFSerializer';
16
9
 
17
- type MetadataMap = { [key: string]: any };
18
10
  export class GltfExportManager {
19
- protected static readonly _CLONED_FROM_MAT_METADATA_PROPERTY = 'clonedFrom';
20
- public static readonly NAME_BEFORE_EXPORT_METADATA_PROPERTY = 'nameBeforeExport';
11
+ protected static readonly _METADATA_PROPS = {
12
+ exportNode: 'exportNode',
13
+ deleteAfterExport: 'deleteAfterExport',
14
+ exchangeMaterialWith: 'exchangeMaterialWith',
15
+ };
21
16
 
22
- /**
23
- * Constructor.
24
- */
25
17
  protected constructor(protected viewer: Viewer) {}
26
18
 
27
- /**
28
- * Creates an {@link GltfExportManager}.
29
- */
30
19
  public static async create(viewer: Viewer): Promise<GltfExportManager> {
31
20
  return new GltfExportManager(viewer);
32
21
  }
33
22
 
34
- /**
35
- * Exports selected nodes to a file.
36
- * @param filename optional name of the exported .GLB file.
37
- * @param exportOptions export options to be merged with default options.\
38
- * `exportOptions.exchangeRefractionMaterials` and `exportOptions.limitTextureSize`
39
- * default to `true` if not given.
40
- * @param optimizeForAR adjusts the exported GLB so that known AR issues get fixed automatically
41
- * @param excluded optional list of geometry (meshes, elements, variants, variantInstances) to be excluded from export
42
- */
43
- public async exportGlb(
44
- filename = 'glb-export.glb',
45
- { exchangeRefractionMaterials = true, limitTextureSize = true, ...exportOptions }: IExportOptionsExtended = {},
46
- optimizeForAR: boolean = false,
47
- excluded?: ExcludedGeometryList
48
- ): Promise<File | undefined> {
49
- const { scene, sceneCopied } = await this.exportPreProcess(
50
- exchangeRefractionMaterials,
51
- limitTextureSize,
52
- optimizeForAR
53
- );
54
- const glbData = await GLTF2Export.GLBAsync(scene, 'dummy', this.gltfExportOptions(exportOptions, excluded));
55
- this.exportPostProcess(scene, sceneCopied);
23
+ public async exportGlb(filename = 'glb-export.glb', excluded?: ExcludedGeometryList) {
24
+ await this._exportPreProcess(excluded);
25
+
26
+ const glbData = await GLTF2Export.GLBAsync(this.viewer.scene, 'dummy', this._gltfExportOptions());
27
+
28
+ await this._exportPostProcess();
56
29
 
57
30
  const resBlob = glbData.glTFFiles['dummy.glb'];
58
31
  // check if result is valid, according to the typings this could also be a string
@@ -67,218 +40,142 @@ export class GltfExportManager {
67
40
  }
68
41
  }
69
42
 
70
- /**
71
- * Exports selected nodes to GLTF. This may result in more than one file, since textures are exported separately.
72
- * @param filename name of the main (text-based) .GLTF file referring to separate texture files.
73
- * @param exportOptions export options to be merged with default options.\
74
- * `exportOptions.exchangeRefractionMaterials` and `exportOptions.limitTextureSize`
75
- * default to `true` if not given.
76
- * @param optimizeForAR adjusts the exported GLB so that known AR issues get fixed automatically
77
- * @param excluded optional list of geometry (meshes, elements, variants, variantInstances) to be excluded from export
78
- */
79
- public async exportGltfToFile(
80
- filename: string,
81
- { exchangeRefractionMaterials = true, limitTextureSize = true, ...exportOptions }: IExportOptionsExtended = {},
82
- optimizeForAR: boolean = false,
83
- excluded?: ExcludedGeometryList
84
- ) {
85
- const { scene, sceneCopied } = await this.exportPreProcess(
86
- exchangeRefractionMaterials,
87
- limitTextureSize,
88
- optimizeForAR
89
- );
90
- const gltf = await GLTF2Export.GLTFAsync(scene, filename, this.gltfExportOptions(exportOptions, excluded));
43
+ public async exportGltfToFile(filename: string, excluded?: ExcludedGeometryList) {
44
+ await this._exportPreProcess(excluded);
45
+
46
+ const gltf = await GLTF2Export.GLTFAsync(this.viewer.scene, filename, this._gltfExportOptions());
91
47
  gltf.downloadFiles();
92
- this.exportPostProcess(scene, sceneCopied);
93
- }
94
48
 
95
- /**
96
- * Exports selected nodes to GLB. This results in one binary file.
97
- * @param filename name of the .GLB file.
98
- * @param exportOptions export options to be merged with default options.\
99
- * `exportOptions.exchangeRefractionMaterials` and `exportOptions.limitTextureSize`
100
- * default to `true` if not given.
101
- * @param optimizeForAR adjusts the exported GLB so that known AR issues get fixed automatically
102
- * @param excluded optional list of geometry (meshes, elements, variants, variantInstances) to be excluded from export
103
- */
104
- public async exportGlbToFile(
105
- filename: string,
106
- { exchangeRefractionMaterials = true, limitTextureSize = true, ...exportOptions }: IExportOptionsExtended = {},
107
- optimizeForAR: boolean = false,
108
- excluded?: ExcludedGeometryList
109
- ) {
110
- const { scene, sceneCopied } = await this.exportPreProcess(
111
- exchangeRefractionMaterials,
112
- limitTextureSize,
113
- optimizeForAR
114
- );
115
- const glb = await GLTF2Export.GLBAsync(scene, filename, this.gltfExportOptions(exportOptions, excluded));
116
- glb.downloadFiles();
117
- this.exportPostProcess(scene, sceneCopied);
49
+ this._exportPostProcess();
118
50
  }
119
51
 
120
- /**
121
- * Gets predefined {@link IExportOptions } merged with given ones.
122
- */
123
- protected gltfExportOptions(mergeWithOptions: IExportOptions = {}, excluded?: ExcludedGeometryList): IExportOptions {
124
- const defaultOptions: IExportOptions = {
125
- shouldExportNode: function (node: any) {
126
- if (!node.isEnabled()) {
127
- return false;
128
- }
129
- if ((node.name as string).startsWith(Viewer.BOUNDING_BOX_NAME)) {
130
- return false;
131
- }
132
- if (excluded && node instanceof TransformNode && isNodeIncludedInExclusionList(node, excluded)) {
133
- return false;
134
- }
135
- return true;
136
- },
137
- };
138
- return merge({}, defaultOptions, mergeWithOptions);
139
- }
52
+ public async exportGlbToFile(filename: string, excluded?: ExcludedGeometryList) {
53
+ await this._exportPreProcess(excluded);
140
54
 
141
- /**
142
- * Stuff to be done before exporting to GLTF
143
- *
144
- * @returns Either the original scene if no adjustments have been made or a copied scene (which can be disposed after
145
- * the export) if adjustments have been made
146
- */
147
- protected async exportPreProcess(
148
- exchangeRefractionMaterials: boolean,
149
- limitTextureSize: boolean,
150
- optimizeForAR: boolean
151
- ): Promise<{ scene: Scene; sceneCopied: boolean }> {
152
- if (!exchangeRefractionMaterials && !optimizeForAR && !limitTextureSize) {
153
- // no need to copy the scene if no adjustments have to be made
154
- return { scene: this.viewer.scene, sceneCopied: false };
155
- }
55
+ const glb = await GLTF2Export.GLBAsync(this.viewer.scene, filename, this._gltfExportOptions());
56
+ glb.downloadFiles();
156
57
 
157
- // copy the scene for the GLB export improvements, so that the original viewer scene remains untouched
158
- const copiedScene = await this.copyViewerScene(limitTextureSize);
58
+ await this._exportPostProcess();
59
+ }
159
60
 
160
- if (exchangeRefractionMaterials) {
161
- this.exchangeRefractionMaterials(copiedScene);
162
- }
61
+ protected async _exportPreProcess(excluded?: ExcludedGeometryList): Promise<void> {
62
+ // handle materials
63
+ this.viewer.scene.materials
64
+ .filter(material => this._shouldReplaceMaterial(material))
65
+ .forEach(material => this._createRefractionMaterialReplacement(material as PBRMaterial));
163
66
 
164
- if (optimizeForAR) {
165
- this.setUniqueMeshNames(copiedScene);
166
- // get rid of negative scalings and morph targets, since iOS can't handle it in the QuickLook app
167
- bakeGeometryOfAllMeshes(copiedScene);
168
- // certain devices can't load models with skeletons, just remove them since animations are not supported in the AR
169
- // scene anyway
170
- while (copiedScene.skeletons.length) {
171
- const skeleton = copiedScene.skeletons.pop();
172
- skeleton!.dispose();
173
- }
174
- }
67
+ // handle nodes
68
+ this.viewer.scene.rootNodes.forEach(rootNode =>
69
+ this._prepareNodeForExport(rootNode as TransformNode, null, excluded)
70
+ );
175
71
 
176
- return { scene: copiedScene, sceneCopied: true };
72
+ // reset transformation of all "TransformNodes", which couldn't be handled by the geometry baking algorithm
73
+ // it's important that this is done AFTER all geometries have been baked
74
+ this.viewer.scene
75
+ .getNodes()
76
+ .filter(node => !!node.metadata?.[GltfExportManager._METADATA_PROPS.exportNode])
77
+ .forEach(node => resetTransformation(node as TransformNode));
177
78
  }
178
79
 
179
- /**
180
- * Create a copy of the viewer scene, which can be further processed and optimized for the GLB export.
181
- * There is no "scene.clone" function, therefore the scene is serialized and loaded again to achieve this result.
182
- */
183
- protected async copyViewerScene(limitTextureSize: boolean): Promise<Scene> {
184
- // required by the scene serializer
185
- await import(/* webpackChunkName: "physicsenginecomponent" */ '@babylonjs/core/Physics/physicsEngineComponent');
186
-
187
- // copy scene function uses scene serializer, which can't handle "complex" data like classes, function or recursive
188
- // data structures in metadata
189
- // it basically does a `JSON.stringify` on the metadata
190
- // therefore the metadata has to be removed from the nodes before the copy process
191
- const metadataArr = this.extractMetadataOfAllNodes();
80
+ protected async _exportPostProcess(): Promise<void> {
81
+ // dispose all nodes and material that have only been created for the export
82
+ this.viewer.scene.rootNodes
83
+ .filter(rootNode => rootNode.metadata?.[GltfExportManager._METADATA_PROPS.deleteAfterExport])
84
+ .forEach(rootNode => rootNode.dispose());
192
85
 
193
- // serialize the scene
194
- const serializedScene = await SceneSerializer.SerializeAsync(this.viewer.scene);
195
-
196
- // set the cropped metadata back to the viewer scene nodes
197
- this.restoreMetadataOfAllNodes(metadataArr);
86
+ this.viewer.scene.materials
87
+ .filter(mat => !!mat.metadata?.[GltfExportManager._METADATA_PROPS.deleteAfterExport])
88
+ .forEach(material => material.dispose(false, false));
89
+ }
198
90
 
199
- // load the scene into an invisible "dummy" canvas
200
- const dummyCanvas = document.createElement('canvas');
201
- const engine = new Engine(dummyCanvas);
91
+ protected _gltfExportOptions(): IExportOptions {
92
+ return {
93
+ shouldExportNode: function (node: BjsNode) {
94
+ return !!node.metadata?.[GltfExportManager._METADATA_PROPS.exportNode];
95
+ },
96
+ // keep root node(s)
97
+ // this seems to be important due to the geometry baking and transformation resetting stuff
98
+ // => root node has no transformation anymore, which seems to be problematic for the import
99
+ removeNoopRootNodes: false,
100
+ };
101
+ }
202
102
 
203
- if (limitTextureSize) {
204
- // according to some tests iOS devices break when exporting a scene with textures above 1024
205
- // this only affects the scene clone for the export
206
- engine.getCaps().maxTextureSize = 1024;
103
+ protected _prepareNodeForExport(
104
+ node: TransformNode,
105
+ clonedParent: Nullable<TransformNode>,
106
+ excluded?: ExcludedGeometryList
107
+ ) {
108
+ if (!this._shouldExportNode(node, excluded)) {
109
+ return;
207
110
  }
208
111
 
209
- // overwritting _LastCreatedScene to fix issue: https://combeenation.youtrack.cloud/issue/CB-8972
210
- // In short: dummy scene erroneously interacts with original viewer scene
211
- // setting viewer scene as fallback again (`_LastCreatedScene`) resolves that issue
212
- const curLastScene = EngineStore._LastCreatedScene;
213
- const newScene = new Scene(engine);
214
- EngineStore._LastCreatedScene = curLastScene;
112
+ // clone original node and create unique name (via uniqueId)
113
+ const newNodeName = `${node.name}_${node.uniqueId}`;
114
+ const clonedNode =
115
+ node instanceof InstancedMesh
116
+ ? createMeshFromInstancedMesh(node, newNodeName)
117
+ : node.clone(newNodeName, clonedParent, true)!;
118
+
119
+ // bake transformation, so that we won't get negative values anymore
120
+ // also exchange material
121
+ if (clonedNode instanceof Mesh) {
122
+ bakeGeometryOfMesh(clonedNode);
123
+ const exchangeWithMaterial =
124
+ clonedNode.material?.metadata?.[GltfExportManager._METADATA_PROPS.exchangeMaterialWith];
125
+ if (exchangeWithMaterial) {
126
+ clonedNode.material = this.viewer.scene.getMaterialByName(exchangeWithMaterial);
127
+ }
128
+ }
215
129
 
216
- SceneLoader.ShowLoadingScreen = false;
217
- await SceneLoader.AppendAsync('', 'data:' + JSON.stringify(serializedScene), newScene, undefined, '.babylon');
130
+ // signalize that this is a cloned node
131
+ injectMetadata(clonedNode!, {
132
+ [GltfExportManager._METADATA_PROPS.exportNode]: true,
133
+ [GltfExportManager._METADATA_PROPS.deleteAfterExport]: true,
134
+ });
218
135
 
219
- return newScene;
136
+ // recourse into children
137
+ const childs = node.getChildTransformNodes(true);
138
+ childs.forEach(child => this._prepareNodeForExport(child, clonedNode, excluded));
220
139
  }
221
140
 
222
- /**
223
- * Stuff to be done after the GLTF export
224
- */
225
- protected exportPostProcess(scene: Scene, disposeScene: boolean) {
226
- if (disposeScene) {
227
- // copied scene for GLB export is not needed anymore, therefore it can be removed
228
- scene.getEngine().dispose();
141
+ protected _shouldExportNode(node: BjsNode, excluded?: ExcludedGeometryList): boolean {
142
+ if (!(node instanceof TransformNode)) {
143
+ return false;
144
+ }
145
+ if (node.name === Viewer.BOUNDING_BOX_NAME) {
146
+ return false;
147
+ }
148
+ if (!node.isEnabled()) {
149
+ return false;
150
+ }
151
+ if (excluded && isNodeIncludedInExclusionList(node, excluded)) {
152
+ return false;
229
153
  }
230
- }
231
-
232
- /**
233
- * Remove all node metadata and return them in a map
234
- */
235
- protected extractMetadataOfAllNodes(): MetadataMap {
236
- return this.viewer.scene.getNodes().reduce((accMetadataObj, curNode) => {
237
- const metadata = curNode.metadata;
238
- delete curNode.metadata;
239
- return { ...accMetadataObj, [curNode.uniqueId.toString()]: metadata };
240
- }, {});
241
- }
242
154
 
243
- /**
244
- * Restore node metadata from previously cropped metadata map
245
- */
246
- protected restoreMetadataOfAllNodes(metadataMap: MetadataMap) {
247
- this.viewer.scene.getNodes().forEach(node => {
248
- const metadata = metadataMap[node.uniqueId.toString()];
249
- if (metadata) {
250
- node.metadata = metadata;
251
- }
252
- });
155
+ return true;
253
156
  }
254
157
 
255
- /**
256
- * Materials with refraction set are not exported properly.
257
- * Exchange all such (relevant) materials with a more export-friendly version
258
- */
259
- protected exchangeRefractionMaterials(scene: Scene) {
260
- for (const n of scene.getNodes()) {
261
- if (!(n instanceof AbstractMesh)) continue;
262
- if (!(n.material instanceof PBRMaterial)) continue;
263
- if (!(n.material as PBRMaterial).subSurface.isRefractionEnabled) continue;
264
- if ((n.material as PBRMaterial).transparencyMode !== PBRMaterial.PBRMATERIAL_OPAQUE) continue;
265
- // if we're here, we have a node holding a material with set refraction whose transparencyMode is set to
266
- // PBRMATERIAL_OPAQUE
267
- n.material = this.createRefractionMaterialReplacement(n.material);
158
+ protected _shouldReplaceMaterial(material: Material): boolean {
159
+ if (!(material instanceof PBRMaterial)) {
160
+ return false;
161
+ }
162
+ if (!material.subSurface.isRefractionEnabled) {
163
+ return false;
164
+ }
165
+ if (material.transparencyMode !== PBRMaterial.PBRMATERIAL_OPAQUE) {
166
+ return false;
268
167
  }
168
+
169
+ return true;
269
170
  }
270
171
 
271
172
  /**
272
173
  * Create an export-friendly replacement material for a material using refraction.
273
- * @param mat Material to be replaced
274
174
  */
275
- protected createRefractionMaterialReplacement(mat: PBRMaterial): PBRMaterial {
276
- // if we're dealing with a clone already, return it instead of cloning
277
- if (this.isMaterialClonedForExport(mat)) return mat;
278
-
175
+ protected _createRefractionMaterialReplacement(material: PBRMaterial): PBRMaterial {
176
+ const newName = `${material.name}_clone`;
279
177
  // change material according to https://www.notion.so/combeenation/Glas-materials-don-t-look-glasy-after-export-d5fda2c6515e4420a8772744d3e6b460
280
- const clonedMaterial = mat.clone(mat.name); // clone material. clone uses same name
281
- clonedMaterial.metadata = { ...mat.metadata, [GltfExportManager._CLONED_FROM_MAT_METADATA_PROPERTY]: mat.uniqueId }; // create shallow copy of metadata on clone. see https://forum.babylonjs.com/t/the-metadata-of-the-mesh-cloned-by-the-instantiatemodelstoscene-method-is-a-shallow-copy/21563
178
+ const clonedMaterial = material.clone(newName); // clone material
282
179
  clonedMaterial.refractionTexture = null;
283
180
  clonedMaterial.metallicReflectanceTexture = null; // is this the correct one for metallic roughness?
284
181
  clonedMaterial.alpha = 0.7;
@@ -287,26 +184,9 @@ export class GltfExportManager {
287
184
  clonedMaterial.metallic = 0.65;
288
185
  clonedMaterial.roughness = 0.15;
289
186
 
290
- return clonedMaterial;
291
- }
292
-
293
- /**
294
- * Inspect if a material was temporarily cloned for GLB export
295
- * @param mat Material to be inspected
296
- */
297
- protected isMaterialClonedForExport(mat: PBRMaterial): boolean {
298
- return has(mat.metadata, GltfExportManager._CLONED_FROM_MAT_METADATA_PROPERTY);
299
- }
187
+ injectMetadata(material, { [GltfExportManager._METADATA_PROPS.exchangeMaterialWith]: newName });
188
+ injectMetadata(clonedMaterial, { [GltfExportManager._METADATA_PROPS.deleteAfterExport]: true });
300
189
 
301
- /**
302
- * Set unique mesh names for GLB export.
303
- * Duplicate names lead to problems in AR on iOS devices.
304
- */
305
- protected setUniqueMeshNames(scene: Scene): void {
306
- const allNodes = scene.getNodes().filter(node => node instanceof TransformNode) as TransformNode[];
307
- allNodes.forEach(currMesh => {
308
- injectMetadata(currMesh, { [GltfExportManager.NAME_BEFORE_EXPORT_METADATA_PROPERTY]: currMesh.name }, false);
309
- currMesh.name = `${currMesh.name}_${currMesh.uniqueId}`;
310
- });
190
+ return clonedMaterial;
311
191
  }
312
192
  }
@@ -1,45 +1,16 @@
1
- import { MorphTargetManager } from '@babylonjs/core';
2
1
  import { VertexBuffer } from '@babylonjs/core/Buffers/buffer';
3
2
  import { Vector3 } from '@babylonjs/core/Maths/math.vector';
4
- import type { Geometry } from '@babylonjs/core/Meshes';
3
+ import { type Geometry } from '@babylonjs/core/Meshes';
5
4
  import { InstancedMesh } from '@babylonjs/core/Meshes/instancedMesh';
6
5
  import { Mesh } from '@babylonjs/core/Meshes/mesh';
7
6
  import { TransformNode } from '@babylonjs/core/Meshes/transformNode';
8
7
  import type { MorphTarget } from '@babylonjs/core/Morph';
8
+ import { MorphTargetManager } from '@babylonjs/core/Morph/morphTargetManager';
9
9
  import type { FloatArray } from '@babylonjs/core/types';
10
10
 
11
- /**
12
- * Removes morph targets and sets transformation values back to their default values.
13
- * The effects from morph targets and tranformation values will be "baked" in the geometry, so that the final appearance
14
- * of the meshes stay the same.
15
- */
16
- const bakeGeometryOfAllMeshes = function (scene: Scene) {
17
- // instanced meshes have to be converted, since they share the geometry of the source mesh, which would lead to issues
18
- // when baking the transformation values
19
- scene.meshes.forEach(mesh => {
20
- if (mesh instanceof InstancedMesh) {
21
- convertInstancedMeshToMesh(mesh);
22
- }
23
- });
24
-
25
- // do the geometry baking for all meshes in the scene
26
- scene.meshes.forEach(mesh => {
27
- if (mesh instanceof Mesh) {
28
- bakeGeometryOfMesh(mesh);
29
- }
30
- });
31
-
32
- // some nodes (mostly transform nodes), are not affected by the baking algorithm since they have no geometry
33
- // => reset their transformation manually
34
- const allNodes = scene.getNodes().filter(node => node instanceof TransformNode) as TransformNode[];
35
- allNodes.forEach(node => {
36
- resetTransformation(node);
37
- });
38
- };
39
-
40
- const convertInstancedMeshToMesh = function (instancedMesh: InstancedMesh) {
11
+ const createMeshFromInstancedMesh = function (instancedMesh: InstancedMesh, newName: string) {
41
12
  // first create a clone of the source mesh
42
- const newMesh = instancedMesh.sourceMesh.clone(`${instancedMesh.name}`, instancedMesh.parent);
13
+ const newMesh = instancedMesh.sourceMesh.clone(newName, instancedMesh.parent);
43
14
  // apply the transformation data
44
15
  newMesh.position = instancedMesh.position;
45
16
  newMesh.rotation = instancedMesh.rotation;
@@ -48,10 +19,7 @@ const convertInstancedMeshToMesh = function (instancedMesh: InstancedMesh) {
48
19
  // also sync the enabled state from the original instanced mesh
49
20
  newMesh.setEnabled(instancedMesh.isEnabled(false));
50
21
 
51
- // re-assign children of the original mesh, since that one won't be used anymore
52
- instancedMesh.getChildren(undefined).forEach(childNode => (childNode.parent = newMesh));
53
- // finally delete the original instanced mesh
54
- instancedMesh.dispose();
22
+ return newMesh;
55
23
  };
56
24
 
57
25
  const bakeGeometryOfMesh = function (mesh: Mesh) {
@@ -69,10 +37,10 @@ const bakeGeometryOfMesh = function (mesh: Mesh) {
69
37
  if (morphTargetManager?.numTargets) {
70
38
  // apply morph target vertices data to mesh geometry
71
39
  // mostly only the "PositionKind" is implemented
72
- bakeMorphTargetManagerIntoVertices(VertexBuffer.PositionKind, morphTargetManager, geometry);
73
- bakeMorphTargetManagerIntoVertices(VertexBuffer.NormalKind, morphTargetManager, geometry);
74
- bakeMorphTargetManagerIntoVertices(VertexBuffer.TangentKind, morphTargetManager, geometry);
75
- bakeMorphTargetManagerIntoVertices(VertexBuffer.UVKind, morphTargetManager, geometry);
40
+ _bakeMorphTargetManagerIntoVertices(VertexBuffer.PositionKind, morphTargetManager, geometry);
41
+ _bakeMorphTargetManagerIntoVertices(VertexBuffer.NormalKind, morphTargetManager, geometry);
42
+ _bakeMorphTargetManagerIntoVertices(VertexBuffer.TangentKind, morphTargetManager, geometry);
43
+ _bakeMorphTargetManagerIntoVertices(VertexBuffer.UVKind, morphTargetManager, geometry);
76
44
 
77
45
  // remove morph target manager with all it's morph targets
78
46
  mesh.morphTargetManager = null;
@@ -86,7 +54,7 @@ const bakeGeometryOfMesh = function (mesh: Mesh) {
86
54
  * @param kind morph targets can affect various vertices kinds, whereas "position" is the most common one
87
55
  * still other kinds (like normals or tangents) can be affected as well and can be provided on this input
88
56
  */
89
- const bakeMorphTargetManagerIntoVertices = function (
57
+ const _bakeMorphTargetManagerIntoVertices = function (
90
58
  kind: string,
91
59
  morphTargetManager: MorphTargetManager,
92
60
  geometry: Geometry
@@ -100,7 +68,7 @@ const bakeMorphTargetManagerIntoVertices = function (
100
68
  let verticesData = [...origVerticesData];
101
69
  for (let i = 0; i < morphTargetManager.numTargets; i++) {
102
70
  const target = morphTargetManager.getTarget(i);
103
- const targetVerticesData = getVerticesDataFromMorphTarget(kind, target);
71
+ const targetVerticesData = _getVerticesDataFromMorphTarget(kind, target);
104
72
  if (targetVerticesData) {
105
73
  // vertices data of this kind are implemented on the morph target
106
74
  // add the influence of this morph target to the vertices data
@@ -115,7 +83,7 @@ const bakeMorphTargetManagerIntoVertices = function (
115
83
  geometry.setVerticesData(kind, verticesData);
116
84
  };
117
85
 
118
- const getVerticesDataFromMorphTarget = function (kind: string, morphTarget: MorphTarget): Nullable<FloatArray> {
86
+ const _getVerticesDataFromMorphTarget = function (kind: string, morphTarget: MorphTarget): Nullable<FloatArray> {
119
87
  switch (kind) {
120
88
  case VertexBuffer.PositionKind:
121
89
  return morphTarget.getPositions();
@@ -137,4 +105,4 @@ const resetTransformation = function (node: TransformNode) {
137
105
  node.scaling = new Vector3(1, 1, 1);
138
106
  };
139
107
 
140
- export { bakeGeometryOfAllMeshes };
108
+ export { createMeshFromInstancedMesh, bakeGeometryOfMesh, resetTransformation };
@@ -1,7 +1,6 @@
1
1
  import { Element } from '../classes/element';
2
2
  import { Variant } from '../classes/variant';
3
3
  import { VariantInstance } from '../classes/variantInstance';
4
- import { GltfExportManager } from '../manager/gltfExportManager';
5
4
  import { TransformNode } from '@babylonjs/core/Meshes/transformNode';
6
5
  import { Tags } from '@babylonjs/core/Misc/tags';
7
6
 
@@ -13,10 +12,7 @@ import { Tags } from '@babylonjs/core/Misc/tags';
13
12
  */
14
13
  const isNodeIncludedInExclusionList = function (node: TransformNode, list: ExcludedGeometryList): boolean {
15
14
  const checkNode = (inputNode: TransformNode, nodeToCheck: TransformNode) => {
16
- // check name instead of unique id, since the unique id changes when copying the scene, which is the case in the
17
- // GLB export
18
- const nodeName = nodeToCheck.metadata?.[GltfExportManager.NAME_BEFORE_EXPORT_METADATA_PROPERTY] ?? nodeToCheck.name;
19
- return inputNode.name === nodeName;
15
+ return inputNode.name === nodeToCheck.name;
20
16
  };
21
17
  const checkElement = (inputEl: Element, nodeToCheck: TransformNode) => {
22
18
  return inputEl.nodesFlat.some(m => checkNode(m, nodeToCheck));
@@ -28,8 +24,7 @@ const isNodeIncludedInExclusionList = function (node: TransformNode, list: Exclu
28
24
  return inputVarInst.variant.elements.some(el => checkElement(el, nodeToCheck));
29
25
  };
30
26
  const checkTagManagerSubject = (inputSubject: TagManagerSubject, nodeToCheck: TransformNode) => {
31
- const nodeName = nodeToCheck.metadata?.[GltfExportManager.NAME_BEFORE_EXPORT_METADATA_PROPERTY] ?? nodeToCheck.name;
32
- const nameMatches = inputSubject.nodeName && inputSubject.nodeName === nodeName;
27
+ const nameMatches = inputSubject.nodeName && inputSubject.nodeName === nodeToCheck.name;
33
28
  const tagMatches = inputSubject.tagName && Tags.MatchesQuery(nodeToCheck, inputSubject.tagName);
34
29
  return nameMatches || tagMatches;
35
30
  };