@loaders.gl/tile-converter 3.1.7 → 3.2.0-alpha.2

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 (224) hide show
  1. package/dist/3d-tiles-attributes-worker.d.ts +28 -0
  2. package/dist/3d-tiles-attributes-worker.d.ts.map +1 -0
  3. package/dist/3d-tiles-attributes-worker.js +4 -0
  4. package/dist/3d-tiles-attributes-worker.js.map +7 -0
  5. package/dist/3d-tiles-converter/3d-tiles-converter.d.ts +82 -0
  6. package/dist/3d-tiles-converter/3d-tiles-converter.d.ts.map +1 -0
  7. package/dist/3d-tiles-converter/3d-tiles-converter.js +268 -0
  8. package/dist/3d-tiles-converter/helpers/b3dm-converter.d.ts +84 -0
  9. package/dist/3d-tiles-converter/helpers/b3dm-converter.d.ts.map +1 -0
  10. package/dist/3d-tiles-converter/helpers/b3dm-converter.js +278 -0
  11. package/dist/3d-tiles-converter/helpers/i3s-obb-to-3d-tiles-obb.d.ts +13 -0
  12. package/dist/3d-tiles-converter/helpers/i3s-obb-to-3d-tiles-obb.d.ts.map +1 -0
  13. package/dist/3d-tiles-converter/helpers/i3s-obb-to-3d-tiles-obb.js +23 -0
  14. package/dist/3d-tiles-converter/helpers/texture-atlas.d.ts +9 -0
  15. package/dist/3d-tiles-converter/helpers/texture-atlas.d.ts.map +1 -0
  16. package/dist/3d-tiles-converter/helpers/texture-atlas.js +52 -0
  17. package/dist/3d-tiles-converter/json-templates/tileset.d.ts +15 -0
  18. package/dist/3d-tiles-converter/json-templates/tileset.d.ts.map +1 -0
  19. package/dist/3d-tiles-converter/json-templates/tileset.js +43 -0
  20. package/dist/bundle.d.ts +2 -0
  21. package/dist/bundle.d.ts.map +1 -0
  22. package/dist/bundle.js +5 -0
  23. package/dist/converter.min.js +20 -20
  24. package/dist/deps-installer/deps-installer.d.ts +4 -0
  25. package/dist/deps-installer/deps-installer.d.ts.map +1 -0
  26. package/dist/deps-installer/deps-installer.js +21 -0
  27. package/dist/dist.min.js +1082 -1131
  28. package/dist/es5/3d-tiles-attributes-worker.js +29 -0
  29. package/dist/es5/3d-tiles-attributes-worker.js.map +1 -0
  30. package/dist/es5/3d-tiles-converter/3d-tiles-converter.js +104 -44
  31. package/dist/es5/3d-tiles-converter/3d-tiles-converter.js.map +1 -1
  32. package/dist/es5/3d-tiles-converter/helpers/b3dm-converter.js +34 -43
  33. package/dist/es5/3d-tiles-converter/helpers/b3dm-converter.js.map +1 -1
  34. package/dist/es5/i3s-attributes-worker.js +29 -0
  35. package/dist/es5/i3s-attributes-worker.js.map +1 -0
  36. package/dist/es5/i3s-converter/helpers/coordinate-converter.js +19 -11
  37. package/dist/es5/i3s-converter/helpers/coordinate-converter.js.map +1 -1
  38. package/dist/es5/i3s-converter/helpers/geometry-attributes.js +2 -2
  39. package/dist/es5/i3s-converter/helpers/geometry-attributes.js.map +1 -1
  40. package/dist/es5/i3s-converter/helpers/geometry-converter.js +267 -178
  41. package/dist/es5/i3s-converter/helpers/geometry-converter.js.map +1 -1
  42. package/dist/es5/i3s-converter/helpers/gltf-attributes.js +71 -0
  43. package/dist/es5/i3s-converter/helpers/gltf-attributes.js.map +1 -0
  44. package/dist/es5/i3s-converter/helpers/node-pages.js +43 -52
  45. package/dist/es5/i3s-converter/helpers/node-pages.js.map +1 -1
  46. package/dist/es5/i3s-converter/i3s-converter.js +264 -219
  47. package/dist/es5/i3s-converter/i3s-converter.js.map +1 -1
  48. package/dist/es5/index.js +8 -0
  49. package/dist/es5/index.js.map +1 -1
  50. package/dist/es5/lib/utils/compress-util.js +14 -17
  51. package/dist/es5/lib/utils/compress-util.js.map +1 -1
  52. package/dist/es5/lib/utils/file-utils.js +39 -14
  53. package/dist/es5/lib/utils/file-utils.js.map +1 -1
  54. package/dist/es5/lib/utils/lod-conversion-utils.js.map +1 -1
  55. package/dist/es5/lib/utils/queue.js +61 -0
  56. package/dist/es5/lib/utils/queue.js.map +1 -0
  57. package/dist/es5/lib/utils/statistic-utills.js.map +1 -1
  58. package/dist/es5/lib/utils/write-queue.js +225 -0
  59. package/dist/es5/lib/utils/write-queue.js.map +1 -0
  60. package/dist/es5/pgm-loader.js +1 -1
  61. package/dist/es5/pgm-loader.js.map +1 -1
  62. package/dist/es5/workers/3d-tiles-attributes-worker.js +37 -0
  63. package/dist/es5/workers/3d-tiles-attributes-worker.js.map +1 -0
  64. package/dist/es5/workers/i3s-attributes-worker.js +40 -0
  65. package/dist/es5/workers/i3s-attributes-worker.js.map +1 -0
  66. package/dist/esm/3d-tiles-attributes-worker.js +16 -0
  67. package/dist/esm/3d-tiles-attributes-worker.js.map +1 -0
  68. package/dist/esm/3d-tiles-converter/3d-tiles-converter.js +32 -5
  69. package/dist/esm/3d-tiles-converter/3d-tiles-converter.js.map +1 -1
  70. package/dist/esm/3d-tiles-converter/helpers/b3dm-converter.js +23 -23
  71. package/dist/esm/3d-tiles-converter/helpers/b3dm-converter.js.map +1 -1
  72. package/dist/esm/i3s-attributes-worker.js +16 -0
  73. package/dist/esm/i3s-attributes-worker.js.map +1 -0
  74. package/dist/esm/i3s-converter/helpers/coordinate-converter.js +19 -11
  75. package/dist/esm/i3s-converter/helpers/coordinate-converter.js.map +1 -1
  76. package/dist/esm/i3s-converter/helpers/geometry-attributes.js +2 -2
  77. package/dist/esm/i3s-converter/helpers/geometry-attributes.js.map +1 -1
  78. package/dist/esm/i3s-converter/helpers/geometry-converter.js +117 -58
  79. package/dist/esm/i3s-converter/helpers/geometry-converter.js.map +1 -1
  80. package/dist/esm/i3s-converter/helpers/gltf-attributes.js +54 -0
  81. package/dist/esm/i3s-converter/helpers/gltf-attributes.js.map +1 -0
  82. package/dist/esm/i3s-converter/helpers/node-pages.js +12 -9
  83. package/dist/esm/i3s-converter/helpers/node-pages.js.map +1 -1
  84. package/dist/esm/i3s-converter/i3s-converter.js +115 -28
  85. package/dist/esm/i3s-converter/i3s-converter.js.map +1 -1
  86. package/dist/esm/index.js +1 -0
  87. package/dist/esm/index.js.map +1 -1
  88. package/dist/esm/lib/utils/compress-util.js +6 -8
  89. package/dist/esm/lib/utils/compress-util.js.map +1 -1
  90. package/dist/esm/lib/utils/file-utils.js +11 -1
  91. package/dist/esm/lib/utils/file-utils.js.map +1 -1
  92. package/dist/esm/lib/utils/lod-conversion-utils.js.map +1 -1
  93. package/dist/esm/lib/utils/queue.js +19 -0
  94. package/dist/esm/lib/utils/queue.js.map +1 -0
  95. package/dist/esm/lib/utils/statistic-utills.js.map +1 -1
  96. package/dist/esm/lib/utils/write-queue.js +88 -0
  97. package/dist/esm/lib/utils/write-queue.js.map +1 -0
  98. package/dist/esm/pgm-loader.js +1 -1
  99. package/dist/esm/pgm-loader.js.map +1 -1
  100. package/dist/esm/workers/3d-tiles-attributes-worker.js +5 -0
  101. package/dist/esm/workers/3d-tiles-attributes-worker.js.map +1 -0
  102. package/dist/esm/workers/i3s-attributes-worker.js +4 -0
  103. package/dist/esm/workers/i3s-attributes-worker.js.map +1 -0
  104. package/dist/i3s-attributes-worker.d.ts +33 -0
  105. package/dist/i3s-attributes-worker.d.ts.map +1 -0
  106. package/dist/i3s-attributes-worker.js +10 -0
  107. package/dist/i3s-attributes-worker.js.map +7 -0
  108. package/dist/i3s-converter/helpers/coordinate-converter.d.ts +41 -0
  109. package/dist/i3s-converter/helpers/coordinate-converter.d.ts.map +1 -0
  110. package/dist/i3s-converter/helpers/coordinate-converter.js +122 -0
  111. package/dist/i3s-converter/helpers/create-scene-server-path.d.ts +9 -0
  112. package/dist/i3s-converter/helpers/create-scene-server-path.d.ts.map +1 -0
  113. package/dist/i3s-converter/helpers/create-scene-server-path.js +28 -0
  114. package/dist/i3s-converter/helpers/geometry-attributes.d.ts +8 -0
  115. package/dist/i3s-converter/helpers/geometry-attributes.d.ts.map +1 -0
  116. package/dist/i3s-converter/helpers/geometry-attributes.js +177 -0
  117. package/dist/i3s-converter/helpers/geometry-converter.d.ts +29 -0
  118. package/dist/i3s-converter/helpers/geometry-converter.d.ts.map +1 -0
  119. package/dist/i3s-converter/helpers/geometry-converter.js +901 -0
  120. package/dist/i3s-converter/helpers/gltf-attributes.d.ts +9 -0
  121. package/dist/i3s-converter/helpers/gltf-attributes.d.ts.map +1 -0
  122. package/dist/i3s-converter/helpers/gltf-attributes.js +56 -0
  123. package/dist/i3s-converter/helpers/node-debug.d.ts +8 -0
  124. package/dist/i3s-converter/helpers/node-debug.d.ts.map +1 -0
  125. package/dist/i3s-converter/helpers/node-debug.js +114 -0
  126. package/dist/i3s-converter/helpers/node-pages.d.ts +117 -0
  127. package/dist/i3s-converter/helpers/node-pages.d.ts.map +1 -0
  128. package/dist/i3s-converter/helpers/node-pages.js +208 -0
  129. package/dist/i3s-converter/i3s-converter.d.ts +325 -0
  130. package/dist/i3s-converter/i3s-converter.d.ts.map +1 -0
  131. package/dist/i3s-converter/i3s-converter.js +1056 -0
  132. package/dist/i3s-converter/json-templates/layers.d.ts +95 -0
  133. package/dist/i3s-converter/json-templates/layers.d.ts.map +1 -0
  134. package/dist/i3s-converter/json-templates/layers.js +199 -0
  135. package/dist/i3s-converter/json-templates/metadata.d.ts +22 -0
  136. package/dist/i3s-converter/json-templates/metadata.d.ts.map +1 -0
  137. package/dist/i3s-converter/json-templates/metadata.js +25 -0
  138. package/dist/i3s-converter/json-templates/node.d.ts +61 -0
  139. package/dist/i3s-converter/json-templates/node.d.ts.map +1 -0
  140. package/dist/i3s-converter/json-templates/node.js +89 -0
  141. package/dist/i3s-converter/json-templates/scene-server.d.ts +28 -0
  142. package/dist/i3s-converter/json-templates/scene-server.d.ts.map +1 -0
  143. package/dist/i3s-converter/json-templates/scene-server.js +31 -0
  144. package/dist/i3s-converter/json-templates/shared-resources.d.ts +14 -0
  145. package/dist/i3s-converter/json-templates/shared-resources.d.ts.map +1 -0
  146. package/dist/i3s-converter/json-templates/shared-resources.js +129 -0
  147. package/dist/i3s-converter/json-templates/store.d.ts +95 -0
  148. package/dist/i3s-converter/json-templates/store.d.ts.map +1 -0
  149. package/dist/i3s-converter/json-templates/store.js +103 -0
  150. package/dist/i3s-converter/types.d.ts +114 -0
  151. package/dist/i3s-converter/types.d.ts.map +1 -0
  152. package/dist/i3s-converter/types.js +2 -0
  153. package/dist/i3s-server/app.d.ts +3 -0
  154. package/dist/i3s-server/app.d.ts.map +1 -0
  155. package/dist/i3s-server/app.js +14 -0
  156. package/dist/i3s-server/controllers/index-controller.d.ts +2 -0
  157. package/dist/i3s-server/controllers/index-controller.d.ts.map +1 -0
  158. package/dist/i3s-server/controllers/index-controller.js +23 -0
  159. package/dist/i3s-server/routes/index.d.ts +3 -0
  160. package/dist/i3s-server/routes/index.d.ts.map +1 -0
  161. package/dist/i3s-server/routes/index.js +16 -0
  162. package/dist/index.d.ts +6 -0
  163. package/dist/index.d.ts.map +1 -0
  164. package/dist/index.js +16 -0
  165. package/dist/lib/utils/compress-util.d.ts +45 -0
  166. package/dist/lib/utils/compress-util.d.ts.map +1 -0
  167. package/dist/lib/utils/compress-util.js +257 -0
  168. package/{src → dist}/lib/utils/file-utils.d.ts +6 -14
  169. package/dist/lib/utils/file-utils.d.ts.map +1 -0
  170. package/dist/lib/utils/file-utils.js +81 -0
  171. package/dist/lib/utils/lod-conversion-utils.d.ts +41 -0
  172. package/dist/lib/utils/lod-conversion-utils.d.ts.map +1 -0
  173. package/dist/lib/utils/lod-conversion-utils.js +76 -0
  174. package/dist/lib/utils/queue.d.ts +7 -0
  175. package/dist/lib/utils/queue.d.ts.map +1 -0
  176. package/dist/lib/utils/queue.js +18 -0
  177. package/dist/lib/utils/statistic-utills.d.ts +3 -0
  178. package/dist/lib/utils/statistic-utills.d.ts.map +1 -0
  179. package/dist/lib/utils/statistic-utills.js +64 -0
  180. package/dist/lib/utils/write-queue.d.ts +22 -0
  181. package/dist/lib/utils/write-queue.d.ts.map +1 -0
  182. package/dist/lib/utils/write-queue.js +62 -0
  183. package/dist/pgm-loader.d.ts +6 -0
  184. package/dist/pgm-loader.d.ts.map +1 -0
  185. package/dist/pgm-loader.js +23 -0
  186. package/dist/workers/3d-tiles-attributes-worker.d.ts +2 -0
  187. package/dist/workers/3d-tiles-attributes-worker.d.ts.map +1 -0
  188. package/dist/workers/3d-tiles-attributes-worker.js +9 -0
  189. package/dist/workers/i3s-attributes-worker.d.ts +2 -0
  190. package/dist/workers/i3s-attributes-worker.d.ts.map +1 -0
  191. package/dist/workers/i3s-attributes-worker.js +5 -0
  192. package/package.json +20 -18
  193. package/src/3d-tiles-attributes-worker.ts +43 -0
  194. package/src/3d-tiles-converter/3d-tiles-converter.ts +48 -5
  195. package/src/3d-tiles-converter/helpers/b3dm-converter.ts +21 -18
  196. package/src/i3s-attributes-worker.ts +46 -0
  197. package/src/i3s-converter/helpers/coordinate-converter.ts +29 -24
  198. package/src/i3s-converter/helpers/geometry-attributes.ts +4 -3
  199. package/src/i3s-converter/helpers/{geometry-converter.js → geometry-converter.ts} +421 -175
  200. package/src/i3s-converter/helpers/gltf-attributes.ts +68 -0
  201. package/src/i3s-converter/helpers/node-pages.ts +25 -17
  202. package/src/i3s-converter/i3s-converter.ts +124 -69
  203. package/src/i3s-converter/types.ts +90 -8
  204. package/src/index.ts +1 -0
  205. package/src/lib/utils/{compress-util.js → compress-util.ts} +105 -18
  206. package/src/lib/utils/file-utils.ts +84 -0
  207. package/src/lib/utils/{lod-conversion-utils.js → lod-conversion-utils.ts} +27 -5
  208. package/src/lib/utils/queue.ts +17 -0
  209. package/src/lib/utils/{statistic-utills.js → statistic-utills.ts} +0 -0
  210. package/src/lib/utils/write-queue.ts +75 -0
  211. package/src/workers/3d-tiles-attributes-worker.ts +6 -0
  212. package/src/workers/i3s-attributes-worker.ts +6 -0
  213. package/dist/es5/i3s-converter/helpers/geometry-converter.d.ts +0 -44
  214. package/dist/es5/lib/utils/compress-util.d.ts +0 -53
  215. package/dist/es5/lib/utils/file-utils.d.ts +0 -43
  216. package/dist/es5/lib/utils/lod-conversion-utils.d.ts +0 -32
  217. package/dist/esm/i3s-converter/helpers/geometry-converter.d.ts +0 -44
  218. package/dist/esm/lib/utils/compress-util.d.ts +0 -53
  219. package/dist/esm/lib/utils/file-utils.d.ts +0 -43
  220. package/dist/esm/lib/utils/lod-conversion-utils.d.ts +0 -32
  221. package/src/i3s-converter/helpers/geometry-converter.d.ts +0 -44
  222. package/src/lib/utils/compress-util.d.ts +0 -53
  223. package/src/lib/utils/file-utils.js +0 -38
  224. package/src/lib/utils/lod-conversion-utils.d.ts +0 -32
@@ -0,0 +1,901 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.convertAttributes = void 0;
7
+ const core_1 = require("@math.gl/core");
8
+ const geospatial_1 = require("@math.gl/geospatial");
9
+ const draco_1 = require("@loaders.gl/draco");
10
+ const core_2 = require("@loaders.gl/core");
11
+ const loader_utils_1 = require("@loaders.gl/loader-utils");
12
+ const md5_1 = __importDefault(require("md5"));
13
+ const geometry_attributes_1 = require("./geometry-attributes");
14
+ const coordinate_converter_1 = require("./coordinate-converter");
15
+ const gltf_attributes_1 = require("./gltf-attributes");
16
+ // Spec - https://github.com/Esri/i3s-spec/blob/master/docs/1.7/pbrMetallicRoughness.cmn.md
17
+ const DEFAULT_ROUGHNESS_FACTOR = 1;
18
+ const DEFAULT_METALLIC_FACTOR = 1;
19
+ const VALUES_PER_VERTEX = 3;
20
+ const VALUES_PER_TEX_COORD = 2;
21
+ const VALUES_PER_COLOR_ELEMENT = 4;
22
+ const STRING_TYPE = 'string';
23
+ const SHORT_INT_TYPE = 'Int32';
24
+ const DOUBLE_TYPE = 'Float64';
25
+ const OBJECT_ID_TYPE = 'Oid32';
26
+ /*
27
+ * 'CUSTOM_ATTRIBUTE_2' - Attribute name which includes batch info and used by New York map.
28
+ * _BATCHID - Default attribute name which includes batch info.
29
+ * BATCHID - Legacy attribute name which includes batch info.
30
+ */
31
+ const BATCHED_ID_POSSIBLE_ATTRIBUTE_NAMES = ['CUSTOM_ATTRIBUTE_2', '_BATCHID', 'BATCHID'];
32
+ let scratchVector = new core_1.Vector3();
33
+ /**
34
+ * Convert binary data from b3dm file to i3s resources
35
+ *
36
+ * @param tileContent - 3d tile content
37
+ * @param nodeId - target nodeId. If a few nodes will be created - ids will be nodeId+n where n - index in the resulting array
38
+ * @param featuresHashArray - hash array of features that is needed to not to mix up same features in parent and child nodes
39
+ * @param attributeStorageInfo - attributes metadata from 3DSceneLayer json
40
+ * @param draco - is converter should create draco compressed geometry
41
+ * @param generateBoundingVolumes - is converter should create accurate bounding voulmes from geometry attributes
42
+ * @param geoidHeightModel - model to convert elevation from elipsoidal to geoid
43
+ * @returns Array of node resources to create one or more i3s nodes
44
+ */
45
+ async function convertB3dmToI3sGeometry(tileContent, nodeId, featuresHashArray, attributeStorageInfo, draco, generateBoundingVolumes, geoidHeightModel, workerSource) {
46
+ const useCartesianPositions = generateBoundingVolumes;
47
+ const materialAndTextureList = convertMaterials(tileContent.gltf?.materials);
48
+ const dataForAttributesConversion = (0, gltf_attributes_1.prepareDataForAttributesConversion)(tileContent);
49
+ const convertedAttributesMap = await convertAttributes(dataForAttributesConversion, useCartesianPositions);
50
+ // TODO uncomment it when worker will be published on CDN.
51
+ /*
52
+ const convertedAttributesMap: Map<string, ConvertedAttributes> =
53
+ await transformI3SAttributesOnWorker(dataForAttributesConversion, {
54
+ useCartesianPositions,
55
+ source: workerSource.I3SAttributes
56
+ });
57
+ */
58
+ if (generateBoundingVolumes) {
59
+ _generateBoundingVolumesFromGeometry(convertedAttributesMap, geoidHeightModel);
60
+ }
61
+ if (convertedAttributesMap.has('default')) {
62
+ materialAndTextureList.push({
63
+ material: getDefaultMaterial()
64
+ });
65
+ }
66
+ const result = [];
67
+ let nodesCounter = nodeId;
68
+ let { materials = [] } = tileContent.gltf || { materials: [] };
69
+ if (!materials?.length) {
70
+ materials.push({ id: 'default' });
71
+ }
72
+ for (let i = 0; i < materials.length; i++) {
73
+ const sourceMaterial = materials[i];
74
+ if (!convertedAttributesMap.has(sourceMaterial.id)) {
75
+ continue; // eslint-disable-line no-continue
76
+ }
77
+ const convertedAttributes = convertedAttributesMap.get(sourceMaterial.id);
78
+ if (!convertedAttributes) {
79
+ continue;
80
+ }
81
+ const { material, texture } = materialAndTextureList[i];
82
+ result.push(await _makeNodeResources({
83
+ convertedAttributes,
84
+ material,
85
+ texture,
86
+ tileContent,
87
+ nodeId: nodesCounter,
88
+ featuresHashArray,
89
+ attributeStorageInfo,
90
+ draco,
91
+ workerSource
92
+ }));
93
+ nodesCounter++;
94
+ }
95
+ if (!result.length) {
96
+ return null;
97
+ }
98
+ return result;
99
+ }
100
+ exports.default = convertB3dmToI3sGeometry;
101
+ /**
102
+ * Create bounding volumes based on positions
103
+ * @param convertedAttributesMap - geometry attributes map
104
+ * @param geoidHeightModel - geoid height model to convert elevation from elipsoidal to geoid
105
+ */
106
+ function _generateBoundingVolumesFromGeometry(convertedAttributesMap, geoidHeightModel) {
107
+ for (const attributes of convertedAttributesMap.values()) {
108
+ const boundingVolumes = (0, coordinate_converter_1.createBoundingVolumesFromGeometry)(attributes.positions, geoidHeightModel);
109
+ attributes.boundingVolumes = boundingVolumes;
110
+ const cartographicOrigin = boundingVolumes.obb.center;
111
+ for (let index = 0; index < attributes.positions.length; index += VALUES_PER_VERTEX) {
112
+ const vertex = attributes.positions.subarray(index, index + VALUES_PER_VERTEX);
113
+ geospatial_1.Ellipsoid.WGS84.cartesianToCartographic(Array.from(vertex), scratchVector);
114
+ scratchVector[2] =
115
+ scratchVector[2] - geoidHeightModel.getHeight(scratchVector[1], scratchVector[0]);
116
+ scratchVector = scratchVector.subtract(cartographicOrigin);
117
+ attributes.positions.set(scratchVector, index);
118
+ }
119
+ }
120
+ }
121
+ /**
122
+ *
123
+ * @param params
124
+ * @param params.convertedAttributes - Converted geometry attributes
125
+ * @param params.material - I3S PBR-like material definition
126
+ * @param params.texture - texture content
127
+ * @param params.tileContent - B3DM decoded content
128
+ * @param params.nodeId - new node ID
129
+ * @param params.featuresHashArray - hash array of features that is needed to not to mix up same features in parent and child nodes
130
+ * @param params.attributesStorageInfo - attributes metadata from 3DSceneLayer json
131
+ * @param params.draco - is converter should create draco compressed geometry
132
+ * @returns Array of I3S node resources
133
+ */
134
+ async function _makeNodeResources({ convertedAttributes, material, texture, tileContent, nodeId, featuresHashArray, attributeStorageInfo, draco, workerSource }) {
135
+ const boundingVolumes = convertedAttributes.boundingVolumes;
136
+ const vertexCount = convertedAttributes.positions.length / VALUES_PER_VERTEX;
137
+ const { faceRange, featureIds, positions, normals, colors, texCoords, featureCount } = (0, geometry_attributes_1.generateAttributes)(convertedAttributes);
138
+ if (tileContent.batchTableJson) {
139
+ makeFeatureIdsUnique(featureIds, convertedAttributes.featureIndices, featuresHashArray, tileContent.batchTableJson);
140
+ }
141
+ const header = new Uint32Array(2);
142
+ const typedFeatureIds = generateBigUint64Array(featureIds);
143
+ header.set([vertexCount, featureCount], 0);
144
+ const fileBuffer = new Uint8Array((0, loader_utils_1.concatenateArrayBuffers)(header.buffer, positions.buffer, normals.buffer, texture ? texCoords.buffer : new ArrayBuffer(0), colors.buffer, typedFeatureIds.buffer, faceRange.buffer));
145
+ const compressedGeometry = draco
146
+ ? generateCompressedGeometry(vertexCount, convertedAttributes, {
147
+ positions,
148
+ normals,
149
+ texCoords: texture ? texCoords : new Float32Array(0),
150
+ colors,
151
+ featureIds,
152
+ faceRange
153
+ }, workerSource.draco)
154
+ : null;
155
+ const attributes = convertBatchTableToAttributeBuffers(tileContent.batchTableJson, featureIds, attributeStorageInfo);
156
+ return {
157
+ geometry: fileBuffer,
158
+ compressedGeometry,
159
+ texture,
160
+ sharedResources: getSharedResources(tileContent.gltf?.materials || [], nodeId),
161
+ meshMaterial: material,
162
+ vertexCount,
163
+ attributes,
164
+ featureCount,
165
+ boundingVolumes
166
+ };
167
+ }
168
+ /**
169
+ * Convert attributes from the gltf nodes tree to i3s plain geometry
170
+ * @param tileContent - 3d tile content
171
+ * @param useCartesianPositions - convert positions to absolute cartesian coordinates instead of cartographic offsets.
172
+ * Cartesian coordinates will be required for creating bounding voulmest from geometry positions
173
+ * @returns map of converted geometry attributes
174
+ */
175
+ async function convertAttributes(attributesData, useCartesianPositions) {
176
+ const { gltfMaterials, nodes, cartographicOrigin, cartesianModelMatrix } = attributesData;
177
+ const attributesMap = new Map();
178
+ for (const material of gltfMaterials || [{ id: 'default' }]) {
179
+ attributesMap.set(material.id, {
180
+ positions: new Float32Array(0),
181
+ normals: new Float32Array(0),
182
+ texCoords: new Float32Array(0),
183
+ colors: new Uint8Array(0),
184
+ featureIndicesGroups: [],
185
+ featureIndices: [],
186
+ boundingVolumes: null
187
+ });
188
+ }
189
+ convertNodes(nodes, cartographicOrigin, cartesianModelMatrix, attributesMap, useCartesianPositions);
190
+ for (const attrKey of attributesMap.keys()) {
191
+ const attributes = attributesMap.get(attrKey);
192
+ if (!attributes) {
193
+ continue;
194
+ }
195
+ if (attributes.positions.length === 0) {
196
+ attributesMap.delete(attrKey);
197
+ continue; // eslint-disable-line no-continue
198
+ }
199
+ if (attributes.featureIndicesGroups) {
200
+ attributes.featureIndices = attributes.featureIndicesGroups.reduce((acc, value) => acc.concat(value));
201
+ delete attributes.featureIndicesGroups;
202
+ }
203
+ }
204
+ return attributesMap;
205
+ }
206
+ exports.convertAttributes = convertAttributes;
207
+ /**
208
+ * Gltf has hierarchical structure of nodes. This function converts nodes starting from those which are in gltf scene object.
209
+ * The goal is applying tranformation matrix for all children. Functions "convertNodes" and "convertNode" work together recursively.
210
+ * @param nodes - gltf nodes array
211
+ * @param tileContent - 3d tile content
212
+ * @param attributesMap - for recursive concatenation of attributes
213
+ * @param useCartesianPositions - convert positions to absolute cartesian coordinates instead of cartographic offsets.
214
+ * Cartesian coordinates will be required for creating bounding voulmest from geometry positions
215
+ * @param matrix - transformation matrix - cumulative transformation matrix formed from all parent node matrices
216
+ * @returns {void}
217
+ */
218
+ function convertNodes(nodes, cartographicOrigin, cartesianModelMatrix, attributesMap, useCartesianPositions, matrix = new core_1.Matrix4([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1])) {
219
+ if (nodes) {
220
+ for (const node of nodes) {
221
+ convertNode(node, cartographicOrigin, cartesianModelMatrix, attributesMap, useCartesianPositions, matrix);
222
+ }
223
+ }
224
+ }
225
+ /**
226
+ * Generate transformation matrix for node
227
+ * Aapply all gltf transformations to initial transformation matrix.
228
+ * @param node
229
+ * @param matrix
230
+ */
231
+ function getCompositeTransformationMatrix(node, matrix) {
232
+ let transformationMatrix = matrix;
233
+ const { matrix: nodeMatrix, rotation, scale, translation } = node;
234
+ if (nodeMatrix) {
235
+ transformationMatrix = matrix.multiplyRight(nodeMatrix);
236
+ }
237
+ if (rotation) {
238
+ transformationMatrix = transformationMatrix.rotateXYZ(rotation);
239
+ }
240
+ if (scale) {
241
+ transformationMatrix = transformationMatrix.scale(scale);
242
+ }
243
+ if (translation) {
244
+ transformationMatrix = transformationMatrix.translate(translation);
245
+ }
246
+ return transformationMatrix;
247
+ }
248
+ /**
249
+ * Convert all primitives of node and all children nodes
250
+ * @param node - gltf node
251
+ * @param {Object} tileContent - 3d tile content
252
+ * @param {Map} attributesMap Map<{positions: Float32Array, normals: Float32Array, texCoords: Float32Array, colors: Uint8Array, featureIndices: Array}> - for recursive concatenation of
253
+ * attributes
254
+ * @param useCartesianPositions - convert positions to absolute cartesian coordinates instead of cartographic offsets.
255
+ * Cartesian coordinates will be required for creating bounding voulmest from geometry positions
256
+ * @param {Matrix4} matrix - transformation matrix - cumulative transformation matrix formed from all parent node matrices
257
+ */
258
+ function convertNode(node, cartographicOrigin, cartesianModelMatrix, attributesMap, useCartesianPositions, matrix = new core_1.Matrix4([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1])) {
259
+ const transformationMatrix = getCompositeTransformationMatrix(node, matrix);
260
+ const mesh = node.mesh;
261
+ if (mesh) {
262
+ convertMesh(mesh, cartographicOrigin, cartesianModelMatrix, attributesMap, useCartesianPositions, transformationMatrix);
263
+ }
264
+ convertNodes(node.children || [], cartographicOrigin, cartesianModelMatrix, attributesMap, useCartesianPositions, transformationMatrix);
265
+ }
266
+ /**
267
+ * Convert all primitives of node and all children nodes
268
+ * @param mesh - gltf node
269
+ * @param content - 3d tile content
270
+ * @param useCartesianPositions - convert positions to absolute cartesian coordinates instead of cartographic offsets.
271
+ * Cartesian coordinates will be required for creating bounding voulmest from geometry positions
272
+ * @param attributesMap Map<{positions: Float32Array, normals: Float32Array, texCoords: Float32Array, colors: Uint8Array, featureIndices: Array}> - for recursive concatenation of
273
+ * attributes
274
+
275
+ * @param {Matrix4} matrix - transformation matrix - cumulative transformation matrix formed from all parent node matrices
276
+ */
277
+ function convertMesh(mesh, cartographicOrigin, cartesianModelMatrix, attributesMap, useCartesianPositions = false, matrix = new core_1.Matrix4([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1])) {
278
+ for (const primitive of mesh.primitives) {
279
+ let outputAttributes = null;
280
+ if (primitive.material) {
281
+ outputAttributes = attributesMap.get(primitive.material.id);
282
+ }
283
+ else if (attributesMap.has('default')) {
284
+ outputAttributes = attributesMap.get('default');
285
+ }
286
+ (0, core_2.assert)(outputAttributes !== null, 'Primitive - material mapping failed');
287
+ const attributes = primitive.attributes;
288
+ if (!outputAttributes) {
289
+ continue;
290
+ }
291
+ outputAttributes.positions = (0, loader_utils_1.concatenateTypedArrays)(outputAttributes.positions, transformVertexArray({
292
+ vertices: attributes.POSITION.value,
293
+ cartographicOrigin,
294
+ cartesianModelMatrix,
295
+ nodeMatrix: matrix,
296
+ indices: primitive.indices?.value,
297
+ attributeSpecificTransformation: transformVertexPositions,
298
+ useCartesianPositions
299
+ }));
300
+ outputAttributes.normals = (0, loader_utils_1.concatenateTypedArrays)(outputAttributes.normals, transformVertexArray({
301
+ vertices: attributes.NORMAL && attributes.NORMAL.value,
302
+ cartographicOrigin,
303
+ cartesianModelMatrix,
304
+ nodeMatrix: matrix,
305
+ indices: primitive.indices?.value,
306
+ attributeSpecificTransformation: transformVertexNormals,
307
+ useCartesianPositions: false
308
+ }));
309
+ outputAttributes.texCoords = (0, loader_utils_1.concatenateTypedArrays)(outputAttributes.texCoords, flattenTexCoords(attributes.TEXCOORD_0 && attributes.TEXCOORD_0.value, primitive.indices?.value));
310
+ outputAttributes.colors = (0, loader_utils_1.concatenateTypedArrays)(outputAttributes.colors, flattenColors(attributes.COLOR_0, primitive.indices?.value));
311
+ outputAttributes.featureIndicesGroups = outputAttributes.featureIndicesGroups || [];
312
+ outputAttributes.featureIndicesGroups.push(flattenBatchIds(getBatchIdsByAttributeName(attributes), primitive.indices?.value));
313
+ }
314
+ }
315
+ /**
316
+ * Convert vertices attributes (POSITIONS or NORMALS) to i3s compatible format
317
+ * @param args
318
+ * @param args.vertices - gltf primitive POSITION or NORMAL attribute
319
+ * @param args.cartographicOrigin - cartographic origin coordinates
320
+ * @param args.cartesianModelMatrix - a cartesian model matrix to transform coordnates from cartesian to cartographic format
321
+ * @param args.nodeMatrix - a gltf node transformation matrix - cumulative transformation matrix formed from all parent node matrices
322
+ * @param args.indices - gltf primitive indices
323
+ * @param args.attributeSpecificTransformation - function to do attribute - specific transformations
324
+ * @param args.useCartesianPositions - use coordinates as it is.
325
+ * @returns {Float32Array}
326
+ */
327
+ function transformVertexArray(args) {
328
+ const { vertices, indices, attributeSpecificTransformation } = args;
329
+ const newVertices = new Float32Array(indices.length * VALUES_PER_VERTEX);
330
+ if (!vertices) {
331
+ return newVertices;
332
+ }
333
+ for (let i = 0; i < indices.length; i++) {
334
+ const coordIndex = indices[i] * VALUES_PER_VERTEX;
335
+ const vertex = vertices.subarray(coordIndex, coordIndex + VALUES_PER_VERTEX);
336
+ let vertexVector = new core_1.Vector3(Array.from(vertex));
337
+ vertexVector = attributeSpecificTransformation(vertexVector, args);
338
+ newVertices[i * VALUES_PER_VERTEX] = vertexVector.x;
339
+ newVertices[i * VALUES_PER_VERTEX + 1] = vertexVector.y;
340
+ newVertices[i * VALUES_PER_VERTEX + 2] = vertexVector.z;
341
+ }
342
+ return newVertices;
343
+ }
344
+ /**
345
+ * Trasform positions vector with the attribute specific transformations
346
+ * @param vertexVector - source positions vector to transform
347
+ * @param calleeArgs
348
+ * @param calleeArgs.cartesianModelMatrix - a cartesian model matrix to transform coordnates from cartesian to cartographic format
349
+ * @param calleeArgs.cartographicOrigin - cartographic origin coordinates
350
+ * @param calleeArgs.nodeMatrix - a gltf node transformation matrix - cumulative transformation matrix formed from all parent node matrices
351
+ * @param calleeArgs.useCartesianPositions - use coordinates as it is.
352
+ * @returns transformed positions vector
353
+ */
354
+ function transformVertexPositions(vertexVector, calleeArgs) {
355
+ const { cartesianModelMatrix, cartographicOrigin, nodeMatrix, useCartesianPositions } = calleeArgs;
356
+ if (nodeMatrix) {
357
+ vertexVector = vertexVector.transform(nodeMatrix);
358
+ }
359
+ vertexVector = vertexVector.transform(cartesianModelMatrix);
360
+ if (useCartesianPositions) {
361
+ return vertexVector;
362
+ }
363
+ geospatial_1.Ellipsoid.WGS84.cartesianToCartographic([vertexVector[0], vertexVector[1], vertexVector[2]], vertexVector);
364
+ vertexVector = vertexVector.subtract(cartographicOrigin);
365
+ return vertexVector;
366
+ }
367
+ /**
368
+ * Trasform normals vector with the attribute specific transformations
369
+ * @param vertexVector - source normals vector to transform
370
+ * @param calleeArgs
371
+ * @param calleeArgs.cartesianModelMatrix - a cartesian model matrix to transform coordnates from cartesian to cartographic format
372
+ * @param calleeArgs.nodeMatrix - a gltf node transformation matrix - cumulative transformation matrix formed from all parent node matrices
373
+ * @returns transformed normals vector
374
+ */
375
+ function transformVertexNormals(vertexVector, calleeArgs) {
376
+ const { cartesianModelMatrix, nodeMatrix } = calleeArgs;
377
+ if (nodeMatrix) {
378
+ vertexVector = vertexVector.transformAsVector(nodeMatrix);
379
+ }
380
+ vertexVector = vertexVector.transformAsVector(cartesianModelMatrix);
381
+ return vertexVector;
382
+ }
383
+ /**
384
+ * Convert uv0 (texture coordinates) from coords based on indices to plain arrays, compatible with i3s
385
+ * @param texCoords - gltf primitive TEXCOORD_0 attribute
386
+ * @param indices - gltf primitive indices
387
+ * @returns flattened texture coordinates
388
+ */
389
+ function flattenTexCoords(texCoords, indices) {
390
+ const newTexCoords = new Float32Array(indices.length * VALUES_PER_TEX_COORD);
391
+ if (!texCoords) {
392
+ // We need dummy UV0s because it is required in 1.6
393
+ // https://github.com/Esri/i3s-spec/blob/master/docs/1.6/vertexAttribute.cmn.md
394
+ newTexCoords.fill(1);
395
+ return newTexCoords;
396
+ }
397
+ for (let i = 0; i < indices.length; i++) {
398
+ const coordIndex = indices[i] * VALUES_PER_TEX_COORD;
399
+ const texCoord = texCoords.subarray(coordIndex, coordIndex + VALUES_PER_TEX_COORD);
400
+ newTexCoords[i * VALUES_PER_TEX_COORD] = texCoord[0];
401
+ newTexCoords[i * VALUES_PER_TEX_COORD + 1] = texCoord[1];
402
+ }
403
+ return newTexCoords;
404
+ }
405
+ /**
406
+ * Convert color from COLOR_0 based on indices to plain arrays, compatible with i3s
407
+ * @param colorsAttribute - gltf primitive COLOR_0 attribute
408
+ * @param indices - gltf primitive indices
409
+ * @returns flattened colors attribute
410
+ */
411
+ function flattenColors(colorsAttribute, indices) {
412
+ const components = colorsAttribute?.components || VALUES_PER_COLOR_ELEMENT;
413
+ const newColors = new Uint8Array(indices.length * components);
414
+ if (!colorsAttribute) {
415
+ // Vertex color multiplies by material color so it must be normalized 1 by default
416
+ newColors.fill(255);
417
+ return newColors;
418
+ }
419
+ const colors = colorsAttribute.value;
420
+ for (let i = 0; i < indices.length; i++) {
421
+ const colorIndex = indices[i] * components;
422
+ const color = colors.subarray(colorIndex, colorIndex + components);
423
+ const colorUint8 = new Uint8Array(components);
424
+ for (let j = 0; j < color.length; j++) {
425
+ colorUint8[j] = color[j] * 255;
426
+ }
427
+ newColors.set(colorUint8, i * components);
428
+ }
429
+ return newColors;
430
+ }
431
+ /**
432
+ * Flatten batchedIds list based on indices to right ordered array, compatible with i3s
433
+ * @param batchedIds - gltf primitive
434
+ * @param indices - gltf primitive indices
435
+ * @returns flattened batch ids
436
+ */
437
+ function flattenBatchIds(batchedIds, indices) {
438
+ if (!batchedIds.length || !indices.length) {
439
+ return [];
440
+ }
441
+ const newBatchIds = [];
442
+ for (let i = 0; i < indices.length; i++) {
443
+ const coordIndex = indices[i];
444
+ newBatchIds.push(batchedIds[coordIndex]);
445
+ }
446
+ return newBatchIds;
447
+ }
448
+ /**
449
+ * Return batchIds based on possible attribute names for different kind of maps.
450
+ * @param attributes - the gltf primitive attributes
451
+ * @returns batch ids attribute
452
+ */
453
+ function getBatchIdsByAttributeName(attributes) {
454
+ let batchIds = [];
455
+ for (let index = 0; index < BATCHED_ID_POSSIBLE_ATTRIBUTE_NAMES.length; index++) {
456
+ const possibleBatchIdAttributeName = BATCHED_ID_POSSIBLE_ATTRIBUTE_NAMES[index];
457
+ if (attributes[possibleBatchIdAttributeName] &&
458
+ attributes[possibleBatchIdAttributeName].value) {
459
+ batchIds = attributes[possibleBatchIdAttributeName].value;
460
+ break;
461
+ }
462
+ }
463
+ return batchIds;
464
+ }
465
+ /**
466
+ * Convert GLTF material to I3S material definitions and textures
467
+ * @param sourceMaterials Source GLTF materials
468
+ * @returns Array of Couples I3SMaterialDefinition + texture content
469
+ */
470
+ function convertMaterials(sourceMaterials = []) {
471
+ const result = [];
472
+ for (const sourceMaterial of sourceMaterials) {
473
+ result.push(convertMaterial(sourceMaterial));
474
+ }
475
+ return result;
476
+ }
477
+ /**
478
+ * Convert texture and material from gltf 2.0 material object
479
+ * @param sourceMaterial - material object
480
+ * @returns I3S material definition and texture
481
+ */
482
+ function convertMaterial(sourceMaterial) {
483
+ const material = {
484
+ doubleSided: sourceMaterial.doubleSided,
485
+ emissiveFactor: sourceMaterial.emissiveFactor?.map((c) => Math.round(c * 255)),
486
+ // It is in upper case in GLTF: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#alpha-coverage
487
+ // But it is in lower case in I3S: https://github.com/Esri/i3s-spec/blob/master/docs/1.7/materialDefinitions.cmn.md
488
+ alphaMode: convertAlphaMode(sourceMaterial.alphaMode),
489
+ pbrMetallicRoughness: {
490
+ roughnessFactor: sourceMaterial?.pbrMetallicRoughness?.roughnessFactor || DEFAULT_ROUGHNESS_FACTOR,
491
+ metallicFactor: sourceMaterial?.pbrMetallicRoughness?.metallicFactor || DEFAULT_METALLIC_FACTOR
492
+ }
493
+ };
494
+ let texture;
495
+ if (sourceMaterial?.pbrMetallicRoughness?.baseColorTexture) {
496
+ texture = sourceMaterial.pbrMetallicRoughness.baseColorTexture.texture.source;
497
+ material.pbrMetallicRoughness.baseColorTexture = {
498
+ textureSetDefinitionId: 0
499
+ };
500
+ }
501
+ else if (sourceMaterial.emissiveTexture) {
502
+ texture = sourceMaterial.emissiveTexture.texture.source;
503
+ // ArcGIS webscene doesn't show emissiveTexture but shows baseColorTexture
504
+ material.pbrMetallicRoughness.baseColorTexture = {
505
+ textureSetDefinitionId: 0
506
+ };
507
+ }
508
+ if (!texture) {
509
+ // Should use default baseColorFactor if it is not present in source material
510
+ // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#reference-pbrmetallicroughness
511
+ const baseColorFactor = sourceMaterial?.pbrMetallicRoughness?.baseColorFactor;
512
+ material.pbrMetallicRoughness.baseColorFactor =
513
+ (baseColorFactor && baseColorFactor.map((c) => Math.round(c * 255))) || undefined;
514
+ }
515
+ return { material, texture };
516
+ }
517
+ /**
518
+ * Converts from `alphaMode` material property from GLTF to I3S format
519
+ * @param gltfAlphaMode Gltf material `alphaMode` property
520
+ * @returns I3SMaterialDefinition.alphaMode property
521
+ */
522
+ function convertAlphaMode(gltfAlphaMode) {
523
+ switch (gltfAlphaMode) {
524
+ case 'OPAQUE':
525
+ return 'opaque';
526
+ case 'MASK':
527
+ return 'mask';
528
+ case 'BLEND':
529
+ return 'blend';
530
+ default:
531
+ return 'opaque';
532
+ }
533
+ }
534
+ /**
535
+ * Form default I3SMaterialDefinition
536
+ * @returns I3S material definition
537
+ */
538
+ function getDefaultMaterial() {
539
+ return {
540
+ alphaMode: 'opaque',
541
+ pbrMetallicRoughness: {
542
+ metallicFactor: 1,
543
+ roughnessFactor: 1
544
+ }
545
+ };
546
+ }
547
+ /**
548
+ * Form "sharedResources" from gltf materials array
549
+ * @param gltfMaterials - GLTF materials array
550
+ * @param nodeId - I3S node ID
551
+ * @returns {materialDefinitionInfos: Object[], textureDefinitionInfos: Object[]} -
552
+ * 2 arrays in format of i3s sharedResources data https://github.com/Esri/i3s-spec/blob/master/docs/1.7/sharedResource.cmn.md
553
+ */
554
+ function getSharedResources(gltfMaterials, nodeId) {
555
+ const i3sResources = {};
556
+ if (!gltfMaterials || !gltfMaterials.length) {
557
+ return i3sResources;
558
+ }
559
+ i3sResources.materialDefinitionInfos = [];
560
+ for (const gltfMaterial of gltfMaterials) {
561
+ const { materialDefinitionInfo, textureDefinitionInfo } = convertGLTFMaterialToI3sSharedResources(gltfMaterial, nodeId);
562
+ i3sResources.materialDefinitionInfos.push(materialDefinitionInfo);
563
+ if (textureDefinitionInfo) {
564
+ i3sResources.textureDefinitionInfos = i3sResources.textureDefinitionInfos || [];
565
+ i3sResources.textureDefinitionInfos.push(textureDefinitionInfo);
566
+ }
567
+ }
568
+ return i3sResources;
569
+ }
570
+ /**
571
+ * Convert gltf material into I3S sharedResources data
572
+ * @param gltfMaterial - gltf material data
573
+ * @param nodeId - I3S node ID
574
+ * @returns - Couple {materialDefinitionInfo, textureDefinitionInfo} extracted from gltf material data
575
+ */
576
+ function convertGLTFMaterialToI3sSharedResources(gltfMaterial, nodeId) {
577
+ const texture = gltfMaterial?.pbrMetallicRoughness?.baseColorTexture || gltfMaterial.emissiveTexture;
578
+ let textureDefinitionInfo = null;
579
+ if (texture) {
580
+ textureDefinitionInfo = extractSharedResourcesTextureInfo(texture.texture, nodeId);
581
+ }
582
+ const { baseColorFactor, metallicFactor } = gltfMaterial?.pbrMetallicRoughness || {};
583
+ let colorFactor = baseColorFactor;
584
+ // If alpha channel is 0 try to get emissive factor from gltf material.
585
+ if ((!baseColorFactor || baseColorFactor[3] === 0) && gltfMaterial.emissiveFactor) {
586
+ colorFactor = gltfMaterial.emissiveFactor;
587
+ colorFactor[3] = colorFactor[3] || 1;
588
+ }
589
+ return {
590
+ materialDefinitionInfo: extractSharedResourcesMaterialInfo(colorFactor || [1, 1, 1, 1], metallicFactor),
591
+ textureDefinitionInfo
592
+ };
593
+ }
594
+ /**
595
+ * Form "materialDefinition" which is part of "sharedResouces"
596
+ * https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#materials
597
+ * See formulas in appendix "Appendix B: BRDF Implementation":
598
+ * const dielectricSpecular = rgb(0.04, 0.04, 0.04)
599
+ * const black = rgb(0, 0, 0)
600
+ * cdiff = lerp(baseColor.rgb * (1 - dielectricSpecular.r), black, metallic)
601
+ * F0 = lerp(dieletricSpecular, baseColor.rgb, metallic)
602
+ *
603
+ * Assumption: F0 - specular in i3s ("specular reflection" <-> "reflectance value at normal incidence")
604
+ * cdiff - diffuse in i3s ("Diffuse color" <-> "'c' diffuse" (c means color?))
605
+ * @param baseColorFactor - RGBA color in 0..1 format
606
+ * @param metallicFactor - "metallicFactor" attribute of gltf material object
607
+ * @returns material definition info for I3S shared resource
608
+ */
609
+ function extractSharedResourcesMaterialInfo(baseColorFactor, metallicFactor = 1) {
610
+ const matDielectricColorComponent = 0.04 / 255; // Color from rgb (255) to 0..1 resolution
611
+ // All color resolutions are 0..1
612
+ const black = new core_1.Vector4(0, 0, 0, 1);
613
+ const unitVector = new core_1.Vector4(1, 1, 1, 1);
614
+ const dielectricSpecular = new core_1.Vector4(matDielectricColorComponent, matDielectricColorComponent, matDielectricColorComponent, 0);
615
+ const baseColorVector = new core_1.Vector4(baseColorFactor);
616
+ // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#metallic-roughness-material
617
+ // Formulas for Cdiff & F0
618
+ const firstOperand = unitVector.subtract(dielectricSpecular).multiply(baseColorVector);
619
+ const diffuse = firstOperand.lerp(firstOperand, black, metallicFactor);
620
+ dielectricSpecular[3] = 1;
621
+ const specular = dielectricSpecular.lerp(dielectricSpecular, baseColorVector, metallicFactor);
622
+ return {
623
+ params: {
624
+ diffuse: diffuse.toArray(),
625
+ specular: specular.toArray(),
626
+ renderMode: 'solid'
627
+ }
628
+ };
629
+ }
630
+ /**
631
+ * Form "textureDefinition" which is part of "sharedResouces"
632
+ * @param texture - texture image info
633
+ * @param nodeId - I3S node ID
634
+ * @returns texture definition infor for shared resource
635
+ */
636
+ function extractSharedResourcesTextureInfo(texture, nodeId) {
637
+ return {
638
+ encoding: texture?.source?.mimeType ? [texture.source.mimeType] : undefined,
639
+ images: [
640
+ {
641
+ // 'i3s' has just size which is width of the image. Images are supposed to be square.
642
+ // https://github.com/Esri/i3s-spec/blob/master/docs/1.7/image.cmn.md
643
+ id: generateImageId(texture, nodeId),
644
+ size: texture.source?.image.width,
645
+ length: [texture.source?.image.data.length]
646
+ }
647
+ ]
648
+ };
649
+ }
650
+ /**
651
+ * Formula for counting imageId:
652
+ * https://github.com/Esri/i3s-spec/blob/0a6366a9249b831db8436c322f8d27521e86cf07/format/Indexed%203d%20Scene%20Layer%20Format%20Specification.md#generating-image-ids
653
+ * @param texture - texture image info
654
+ * @param nodeId - I3S node ID
655
+ * @returns calculate image ID according to the spec
656
+ */
657
+ function generateImageId(texture, nodeId) {
658
+ const { width, height } = texture.source?.image;
659
+ const levelCountOfTexture = 1;
660
+ const indexOfLevel = 0;
661
+ const indexOfTextureInStore = nodeId + 1;
662
+ const zerosCount = 32 - indexOfTextureInStore.toString(2).length;
663
+ const rightHalf = '0'.repeat(zerosCount).concat(indexOfTextureInStore.toString(2));
664
+ const shiftedLevelCountOfTexture = levelCountOfTexture << 28;
665
+ const shiftedIndexOfLevel = indexOfLevel << 24;
666
+ const shiftedWidth = (width - 1) << 12;
667
+ const shiftedHeight = (height - 1) << 0;
668
+ const leftHalf = shiftedLevelCountOfTexture + shiftedIndexOfLevel + shiftedWidth + shiftedHeight;
669
+ const imageId = BigInt(`0b${leftHalf.toString(2)}${rightHalf}`);
670
+ return imageId.toString();
671
+ }
672
+ /**
673
+ * Make all feature ids unique through all nodes in layout.
674
+ * @param featureIds
675
+ * @param featureIndices
676
+ * @param featuresHashArray
677
+ * @param batchTable
678
+ * @returns {void}
679
+ */
680
+ function makeFeatureIdsUnique(featureIds, featureIndices, featuresHashArray, batchTable) {
681
+ const replaceMap = getFeaturesReplaceMap(featureIds, batchTable, featuresHashArray);
682
+ replaceIndicesByUnique(featureIndices, replaceMap);
683
+ replaceIndicesByUnique(featureIds, replaceMap);
684
+ }
685
+ /**
686
+ * Generate replace map to make featureIds unique.
687
+ * @param {Array} featureIds
688
+ * @param {Object} batchTable
689
+ * @param {Array} featuresHashArray
690
+ * @returns {Object}
691
+ */
692
+ function getFeaturesReplaceMap(featureIds, batchTable, featuresHashArray) {
693
+ const featureMap = {};
694
+ for (let index = 0; index < featureIds.length; index++) {
695
+ const oldFeatureId = featureIds[index];
696
+ const uniqueFeatureId = getOrCreateUniqueFeatureId(index, batchTable, featuresHashArray);
697
+ featureMap[oldFeatureId.toString()] = uniqueFeatureId;
698
+ }
699
+ return featureMap;
700
+ }
701
+ /**
702
+ * Generates string for unique batch id creation.
703
+ * @param {Object} batchTable
704
+ * @param {Number} index
705
+ * @returns {String}
706
+ */
707
+ function generateStringFromBatchTableByIndex(batchTable, index) {
708
+ let str = '';
709
+ for (const key in batchTable) {
710
+ str += batchTable[key][index];
711
+ }
712
+ return str;
713
+ }
714
+ /**
715
+ * Return already exited featureId or creates and returns new to support unique feature ids throw nodes.
716
+ * @param {Number} index
717
+ * @param {Object} batchTable
718
+ * @param {Array} featuresHashArray
719
+ * @returns {Number}
720
+ */
721
+ function getOrCreateUniqueFeatureId(index, batchTable, featuresHashArray) {
722
+ const batchTableStr = generateStringFromBatchTableByIndex(batchTable, index);
723
+ const hash = (0, md5_1.default)(batchTableStr);
724
+ if (featuresHashArray.includes(hash)) {
725
+ return featuresHashArray.indexOf(hash);
726
+ }
727
+ return featuresHashArray.push(hash) - 1;
728
+ }
729
+ /**
730
+ * Do replacement of indices for making them unique through all nodes.
731
+ * @param {Array} indicesArray
732
+ * @param {Object} featureMap
733
+ * @returns {void}
734
+ */
735
+ function replaceIndicesByUnique(indicesArray, featureMap) {
736
+ for (let index = 0; index < indicesArray.length; index++) {
737
+ indicesArray[index] = featureMap[indicesArray[index]];
738
+ }
739
+ }
740
+ /**
741
+ * Convert batch table data to attribute buffers.
742
+ * @param {Object} batchTable - table with metadata for particular feature.
743
+ * @param {Array} featureIds
744
+ * @param {Array} attributeStorageInfo
745
+ * @returns {Array} - Array of file buffers.
746
+ */
747
+ function convertBatchTableToAttributeBuffers(batchTable, featureIds, attributeStorageInfo) {
748
+ const attributeBuffers = [];
749
+ if (batchTable) {
750
+ const batchTableWithFeatureIds = {
751
+ OBJECTID: featureIds,
752
+ ...batchTable
753
+ };
754
+ for (const key in batchTableWithFeatureIds) {
755
+ const type = getAttributeType(key, attributeStorageInfo);
756
+ let attributeBuffer = null;
757
+ switch (type) {
758
+ case OBJECT_ID_TYPE:
759
+ case SHORT_INT_TYPE:
760
+ attributeBuffer = generateShortIntegerAttributeBuffer(batchTableWithFeatureIds[key]);
761
+ break;
762
+ case DOUBLE_TYPE:
763
+ attributeBuffer = generateDoubleAttributeBuffer(batchTableWithFeatureIds[key]);
764
+ break;
765
+ case STRING_TYPE:
766
+ attributeBuffer = generateStringAttributeBuffer(batchTableWithFeatureIds[key]);
767
+ break;
768
+ default:
769
+ attributeBuffer = generateStringAttributeBuffer(batchTableWithFeatureIds[key]);
770
+ }
771
+ if (attributeBuffer) {
772
+ attributeBuffers.push(attributeBuffer);
773
+ }
774
+ }
775
+ }
776
+ return attributeBuffers;
777
+ }
778
+ /**
779
+ * Return attribute type.
780
+ * @param {String} key
781
+ * @param {Array} attributeStorageInfo
782
+ * @returns {String} attribute type.
783
+ */
784
+ function getAttributeType(key, attributeStorageInfo) {
785
+ const attribute = attributeStorageInfo.find((attr) => attr.name === key);
786
+ return attribute.attributeValues.valueType;
787
+ }
788
+ /**
789
+ * Convert short integer to attribute arrayBuffer.
790
+ * @param {Array} featureIds
791
+ * @returns {ArrayBuffer} - Buffer with objectId data.
792
+ */
793
+ function generateShortIntegerAttributeBuffer(featureIds) {
794
+ const count = new Uint32Array([featureIds.length]);
795
+ const valuesArray = new Uint32Array(featureIds);
796
+ return (0, loader_utils_1.concatenateArrayBuffers)(count.buffer, valuesArray.buffer);
797
+ }
798
+ /**
799
+ * Convert double to attribute arrayBuffer.
800
+ * @param {Array} featureIds
801
+ * @returns {ArrayBuffer} - Buffer with objectId data.
802
+ */
803
+ function generateDoubleAttributeBuffer(featureIds) {
804
+ const count = new Uint32Array([featureIds.length]);
805
+ const padding = new Uint8Array(4);
806
+ const valuesArray = new Float64Array(featureIds);
807
+ return (0, loader_utils_1.concatenateArrayBuffers)(count.buffer, padding.buffer, valuesArray.buffer);
808
+ }
809
+ /**
810
+ * Convert batch table attributes to array buffer with batch table data.
811
+ * @param {Array} batchAttributes
812
+ * @returns {ArrayBuffer} - Buffer with batch table data.
813
+ */
814
+ function generateStringAttributeBuffer(batchAttributes) {
815
+ const stringCountArray = new Uint32Array([batchAttributes.length]);
816
+ let totalNumberOfBytes = 0;
817
+ const stringSizesArray = new Uint32Array(batchAttributes.length);
818
+ const stringBufferArray = [];
819
+ for (let index = 0; index < batchAttributes.length; index++) {
820
+ const currentString = `${String(batchAttributes[index])}\0`;
821
+ const currentStringBuffer = Buffer.from(currentString);
822
+ const currentStringSize = currentStringBuffer.length;
823
+ totalNumberOfBytes += currentStringSize;
824
+ stringSizesArray[index] = currentStringSize;
825
+ stringBufferArray.push(currentStringBuffer);
826
+ }
827
+ const totalBytes = new Uint32Array([totalNumberOfBytes]);
828
+ return (0, loader_utils_1.concatenateArrayBuffers)(stringCountArray.buffer, totalBytes.buffer, stringSizesArray.buffer, ...stringBufferArray);
829
+ }
830
+ /**
831
+ * Convert featureIds to BigUint64Array.
832
+ * @param {Array} featureIds
833
+ * @returns {BigUint64Array} - Array of feature ids in BigUint64 format.
834
+ */
835
+ function generateBigUint64Array(featureIds) {
836
+ const typedFeatureIds = new BigUint64Array(featureIds.length);
837
+ for (let index = 0; index < featureIds.length; index++) {
838
+ typedFeatureIds[index] = BigInt(featureIds[index]);
839
+ }
840
+ return typedFeatureIds;
841
+ }
842
+ /**
843
+ * Generates draco compressed geometry
844
+ * @param {Number} vertexCount
845
+ * @param {Object} convertedAttributes - get rid of this argument here
846
+ * @param {Object} attributes - geometry attributes to compress
847
+ * @param {string} dracoWorkerSoure - draco worker source code
848
+ * @returns {Promise<object>} - COmpressed geometry.
849
+ */
850
+ async function generateCompressedGeometry(vertexCount, convertedAttributes, attributes, dracoWorkerSoure) {
851
+ const { positions, normals, texCoords, colors, featureIds, faceRange } = attributes;
852
+ const indices = new Uint32Array(vertexCount);
853
+ for (let index = 0; index < indices.length; index++) {
854
+ indices.set([index], index);
855
+ }
856
+ const featureIndices = new Uint32Array(convertedAttributes.featureIndices.length ? convertedAttributes.featureIndices : vertexCount);
857
+ const featureIndex = generateFeatureIndexAttribute(featureIndices, faceRange);
858
+ const compressedAttributes = {
859
+ positions,
860
+ normals,
861
+ colors,
862
+ 'feature-index': featureIndex
863
+ };
864
+ if (texCoords.length) {
865
+ compressedAttributes.texCoords = texCoords;
866
+ }
867
+ const attributesMetadata = {
868
+ 'feature-index': {
869
+ 'i3s-attribute-type': 'feature-index',
870
+ 'i3s-feature-ids': new Int32Array(featureIds)
871
+ }
872
+ };
873
+ return (0, core_2.encode)({ attributes: compressedAttributes, indices }, draco_1.DracoWriterWorker, {
874
+ ...draco_1.DracoWriterWorker.options,
875
+ source: dracoWorkerSoure,
876
+ reuseWorkers: true,
877
+ _nodeWorkers: true,
878
+ draco: {
879
+ method: 'MESH_SEQUENTIAL_ENCODING',
880
+ attributesMetadata
881
+ }
882
+ });
883
+ }
884
+ /**
885
+ * Generates ordered feature indices based on face range
886
+ * @param {Uint32Array} featureIndex
887
+ * @param {Uint32Array} faceRange
888
+ * @returns {Uint32Array}
889
+ */
890
+ function generateFeatureIndexAttribute(featureIndex, faceRange) {
891
+ const orderedFeatureIndices = new Uint32Array(featureIndex.length);
892
+ let fillIndex = 0;
893
+ let startIndex = 0;
894
+ for (let index = 1; index < faceRange.length; index += 2) {
895
+ const endIndex = (faceRange[index] + 1) * VALUES_PER_VERTEX;
896
+ orderedFeatureIndices.fill(fillIndex, startIndex, endIndex);
897
+ fillIndex++;
898
+ startIndex = endIndex + 1;
899
+ }
900
+ return orderedFeatureIndices;
901
+ }