@combeenation/3d-viewer 20.0.0-alpha1 → 20.0.0-beta1

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.
@@ -83,6 +83,16 @@ export type UpdateShadowsSettings = {
83
83
  excludeReceiverNodes?: NodeDescription[];
84
84
  };
85
85
 
86
+ export type CalculateBoundingInfoSettings = {
87
+ /** Optional list of nodes to be excluded from bounding info calculation */
88
+ excludeNodes?: NodeDescription[];
89
+ /**
90
+ * Defines if HTML anchors should be considered for the bounding info calculation.\
91
+ * Default: `true`
92
+ */
93
+ excludeHtmlAnchors?: boolean;
94
+ };
95
+
86
96
  /**
87
97
  * Additional scene settings, which are not available in a basic `AssetContainer`.
88
98
  * !!! IMPORTANT when adding a new property !!!
@@ -104,6 +114,8 @@ type SceneAsset = BaseAsset & {
104
114
  * This contains creating or loading scenes with certain settings for lighting, cameras and appearance in genereal.
105
115
  */
106
116
  export class SceneManager {
117
+ protected static _DEFAULT_SCENE_ASSET_ENVIRONMENT_URL =
118
+ 'https://cbnpeuwstservice.blob.core.windows.net/viewer3d/static/studio.env';
107
119
  protected static _DEFAULT_SCENE_ASSET_NAME = '$defaultScene';
108
120
  protected static _DEFAULT_GROUND_PLANE_NAME = 'BackgroundPlane';
109
121
  protected static _DEFAULT_GROUND_SIZING_FACTOR = 5;
@@ -125,7 +137,7 @@ export class SceneManager {
125
137
 
126
138
  environment: {
127
139
  create: true,
128
- url: 'https://assets.babylonjs.com/environments/environmentSpecular.env',
140
+ url: SceneManager._DEFAULT_SCENE_ASSET_ENVIRONMENT_URL,
129
141
  intensity: 1,
130
142
  },
131
143
  };
@@ -280,7 +292,9 @@ export class SceneManager {
280
292
  * - do not have a material of type "BackgroundMaterial"
281
293
  * - do not have an infinite distance (like sky boxes)
282
294
  */
283
- public calculateBoundingInfo(excludeNodes?: NodeDescription[]): BoundingInfo {
295
+ public calculateBoundingInfo(settings?: CalculateBoundingInfoSettings): BoundingInfo {
296
+ const { excludeNodes, excludeHtmlAnchors } = settings ?? {};
297
+
284
298
  // CB-6062: workaround for BoundingBox not respecting render loop
285
299
  this.viewer.scene.render();
286
300
 
@@ -293,7 +307,7 @@ export class SceneManager {
293
307
  hasInvalidBoundingInfo: true,
294
308
  hasInfiniteDistance: true,
295
309
  isGeneratedBackgroundMesh: true,
296
- isHtmlAnchorMesh: true,
310
+ isHtmlAnchorMesh: excludeHtmlAnchors !== false,
297
311
  });
298
312
 
299
313
  return !isExcluded;
@@ -321,7 +335,7 @@ export class SceneManager {
321
335
  * plane mesh can be used as well.
322
336
  */
323
337
  public updateGround(settings?: UpdateGroundSettings): void {
324
- const bboxInfo = this.calculateBoundingInfo(settings?.excludeNodes);
338
+ const bboxInfo = this.calculateBoundingInfo({ excludeNodes: settings?.excludeNodes });
325
339
 
326
340
  const groundMesh = settings?.groundMesh ?? this.viewer.scene.getMeshByName(SceneManager._DEFAULT_GROUND_PLANE_NAME);
327
341
  if (!groundMesh) {
@@ -4,6 +4,8 @@ import {
4
4
  Mesh,
5
5
  MorphTarget,
6
6
  MorphTargetManager,
7
+ Node,
8
+ Tags,
7
9
  TransformNode,
8
10
  Vector3,
9
11
  VertexBuffer,
@@ -13,6 +15,7 @@ import {
13
15
  export type BakeGeometrySettings = {
14
16
  keepTransformation?: boolean;
15
17
  };
18
+
16
19
  export type CreateTransformNodeSettings = {
17
20
  parentNode?: TransformNode;
18
21
  position?: Vector3;
@@ -20,6 +23,34 @@ export type CreateTransformNodeSettings = {
20
23
  scaling?: Vector3;
21
24
  };
22
25
 
26
+ /**
27
+ * Expected metadata structure for find node functions {@link ViewerUtils.findChildNodes} and
28
+ * {@link ViewerUtils.findParentNode}
29
+ */
30
+ export type MetadataObject = Record<string, unknown>;
31
+
32
+ /**
33
+ * Contains all constructor that derive from `Node`, e.g. `TransformNode`, `Mesh`
34
+ */
35
+ export type DerivedNodeType<T extends Node> = new (...args: any[]) => T;
36
+
37
+ /**
38
+ * Criteria object for find node functions {@link ViewerUtils.findChildNodes} and {@link ViewerUtils.findParentNode}.\
39
+ * If property is omitted, the dedicated filter passes.
40
+ *
41
+ * @param nodeName has to match exactly
42
+ * @param tagName uses algorithm of `Tags.MatchesQuery`, in most cases this is just an exact string match check
43
+ * @param metadataObject has to be an object, filter passes if all property values of the given input object match the
44
+ * checked node
45
+ * @param type nodes type has to match (e.g. Mesh)
46
+ */
47
+ export type FindNodeCriteria<T extends Node> = {
48
+ nodeName?: string;
49
+ tagName?: string;
50
+ metadataObject?: MetadataObject;
51
+ type?: DerivedNodeType<T>;
52
+ };
53
+
23
54
  export class ViewerUtils {
24
55
  /** @internal */
25
56
  public constructor(protected viewer: Viewer) {}
@@ -99,6 +130,41 @@ export class ViewerUtils {
99
130
  return node;
100
131
  }
101
132
 
133
+ /**
134
+ * Finds all child nodes (TransformNodes, Meshes, but also Lights, Cameras, etc...) that match a given criteria.
135
+ *
136
+ * @param node If left empty, all nodes of the scene are considered
137
+ * @param criteria If left empty, all child nodes are returned
138
+ */
139
+ public findChildNodes<T extends Node>(node?: Node, criteria?: FindNodeCriteria<T>): T[] {
140
+ const allNodes = node ? node.getChildren(undefined, false) : [...this.viewer.scene.getNodes()];
141
+
142
+ if (!criteria) return allNodes as T[];
143
+
144
+ const foundNodes = allNodes.filter(node => this._matchesFindNodeCriteria(node, criteria));
145
+ return foundNodes as T[];
146
+ }
147
+
148
+ /**
149
+ * Finds nearest node that matches a given criteria.\
150
+ * Returns `undefined` if no node could be found.
151
+ */
152
+ public findParentNode<T extends Node>(node: Node, criteria?: FindNodeCriteria<T>): T | undefined {
153
+ const parent = node.parent;
154
+ if (!parent) {
155
+ return undefined;
156
+ } else if (!criteria) {
157
+ return parent as T;
158
+ }
159
+
160
+ const matchesCriteria = this._matchesFindNodeCriteria(parent, criteria);
161
+ if (matchesCriteria) {
162
+ return parent as T;
163
+ } else {
164
+ return this.findParentNode(parent, criteria);
165
+ }
166
+ }
167
+
102
168
  /**
103
169
  * @param kind morph targets can affect various vertices kinds, whereas "position" is the most common one
104
170
  * still other kinds (like normals or tangents) can be affected as well and can be provided on this input
@@ -146,4 +212,22 @@ export class ViewerUtils {
146
212
 
147
213
  return null;
148
214
  }
215
+
216
+ protected _matchesFindNodeCriteria<T extends Node>(node: Node, criteria?: FindNodeCriteria<T>): boolean {
217
+ if (!criteria) return true;
218
+
219
+ const { nodeName, tagName, metadataObject, type } = criteria;
220
+ const nodeNameFits = !nodeName || node.name === nodeName;
221
+ const tagNameFits = !tagName || Tags.MatchesQuery(node, tagName);
222
+ const metadataFits = !metadataObject || this._matchesMetadata(node.metadata, metadataObject);
223
+ const typeFits = !type || node instanceof type;
224
+
225
+ return nodeNameFits && tagNameFits && metadataFits && typeFits;
226
+ }
227
+
228
+ protected _matchesMetadata(metadata: unknown, filter: MetadataObject): boolean {
229
+ if (!metadata || typeof metadata !== 'object') return false;
230
+
231
+ return Object.entries(filter).every(([key, value]) => (metadata as MetadataObject)[key] === value);
232
+ }
149
233
  }