@loaders.gl/tile-converter 4.0.0-alpha.24 → 4.0.0-alpha.25

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 (44) hide show
  1. package/dist/3d-tiles-converter/helpers/b3dm-converter.d.ts +4 -4
  2. package/dist/converter.min.js +106 -106
  3. package/dist/dist.min.js +507 -489
  4. package/dist/es5/3d-tiles-converter/helpers/b3dm-converter.js +18 -18
  5. package/dist/es5/3d-tiles-converter/helpers/b3dm-converter.js.map +1 -1
  6. package/dist/es5/deps-installer/deps-installer.js +1 -1
  7. package/dist/es5/i3s-converter/helpers/batch-ids-extensions.js +16 -14
  8. package/dist/es5/i3s-converter/helpers/batch-ids-extensions.js.map +1 -1
  9. package/dist/es5/i3s-converter/helpers/geometry-converter.js +4 -76
  10. package/dist/es5/i3s-converter/helpers/geometry-converter.js.map +1 -1
  11. package/dist/es5/i3s-converter/helpers/preprocess-3d-tiles.js +15 -8
  12. package/dist/es5/i3s-converter/helpers/preprocess-3d-tiles.js.map +1 -1
  13. package/dist/es5/i3s-converter/i3s-converter.js.map +1 -1
  14. package/dist/es5/i3s-converter/types.js.map +1 -1
  15. package/dist/es5/pgm-loader.js +1 -1
  16. package/dist/esm/3d-tiles-converter/helpers/b3dm-converter.js +8 -8
  17. package/dist/esm/3d-tiles-converter/helpers/b3dm-converter.js.map +1 -1
  18. package/dist/esm/deps-installer/deps-installer.js +1 -1
  19. package/dist/esm/i3s-converter/helpers/batch-ids-extensions.js +5 -15
  20. package/dist/esm/i3s-converter/helpers/batch-ids-extensions.js.map +1 -1
  21. package/dist/esm/i3s-converter/helpers/geometry-converter.js +3 -75
  22. package/dist/esm/i3s-converter/helpers/geometry-converter.js.map +1 -1
  23. package/dist/esm/i3s-converter/helpers/preprocess-3d-tiles.js +15 -9
  24. package/dist/esm/i3s-converter/helpers/preprocess-3d-tiles.js.map +1 -1
  25. package/dist/esm/i3s-converter/i3s-converter.js.map +1 -1
  26. package/dist/esm/i3s-converter/types.js.map +1 -1
  27. package/dist/esm/i3s-server/bin/i3s-server.min.js +75 -75
  28. package/dist/esm/pgm-loader.js +1 -1
  29. package/dist/i3s-converter/helpers/batch-ids-extensions.d.ts +4 -1
  30. package/dist/i3s-converter/helpers/batch-ids-extensions.d.ts.map +1 -1
  31. package/dist/i3s-converter/helpers/geometry-converter.d.ts +1 -1
  32. package/dist/i3s-converter/helpers/geometry-converter.d.ts.map +1 -1
  33. package/dist/i3s-converter/helpers/preprocess-3d-tiles.d.ts.map +1 -1
  34. package/dist/i3s-converter/i3s-converter.d.ts.map +1 -1
  35. package/dist/i3s-converter/types.d.ts +6 -1
  36. package/dist/i3s-converter/types.d.ts.map +1 -1
  37. package/dist/slpk-extractor.min.js +42 -42
  38. package/package.json +14 -14
  39. package/src/3d-tiles-converter/helpers/b3dm-converter.ts +8 -8
  40. package/src/i3s-converter/helpers/batch-ids-extensions.ts +14 -35
  41. package/src/i3s-converter/helpers/geometry-converter.ts +23 -168
  42. package/src/i3s-converter/helpers/preprocess-3d-tiles.ts +30 -9
  43. package/src/i3s-converter/i3s-converter.ts +0 -2
  44. package/src/i3s-converter/types.ts +6 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@loaders.gl/tile-converter",
3
- "version": "4.0.0-alpha.24",
3
+ "version": "4.0.0-alpha.25",
4
4
  "description": "Converter",
5
5
  "license": "MIT",
6
6
  "publishConfig": {
@@ -45,18 +45,18 @@
45
45
  "build-i3s-server-bundle": "esbuild src/i3s-server/bin/www.ts --outfile=dist/esm/i3s-server/bin/i3s-server.min.js --platform=node --target=esnext,node14 --external:join-images --minify --bundle --define:__VERSION__=\\\"$npm_package_version\\\""
46
46
  },
47
47
  "dependencies": {
48
- "@loaders.gl/3d-tiles": "4.0.0-alpha.24",
49
- "@loaders.gl/crypto": "4.0.0-alpha.24",
50
- "@loaders.gl/draco": "4.0.0-alpha.24",
51
- "@loaders.gl/gltf": "4.0.0-alpha.24",
52
- "@loaders.gl/i3s": "4.0.0-alpha.24",
53
- "@loaders.gl/images": "4.0.0-alpha.24",
54
- "@loaders.gl/loader-utils": "4.0.0-alpha.24",
55
- "@loaders.gl/polyfills": "4.0.0-alpha.24",
56
- "@loaders.gl/textures": "4.0.0-alpha.24",
57
- "@loaders.gl/tiles": "4.0.0-alpha.24",
58
- "@loaders.gl/worker-utils": "4.0.0-alpha.24",
59
- "@loaders.gl/zip": "4.0.0-alpha.24",
48
+ "@loaders.gl/3d-tiles": "4.0.0-alpha.25",
49
+ "@loaders.gl/crypto": "4.0.0-alpha.25",
50
+ "@loaders.gl/draco": "4.0.0-alpha.25",
51
+ "@loaders.gl/gltf": "4.0.0-alpha.25",
52
+ "@loaders.gl/i3s": "4.0.0-alpha.25",
53
+ "@loaders.gl/images": "4.0.0-alpha.25",
54
+ "@loaders.gl/loader-utils": "4.0.0-alpha.25",
55
+ "@loaders.gl/polyfills": "4.0.0-alpha.25",
56
+ "@loaders.gl/textures": "4.0.0-alpha.25",
57
+ "@loaders.gl/tiles": "4.0.0-alpha.25",
58
+ "@loaders.gl/worker-utils": "4.0.0-alpha.25",
59
+ "@loaders.gl/zip": "4.0.0-alpha.25",
60
60
  "@math.gl/core": "^3.5.1",
61
61
  "@math.gl/culling": "^3.5.1",
62
62
  "@math.gl/geoid": "^3.5.1",
@@ -80,7 +80,7 @@
80
80
  "join-images": "^1.1.3",
81
81
  "sharp": "^0.31.3"
82
82
  },
83
- "gitHead": "97a8990595c132fb14e3445a8768d9f4cb98ff05",
83
+ "gitHead": "40135f391b869388dbbcd615bbe51178d0c370be",
84
84
  "devDependencies": {
85
85
  "@types/express": "^4.17.17",
86
86
  "@types/node": "^20.4.2"
@@ -33,7 +33,7 @@ export default class B3dmConverter {
33
33
  i3sAttributesData: I3SAttributesData,
34
34
  featureAttributes: any = null
35
35
  ): Promise<ArrayBuffer> {
36
- const gltf = await this.buildGltf(i3sAttributesData, featureAttributes);
36
+ const gltf = await this.buildGLTF(i3sAttributesData, featureAttributes);
37
37
  const b3dm = encodeSync(
38
38
  {
39
39
  gltfEncoded: new Uint8Array(gltf),
@@ -51,7 +51,7 @@ export default class B3dmConverter {
51
51
  * @param i3sTile - Tile3D instance for I3S node
52
52
  * @returns - encoded glb content
53
53
  */
54
- async buildGltf(
54
+ async buildGLTF(
55
55
  i3sAttributesData: I3SAttributesData,
56
56
  featureAttributes: any
57
57
  ): Promise<ArrayBuffer> {
@@ -59,8 +59,8 @@ export default class B3dmConverter {
59
59
  const {material, attributes, indices: originalIndices, modelMatrix} = tileContent;
60
60
  const gltfBuilder = new GLTFScenegraph();
61
61
 
62
- const textureIndex = await this._addI3sTextureToGltf(tileContent, textureFormat, gltfBuilder);
63
- const pbrMaterialInfo = this._convertI3sMaterialToGltfMaterial(material, textureIndex);
62
+ const textureIndex = await this._addI3sTextureToGLTF(tileContent, textureFormat, gltfBuilder);
63
+ const pbrMaterialInfo = this._convertI3sMaterialToGLTFMaterial(material, textureIndex);
64
64
  const materialIndex = gltfBuilder.addMaterial(pbrMaterialInfo);
65
65
 
66
66
  const positions = attributes.positions;
@@ -115,7 +115,7 @@ export default class B3dmConverter {
115
115
  * @param {GLTFScenegraph} gltfBuilder - gltfScenegraph instance to construct GLTF
116
116
  * @returns {Promise<number | null>} - GLTF texture index
117
117
  */
118
- async _addI3sTextureToGltf(tileContent, textureFormat, gltfBuilder) {
118
+ async _addI3sTextureToGLTF(tileContent, textureFormat, gltfBuilder) {
119
119
  const {texture, material, attributes} = tileContent;
120
120
  let textureIndex = null;
121
121
  let selectedTexture = texture;
@@ -222,7 +222,7 @@ export default class B3dmConverter {
222
222
  * @param {number | null} textureIndex - texture index in GLTF
223
223
  * @returns {object} GLTF material
224
224
  */
225
- _convertI3sMaterialToGltfMaterial(material, textureIndex) {
225
+ _convertI3sMaterialToGLTFMaterial(material, textureIndex) {
226
226
  const isTextureIndexExists = textureIndex !== null;
227
227
 
228
228
  if (!material) {
@@ -248,7 +248,7 @@ export default class B3dmConverter {
248
248
  }
249
249
 
250
250
  if (textureIndex !== null) {
251
- material = this._setGltfTexture(material, textureIndex);
251
+ material = this._setGLTFTexture(material, textureIndex);
252
252
  }
253
253
 
254
254
  return material;
@@ -260,7 +260,7 @@ export default class B3dmConverter {
260
260
  * @param {number} textureIndex - texture index in GLTF
261
261
  * @returns {void}
262
262
  */
263
- _setGltfTexture(materialDefinition, textureIndex) {
263
+ _setGLTFTexture(materialDefinition, textureIndex) {
264
264
  const material = {
265
265
  ...materialDefinition,
266
266
  pbrMetallicRoughness: {...materialDefinition.pbrMetallicRoughness}
@@ -3,8 +3,7 @@ import type {NumericArray} from '@loaders.gl/loader-utils';
3
3
  import type {
4
4
  GLTF_EXT_feature_metadata_FeatureIdTexture,
5
5
  GLTF_EXT_feature_metadata_GLTF,
6
- GLTF_EXT_feature_metadata_Primitive,
7
- GLTF_EXT_structural_metadata
6
+ GLTF_EXT_feature_metadata_Primitive
8
7
  } from '@loaders.gl/gltf';
9
8
 
10
9
  import type {GLTF_EXT_mesh_features} from '@loaders.gl/gltf';
@@ -12,11 +11,14 @@ import type {GLTF_EXT_mesh_features} from '@loaders.gl/gltf';
12
11
  import {TypedArray} from '@math.gl/core';
13
12
  import {TextureImageProperties} from '../types';
14
13
  import {emod} from '@loaders.gl/math';
15
- import {EXT_STRUCTURAL_METADATA, EXT_MESH_FEATURES, EXT_FEATURE_METADATA} from '@loaders.gl/gltf';
14
+ import {EXT_MESH_FEATURES, EXT_FEATURE_METADATA} from '@loaders.gl/gltf';
16
15
  import {Tiles3DTileContent} from '@loaders.gl/3d-tiles';
17
16
 
18
17
  /**
19
- * Get featureTexture by metadataClass
18
+ * Get featureTexture by a metadata class.
19
+ * Metadata classes come from a structural metadata extesion (EXT_feature_metadata or EXT_structural_metadata).
20
+ * The glTF might contain multiple texel-level metadata textures related to different classes. Having only one metadata class
21
+ * selected to convert to I3S, we have to pick only one texture to convert to per-vertex property.
20
22
  * @param tileContent - 3d tile content
21
23
  * @param metadataClass - user selected feature metadata class name
22
24
  * @returns featureTexture key
@@ -72,12 +74,6 @@ export function handleBatchIdsExtensions(
72
74
  );
73
75
  case EXT_MESH_FEATURES:
74
76
  return handleExtMeshFeaturesExtension(attributes, extensionData as GLTF_EXT_mesh_features);
75
- case EXT_STRUCTURAL_METADATA:
76
- return handleExtStructuralMetadataExtension(
77
- attributes,
78
- extensionData as GLTF_EXT_structural_metadata
79
- );
80
-
81
77
  default:
82
78
  return [];
83
79
  }
@@ -86,23 +82,6 @@ export function handleBatchIdsExtensions(
86
82
  return [];
87
83
  }
88
84
 
89
- function handleExtStructuralMetadataExtension(
90
- attributes: {
91
- [key: string]: GLTFAccessorPostprocessed;
92
- },
93
- extStructuralMetadata: GLTF_EXT_structural_metadata
94
- ): NumericArray {
95
- // Take only first extension object to get batchIds attribute name.
96
- const dataAttributeNames = extStructuralMetadata?.dataAttributeNames;
97
- if (dataAttributeNames?.length) {
98
- // Let's use the first element of the array
99
- // TODO: What to do with others if any?
100
- const batchIdsAttribute = attributes[dataAttributeNames[0]];
101
- return batchIdsAttribute.value;
102
- }
103
- return [];
104
- }
105
-
106
85
  /**
107
86
  * Getting batchIds from EXT_mesh_features extensions.
108
87
  * @param attributes - gltf accessors
@@ -115,19 +94,19 @@ function handleExtMeshFeaturesExtension(
115
94
  },
116
95
  extMeshFeatures: GLTF_EXT_mesh_features
117
96
  ): NumericArray {
118
- const dataAttributeNames = extMeshFeatures?.dataAttributeNames;
119
- if (dataAttributeNames?.length) {
120
- // Let's use the first element of the array
121
- // TODO: What to do with others if any?
122
- const batchIdsAttribute = attributes[dataAttributeNames[0]];
123
- return batchIdsAttribute.value;
97
+ for (let ids of extMeshFeatures.featureIds) {
98
+ if (typeof ids.propertyTable !== 'undefined') {
99
+ // propertyTable is an index that can be 0
100
+ // return the first featureID set that corresponts to property table.
101
+ return ids.data as NumericArray;
102
+ }
124
103
  }
125
104
  return [];
126
105
  }
127
106
 
128
107
  /**
129
108
  * Get batchIds from EXT_feature_metadata extension.
130
- * Docs - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata
109
+ * @see - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata
131
110
  * @param attributes - glTF attributes
132
111
  * @param extFeatureMetadata - primitive-level EXT_FEATURE_METADATA extension data
133
112
  * @param textures - texture images
@@ -182,7 +161,7 @@ function handleExtFeatureMetadataExtension(
182
161
 
183
162
  /**
184
163
  * Generates implicit feature ids
185
- * Spec - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata#implicit-feature-ids
164
+ * @see - https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_feature_metadata#implicit-feature-ids
186
165
  * @param featuresCount
187
166
  * @param constant
188
167
  * @param devisor
@@ -1,14 +1,13 @@
1
1
  import type {FeatureTableJson, Tiles3DTileContent} from '@loaders.gl/3d-tiles';
2
2
  import type {
3
- GLTF_EXT_mesh_features,
4
- GLTF_EXT_structural_metadata,
5
3
  GLTFAccessorPostprocessed,
6
4
  GLTFMaterialPostprocessed,
7
5
  GLTFNodePostprocessed,
8
6
  GLTFMeshPrimitivePostprocessed,
9
7
  GLTFMeshPostprocessed,
10
8
  GLTFTexturePostprocessed,
11
- GLTF_EXT_feature_metadata_GLTF
9
+ GLTF_EXT_feature_metadata_GLTF,
10
+ GLTF_EXT_structural_metadata_GLTF
12
11
  } from '@loaders.gl/gltf';
13
12
 
14
13
  import {Vector3, Matrix4, Vector4} from '@math.gl/core';
@@ -50,7 +49,12 @@ import type {GLTFAttributesData, TextureImageProperties, TypedArrayConstructor}
50
49
  import {generateSyntheticIndices} from '../../lib/utils/geometry-utils';
51
50
  import {BoundingSphere, OrientedBoundingBox} from '@math.gl/culling';
52
51
 
53
- import {EXT_MESH_FEATURES, EXT_FEATURE_METADATA, EXT_STRUCTURAL_METADATA} from '@loaders.gl/gltf';
52
+ import {
53
+ EXT_FEATURE_METADATA,
54
+ EXT_STRUCTURAL_METADATA,
55
+ getPropertyTableFromExtFeatureMetadata,
56
+ getPropertyTableFromExtStructuralMetadata
57
+ } from '@loaders.gl/gltf';
54
58
 
55
59
  // Spec - https://github.com/Esri/i3s-spec/blob/master/docs/1.7/pbrMetallicRoughness.cmn.md
56
60
  const DEFAULT_ROUGHNESS_FACTOR = 1;
@@ -385,7 +389,7 @@ export async function convertAttributes(
385
389
  }
386
390
 
387
391
  /**
388
- * Gltf has hierarchical structure of nodes. This function converts nodes starting from those which are in gltf scene object.
392
+ * glTF has hierarchical structure of nodes. This function converts nodes starting from those which are in gltf scene object.
389
393
  * The goal is applying tranformation matrix for all children. Functions "convertNodes" and "convertNode" work together recursively.
390
394
  * @param nodes - gltf nodes array
391
395
  * @param images - gltf images array
@@ -1053,7 +1057,7 @@ function convertMaterial(sourceMaterial: GLTFMaterialPostprocessed): I3SMaterial
1053
1057
 
1054
1058
  /**
1055
1059
  * Converts from `alphaMode` material property from GLTF to I3S format
1056
- * @param gltfAlphaMode Gltf material `alphaMode` property
1060
+ * @param gltfAlphaMode glTF material `alphaMode` property
1057
1061
  * @returns I3SMaterialDefinition.alphaMode property
1058
1062
  */
1059
1063
  function convertAlphaMode(
@@ -1606,7 +1610,7 @@ function generateFeatureIndexAttribute(
1606
1610
  * For example it can be batchTable for b3dm files or property table in gLTF extension.
1607
1611
  * @param tileContent - 3DTiles tile content
1608
1612
  * @param metadataClass - user selected feature metadata class name
1609
- * @return batch table from b3dm / feature properties from EXT_FEATURE_METADATA, EXT_MESH_FEATURES or EXT_STRUCTURAL_METADATA
1613
+ * @return batch table from b3dm / feature properties from EXT_FEATURE_METADATA or EXT_STRUCTURAL_METADATA.
1610
1614
  */
1611
1615
  export function getPropertyTable(
1612
1616
  tileContent: Tiles3DTileContent | null,
@@ -1616,7 +1620,7 @@ export function getPropertyTable(
1616
1620
  return null;
1617
1621
  }
1618
1622
  let propertyTable: FeatureTableJson | null;
1619
- const batchTableJson = tileContent?.batchTableJson;
1623
+ const batchTableJson = tileContent.batchTableJson;
1620
1624
 
1621
1625
  if (batchTableJson) {
1622
1626
  return batchTableJson;
@@ -1625,16 +1629,9 @@ export function getPropertyTable(
1625
1629
  const {extensionName, extension} = getPropertyTableExtension(tileContent);
1626
1630
 
1627
1631
  switch (extensionName) {
1628
- case EXT_MESH_FEATURES: {
1629
- propertyTable = getPropertyTableFromExtMeshFeatures(
1630
- extension as GLTF_EXT_mesh_features,
1631
- metadataClass
1632
- );
1633
- return propertyTable;
1634
- }
1635
1632
  case EXT_STRUCTURAL_METADATA: {
1636
1633
  propertyTable = getPropertyTableFromExtStructuralMetadata(
1637
- extension as GLTF_EXT_structural_metadata,
1634
+ extension as GLTF_EXT_structural_metadata_GLTF,
1638
1635
  metadataClass
1639
1636
  );
1640
1637
  return propertyTable;
@@ -1657,18 +1654,9 @@ export function getPropertyTable(
1657
1654
  */
1658
1655
  function getPropertyTableExtension(tileContent: Tiles3DTileContent): {
1659
1656
  extensionName: null | string;
1660
- extension:
1661
- | string
1662
- | GLTF_EXT_feature_metadata_GLTF
1663
- | GLTF_EXT_structural_metadata
1664
- | GLTF_EXT_mesh_features
1665
- | null;
1657
+ extension: string | GLTF_EXT_feature_metadata_GLTF | GLTF_EXT_structural_metadata_GLTF | null;
1666
1658
  } {
1667
- const extensionsWithPropertyTables = [
1668
- EXT_FEATURE_METADATA,
1669
- EXT_STRUCTURAL_METADATA,
1670
- EXT_MESH_FEATURES
1671
- ];
1659
+ const extensionsWithPropertyTables = [EXT_FEATURE_METADATA, EXT_STRUCTURAL_METADATA];
1672
1660
  const extensionsUsed = tileContent?.gltf?.extensionsUsed;
1673
1661
 
1674
1662
  if (!extensionsUsed) {
@@ -1679,6 +1667,12 @@ function getPropertyTableExtension(tileContent: Tiles3DTileContent): {
1679
1667
  for (const extensionItem of tileContent?.gltf?.extensionsUsed || []) {
1680
1668
  if (extensionsWithPropertyTables.includes(extensionItem)) {
1681
1669
  extensionName = extensionItem;
1670
+ /*
1671
+ It returns the first extension containing the property table.
1672
+ We assume that there can be only one extension containing the property table:
1673
+ either EXT_FEATURE_METADATA, which is a depricated extension,
1674
+ or EXT_STRUCTURAL_METADATA.
1675
+ */
1682
1676
  break;
1683
1677
  }
1684
1678
  }
@@ -1689,147 +1683,8 @@ function getPropertyTableExtension(tileContent: Tiles3DTileContent): {
1689
1683
 
1690
1684
  const extension = tileContent?.gltf?.extensions?.[extensionName] as
1691
1685
  | string // EXT_mesh_features doesn't have global metadata
1692
- | GLTF_EXT_feature_metadata_GLTF;
1686
+ | GLTF_EXT_feature_metadata_GLTF
1687
+ | GLTF_EXT_structural_metadata_GLTF;
1693
1688
 
1694
1689
  return {extensionName, extension};
1695
1690
  }
1696
-
1697
- /**
1698
- * Handle EXT_feature_metadata to get property table
1699
- * @param extension - global level of EXT_FEATURE_METADATA extension
1700
- * @param metadataClass - user selected feature metadata class name
1701
- * @returns {FeatureTableJson | null} Property table or null if the extension can't be handled properly.
1702
- */
1703
- function getPropertyTableFromExtFeatureMetadata(
1704
- extension: GLTF_EXT_feature_metadata_GLTF,
1705
- metadataClass?: string
1706
- ): FeatureTableJson | null {
1707
- if (extension?.featureTables) {
1708
- /**
1709
- * Take only first feature table to generate attributes storage info object.
1710
- * TODO: Think about getting data from all feature tables?
1711
- * It can be tricky just because 3dTiles is able to have multiple featureId attributes and multiple feature tables.
1712
- * In I3S we should decide which featureIds attribute will be passed to geometry data.
1713
- */
1714
- const firstFeatureTableName = Object.keys(extension.featureTables)?.[0];
1715
-
1716
- if (firstFeatureTableName) {
1717
- const featureTable = extension?.featureTables[firstFeatureTableName];
1718
- const propertyTable = {};
1719
-
1720
- for (const propertyName in featureTable.properties) {
1721
- propertyTable[propertyName] = featureTable.properties[propertyName].data;
1722
- }
1723
-
1724
- return propertyTable;
1725
- }
1726
- }
1727
-
1728
- if (extension?.featureTextures) {
1729
- let featureTexture: string | undefined;
1730
- for (const textureKey in extension.featureTextures) {
1731
- const texture = extension.featureTextures[textureKey];
1732
- if (texture.class === metadataClass) {
1733
- featureTexture = textureKey;
1734
- }
1735
- }
1736
-
1737
- if (typeof featureTexture === 'string') {
1738
- const featureTable = extension?.featureTextures[featureTexture];
1739
- const propertyTable = {};
1740
-
1741
- for (const propertyName in featureTable.properties) {
1742
- propertyTable[propertyName] = featureTable.properties[propertyName].data;
1743
- }
1744
-
1745
- return propertyTable;
1746
- }
1747
- }
1748
-
1749
- console.warn(
1750
- "The I3S converter couldn't handle EXT_feature_metadata extension: There is neither featureTables, no featureTextures in the extension."
1751
- );
1752
- return null;
1753
- }
1754
-
1755
- /**
1756
- * Handle EXT_structural_metadata to get property table
1757
- * @param extension - global level of EXT_STRUCTURAL_METADATA extension
1758
- * @param metadataClass - user selected feature metadata class name
1759
- * @returns {FeatureTableJson | null} Property table or null if the extension can't be handled properly.
1760
- */
1761
- function getPropertyTableFromExtStructuralMetadata(
1762
- extension: GLTF_EXT_structural_metadata,
1763
- metadataClass?: string
1764
- ): FeatureTableJson | null {
1765
- if (extension?.propertyTables) {
1766
- /**
1767
- * Take only first feature table to generate attributes storage info object.
1768
- * TODO: Think about getting data from all feature tables?
1769
- * It can be tricky just because 3dTiles is able to have multiple featureId attributes and multiple feature tables.
1770
- * In I3S we should decide which featureIds attribute will be passed to geometry data.
1771
- */
1772
- const firstPropertyTable = extension?.propertyTables[0];
1773
- const propertyTableWithData = {};
1774
-
1775
- for (const propertyName in firstPropertyTable.properties) {
1776
- propertyTableWithData[propertyName] = firstPropertyTable.properties[propertyName].data;
1777
- }
1778
-
1779
- return propertyTableWithData;
1780
- }
1781
-
1782
- if (extension?.propertyTextures) {
1783
- /**
1784
- * Take only first feature table to generate attributes storage info object.
1785
- * TODO: Think about getting data from all feature tables?
1786
- * It can be tricky just because 3dTiles is able to have multiple featureId attributes and multiple feature tables.
1787
- * In I3S we should decide which featureIds attribute will be passed to geometry data.
1788
- */
1789
- if (extension?.propertyTextures) {
1790
- const firstPropertyTexture = extension?.propertyTextures[0];
1791
- const propertyTableWithData = {};
1792
-
1793
- for (const propertyName in firstPropertyTexture.properties) {
1794
- propertyTableWithData[propertyName] = firstPropertyTexture.properties[propertyName].data;
1795
- }
1796
-
1797
- return propertyTableWithData;
1798
- }
1799
- }
1800
-
1801
- console.warn(
1802
- "The I3S converter couldn't handle EXT_structural_metadata extension: There is neither propertyTables, no propertyTextures in the extension."
1803
- );
1804
- return null;
1805
- }
1806
-
1807
- /**
1808
- * Handle EXT_mesh_features to get property table
1809
- * @param extension - global level of EXT_MESH_FEATURES extension
1810
- * @param metadataClass - user selected feature metadata class name
1811
- * @returns {FeatureTableJson | null} Property table or null if the extension can't be handled properly.
1812
- */
1813
- function getPropertyTableFromExtMeshFeatures(
1814
- extension: GLTF_EXT_mesh_features,
1815
- metadataClass?: string
1816
- ): FeatureTableJson | null {
1817
- if (extension?.featureIds) {
1818
- const firstFeatureId = extension?.featureIds[0];
1819
- const propertyTableWithData = {};
1820
-
1821
- // When firstFeatureId.propertyTable is defined, the property data will be taken from EXT_structural_metadata extension
1822
- if (!firstFeatureId.propertyTable) {
1823
- console.warn(
1824
- 'Should be implemented as we have the tileset with Ext_mesh_features not linked with EXT_structural_metadata extension'
1825
- );
1826
- }
1827
-
1828
- return propertyTableWithData;
1829
- }
1830
-
1831
- console.warn(
1832
- "The I3S converter couldn't handle EXT_mesh_features extension: There is no featureIds in the extension."
1833
- );
1834
- return null;
1835
- }
@@ -1,6 +1,12 @@
1
1
  import {Tiles3DTileContent} from '@loaders.gl/3d-tiles';
2
2
  import {GLTFPrimitiveModeString, PreprocessData} from '../types';
3
- import {GLTF, GLTFLoader, GLTF_EXT_feature_metadata_GLTF} from '@loaders.gl/gltf';
3
+ import {
4
+ EXT_STRUCTURAL_METADATA,
5
+ GLTF,
6
+ GLTFLoader,
7
+ GLTF_EXT_feature_metadata_GLTF,
8
+ GLTF_EXT_structural_metadata_GLTF
9
+ } from '@loaders.gl/gltf';
4
10
  import {parse} from '@loaders.gl/core';
5
11
  import {EXT_FEATURE_METADATA} from '@loaders.gl/gltf';
6
12
 
@@ -43,8 +49,8 @@ export const analyzeTileContent = async (
43
49
  if (!gltf) {
44
50
  return defaultResult;
45
51
  }
46
- const meshTopologyTypes = getMeshTypesFromGltf(gltf);
47
- const metadataClasses = getMetadataClassesFromGltf(gltf);
52
+ const meshTopologyTypes = getMeshTypesFromGLTF(gltf);
53
+ const metadataClasses = getMetadataClassesFromGLTF(gltf);
48
54
  return {
49
55
  meshTopologyTypes,
50
56
  metadataClasses
@@ -56,7 +62,7 @@ export const analyzeTileContent = async (
56
62
  * @param gltfJson - JSON part of GLB content
57
63
  * @returns array of mesh types found
58
64
  */
59
- const getMeshTypesFromGltf = (gltfJson: GLTF): Set<GLTFPrimitiveModeString> => {
65
+ const getMeshTypesFromGLTF = (gltfJson: GLTF): Set<GLTFPrimitiveModeString> => {
60
66
  const result: Set<GLTFPrimitiveModeString> = new Set();
61
67
  for (const mesh of gltfJson.meshes || []) {
62
68
  for (const primitive of mesh.primitives) {
@@ -72,17 +78,32 @@ const getMeshTypesFromGltf = (gltfJson: GLTF): Set<GLTFPrimitiveModeString> => {
72
78
 
73
79
  /**
74
80
  * Get feature metadata classes from glTF
81
+ * The tileset might contain multiple metadata classes provided by EXT_feature_metadata and EXT_structural_metadata extensions.
82
+ * Every class is a set of properties. But I3S can consume only one set of properties.
83
+ * On the pre-process we collect all classes from the tileset in order to show the prompt to select one class for conversion to I3S.
75
84
  * @param gltfJson - JSON part of GLB content
76
85
  * @returns array of classes
77
86
  */
78
- const getMetadataClassesFromGltf = (gltfJson: GLTF): Set<string> => {
87
+ const getMetadataClassesFromGLTF = (gltfJson: GLTF): Set<string> => {
79
88
  const result: Set<string> = new Set();
80
89
 
81
- const classes = (gltfJson.extensions?.[EXT_FEATURE_METADATA] as GLTF_EXT_feature_metadata_GLTF)
82
- ?.schema?.classes;
90
+ // Try to parse from EXT_feature_metadata
91
+ const extFeatureMetadataClasses = (
92
+ gltfJson.extensions?.[EXT_FEATURE_METADATA] as GLTF_EXT_feature_metadata_GLTF
93
+ )?.schema?.classes;
83
94
 
84
- if (classes) {
85
- for (const classKey of Object.keys(classes)) {
95
+ if (extFeatureMetadataClasses) {
96
+ for (const classKey of Object.keys(extFeatureMetadataClasses)) {
97
+ result.add(classKey);
98
+ }
99
+ }
100
+
101
+ // Try to parse from EXT_structural_metadata
102
+ const extStructuralMetadataClasses = (
103
+ gltfJson.extensions?.[EXT_STRUCTURAL_METADATA] as GLTF_EXT_structural_metadata_GLTF
104
+ )?.schema?.classes;
105
+ if (extStructuralMetadataClasses) {
106
+ for (const classKey of Object.keys(extStructuralMetadataClasses)) {
86
107
  result.add(classKey);
87
108
  }
88
109
  }
@@ -656,7 +656,6 @@ export default class I3SConverter {
656
656
  We will append new attributes only in case the property table is updated.
657
657
  According to ver 1.9 (see https://github.com/Esri/i3s-spec/blob/master/docs/1.9/attributeStorageInfo.cmn.md):
658
658
  "The attributeStorageInfo object describes the structure of the binary attribute data resource of a layer, which is the same for every node in the layer."
659
- But the specification of ver 2.1 doesn't have such a requirement ("...the same for every node...")
660
659
  */
661
660
  this._convertPropertyTableToNodeAttributes(propertyTable);
662
661
  }
@@ -1167,7 +1166,6 @@ export default class I3SConverter {
1167
1166
  We will append new attributes only in case the property table is updated.
1168
1167
  According to ver 1.9 (see https://github.com/Esri/i3s-spec/blob/master/docs/1.9/attributeStorageInfo.cmn.md):
1169
1168
  "The attributeStorageInfo object describes the structure of the binary attribute data resource of a layer, which is the same for every node in the layer."
1170
- But the specification of ver 2.1 doesn't have such a requirement ("...the same for every node...")
1171
1169
  */
1172
1170
  const found = this.layers0!.attributeStorageInfo!.find((element) => element.name === key);
1173
1171
  if (!found) {
@@ -187,7 +187,12 @@ export enum GLTFPrimitiveModeString {
187
187
  export type PreprocessData = {
188
188
  /** Mesh topology types used in gltf primitives of the tileset */
189
189
  meshTopologyTypes: Set<GLTFPrimitiveModeString>;
190
- /** Featrue metadata classes found in glTF extensions */
190
+ /**
191
+ * Featrue metadata classes found in glTF extensions
192
+ * The tileset might contain multiple metadata classes provided by EXT_feature_metadata and EXT_structural_metadata extensions.
193
+ * Every class is a set of properties. But I3S can consume only one set of properties.
194
+ * On the pre-process we collect all classes from the tileset in order to show the prompt to select one class for conversion to I3S.
195
+ */
191
196
  metadataClasses: Set<string>;
192
197
  };
193
198