@combeenation/3d-viewer 11.0.0 → 11.1.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@combeenation/3d-viewer",
3
- "version": "11.0.0",
3
+ "version": "11.1.0",
4
4
  "description": "Combeenation 3D Viewer",
5
5
  "homepage": "https://github.com/Combeenation/3d-viewer#readme",
6
6
  "bugs": {
@@ -51,6 +51,7 @@
51
51
  "@babylonjs/loaders": "6.27.1",
52
52
  "@babylonjs/materials": "6.27.1",
53
53
  "@babylonjs/node-editor": "6.27.1",
54
+ "@babylonjs/node-geometry-editor": "6.27.1",
54
55
  "@babylonjs/serializers": "6.27.1",
55
56
  "eventemitter3": "4.0.7",
56
57
  "gsap": "3.11.2",
@@ -359,6 +359,7 @@ export class Viewer extends EventBroadcaster {
359
359
  // load additional packages for certain inspector features like "node material editor"
360
360
  // this is done after showing the debug layer to save time
361
361
  await import(/* webpackChunkName: "node-material-editor" */ '@babylonjs/node-editor');
362
+ await import(/* webpackChunkName: "node-geometry-editor" */ '@babylonjs/node-geometry-editor');
362
363
 
363
364
  return true;
364
365
  } else {
@@ -1,12 +1,13 @@
1
- import { bakeGeometryOfAllMeshes } from '..//util/geometryHelper';
2
1
  import { Viewer } from '../classes/viewer';
3
2
  import { injectMetadata } from '../util/babylonHelper';
3
+ import { bakeGeometryOfAllMeshes } from '../util/geometryHelper';
4
4
  import { isNodeIncludedInExclusionList } from '../util/structureHelper';
5
5
  import { Engine } from '@babylonjs/core/Engines/engine';
6
6
  import { EngineStore } from '@babylonjs/core/Engines/engineStore';
7
7
  import { SceneLoader } from '@babylonjs/core/Loading/sceneLoader';
8
8
  import { PBRMaterial } from '@babylonjs/core/Materials/PBR/pbrMaterial';
9
9
  import { Color3 } from '@babylonjs/core/Maths/math.color';
10
+ import { Vector3 } from '@babylonjs/core/Maths/math.vector';
10
11
  import { AbstractMesh } from '@babylonjs/core/Meshes/abstractMesh';
11
12
  import { TransformNode } from '@babylonjs/core/Meshes/transformNode';
12
13
  import { SceneSerializer } from '@babylonjs/core/Misc/sceneSerializer';
@@ -16,9 +17,11 @@ import { has, merge } from 'lodash-es';
16
17
 
17
18
  type MetadataMap = { [key: string]: any };
18
19
  export class GltfExportManager {
19
- protected static readonly _CLONED_FROM_MAT_METADATA_PROPERTY = 'clonedFrom';
20
20
  public static readonly NAME_BEFORE_EXPORT_METADATA_PROPERTY = 'nameBeforeExport';
21
21
 
22
+ protected static readonly _EXPORT_ROOT_NAME = '__export_root__';
23
+ protected static readonly _CLONED_FROM_MAT_METADATA_PROPERTY = 'clonedFrom';
24
+
22
25
  /**
23
26
  * Constructor.
24
27
  */
@@ -162,15 +165,37 @@ export class GltfExportManager {
162
165
  }
163
166
 
164
167
  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
168
  // certain devices can't load models with skeletons, just remove them since animations are not supported in the AR
169
169
  // scene anyway
170
170
  while (copiedScene.skeletons.length) {
171
171
  const skeleton = copiedScene.skeletons.pop();
172
172
  skeleton!.dispose();
173
173
  }
174
+ // also get rid of cameras and lights, as we don't need them in AR
175
+ while (copiedScene.cameras.length) {
176
+ const camera = copiedScene.cameras.pop();
177
+ camera!.dispose();
178
+ }
179
+ while (copiedScene.lights.length) {
180
+ const light = copiedScene.lights.pop();
181
+ light!.dispose();
182
+ }
183
+
184
+ // since Babylon.js v6 the conversion to right handed GLB coordinate system is done differently
185
+ // previously the geometry itself has been altered, now they negate the scaling of all root nodes
186
+ // this is an issue for us, since we will receive this negated scalings in the exported GLB, which leads to issues
187
+ // on iOS devices
188
+ // we fix that by adding a top level root node with a negative scaling as well
189
+ // the exporter just removes this node as he detects a "noop root node" (implementation detail of Babylon.js)
190
+ // everything beneath this node remains untouched
191
+ // TODO BJS update: Test AR export on iPhones as well and double check if we still need this special logic.
192
+ const exportRootNode = new TransformNode(GltfExportManager._EXPORT_ROOT_NAME, copiedScene);
193
+ exportRootNode.scaling = new Vector3(-1, 1, 1);
194
+ copiedScene.rootNodes.forEach(rootNode => (rootNode.parent = exportRootNode));
195
+
196
+ this.setUniqueMeshNames(copiedScene);
197
+ // get rid of negative scalings and morph targets, since iOS can't handle it in the QuickLook app
198
+ bakeGeometryOfAllMeshes(copiedScene, [{ nodeName: GltfExportManager._EXPORT_ROOT_NAME }]);
174
199
  }
175
200
 
176
201
  return { scene: copiedScene, sceneCopied: true };
@@ -1,3 +1,4 @@
1
+ import { isNodeIncludedInExclusionList } from './structureHelper';
1
2
  import { MorphTargetManager } from '@babylonjs/core';
2
3
  import { VertexBuffer } from '@babylonjs/core/Buffers/buffer';
3
4
  import { Vector3 } from '@babylonjs/core/Maths/math.vector';
@@ -13,17 +14,25 @@ import type { FloatArray } from '@babylonjs/core/types';
13
14
  * The effects from morph targets and tranformation values will be "baked" in the geometry, so that the final appearance
14
15
  * of the meshes stay the same.
15
16
  */
16
- const bakeGeometryOfAllMeshes = function (scene: Scene) {
17
+ const bakeGeometryOfAllMeshes = function (scene: Scene, excluded?: ExcludedGeometryList) {
18
+ // in some cases we want to keep the transformation of certain nodes
19
+ // => root node for Gltf export
20
+ // it's important to NOT check parents in this case
21
+ const keepNode = (node: TransformNode, excluded?: ExcludedGeometryList) =>
22
+ !excluded || !isNodeIncludedInExclusionList(node, excluded, true);
23
+
24
+ const meshes = scene.meshes.filter(mesh => keepNode(mesh, excluded));
25
+
17
26
  // instanced meshes have to be converted, since they share the geometry of the source mesh, which would lead to issues
18
27
  // when baking the transformation values
19
- scene.meshes.forEach(mesh => {
28
+ meshes.forEach(mesh => {
20
29
  if (mesh instanceof InstancedMesh) {
21
30
  convertInstancedMeshToMesh(mesh);
22
31
  }
23
32
  });
24
33
 
25
34
  // do the geometry baking for all meshes in the scene
26
- scene.meshes.forEach(mesh => {
35
+ meshes.forEach(mesh => {
27
36
  if (mesh instanceof Mesh) {
28
37
  bakeGeometryOfMesh(mesh);
29
38
  }
@@ -31,7 +40,9 @@ const bakeGeometryOfAllMeshes = function (scene: Scene) {
31
40
 
32
41
  // some nodes (mostly transform nodes), are not affected by the baking algorithm since they have no geometry
33
42
  // => reset their transformation manually
34
- const allNodes = scene.getNodes().filter(node => node instanceof TransformNode) as TransformNode[];
43
+ const allNodes = scene
44
+ .getNodes()
45
+ .filter(node => node instanceof TransformNode && keepNode(node, excluded)) as TransformNode[];
35
46
  allNodes.forEach(node => {
36
47
  resetTransformation(node);
37
48
  });
@@ -11,7 +11,11 @@ import { Tags } from '@babylonjs/core/Misc/tags';
11
11
  * @param list list of excluded geometry
12
12
  * @returns boolean based on whether node (or one of its parents) was found in list
13
13
  */
14
- const isNodeIncludedInExclusionList = function (node: TransformNode, list: ExcludedGeometryList): boolean {
14
+ const isNodeIncludedInExclusionList = function (
15
+ node: TransformNode,
16
+ list: ExcludedGeometryList,
17
+ skipParentCheck?: boolean
18
+ ): boolean {
15
19
  const checkNode = (inputNode: TransformNode, nodeToCheck: TransformNode) => {
16
20
  // check name instead of unique id, since the unique id changes when copying the scene, which is the case in the
17
21
  // GLB export
@@ -53,7 +57,7 @@ const isNodeIncludedInExclusionList = function (node: TransformNode, list: Exclu
53
57
  };
54
58
 
55
59
  let isExcluded = list.some(geometryToExclude => check(geometryToExclude, node));
56
- if (!isExcluded && node.parent instanceof TransformNode) {
60
+ if (!isExcluded && !skipParentCheck && node.parent instanceof TransformNode) {
57
61
  isExcluded = isNodeIncludedInExclusionList(node.parent, list);
58
62
  }
59
63