@loaders.gl/tile-converter 3.3.0-alpha.1 → 3.3.0-alpha.10

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 (252) hide show
  1. package/dist/3d-tiles-attributes-worker.d.ts +3 -3
  2. package/dist/3d-tiles-attributes-worker.d.ts.map +1 -1
  3. package/dist/3d-tiles-attributes-worker.js +2 -3
  4. package/dist/3d-tiles-attributes-worker.js.map +3 -3
  5. package/dist/3d-tiles-converter/3d-tiles-converter.d.ts +8 -0
  6. package/dist/3d-tiles-converter/3d-tiles-converter.d.ts.map +1 -1
  7. package/dist/3d-tiles-converter/3d-tiles-converter.js +57 -43
  8. package/dist/3d-tiles-converter/helpers/b3dm-converter.d.ts +5 -5
  9. package/dist/3d-tiles-converter/helpers/b3dm-converter.d.ts.map +1 -1
  10. package/dist/3d-tiles-converter/helpers/b3dm-converter.js +21 -17
  11. package/dist/converter-cli.js +29 -4
  12. package/dist/converter.min.js +24 -21
  13. package/dist/deps-installer/deps-installer.d.ts +5 -1
  14. package/dist/deps-installer/deps-installer.d.ts.map +1 -1
  15. package/dist/deps-installer/deps-installer.js +29 -1
  16. package/dist/dist.min.js +61034 -64112
  17. package/dist/es5/3d-tiles-attributes-worker.js +4 -7
  18. package/dist/es5/3d-tiles-attributes-worker.js.map +1 -1
  19. package/dist/es5/3d-tiles-converter/3d-tiles-converter.js +125 -210
  20. package/dist/es5/3d-tiles-converter/3d-tiles-converter.js.map +1 -1
  21. package/dist/es5/3d-tiles-converter/helpers/b3dm-converter.js +53 -85
  22. package/dist/es5/3d-tiles-converter/helpers/b3dm-converter.js.map +1 -1
  23. package/dist/es5/3d-tiles-converter/helpers/i3s-obb-to-3d-tiles-obb.js +0 -8
  24. package/dist/es5/3d-tiles-converter/helpers/i3s-obb-to-3d-tiles-obb.js.map +1 -1
  25. package/dist/es5/3d-tiles-converter/helpers/texture-atlas.js +0 -5
  26. package/dist/es5/3d-tiles-converter/helpers/texture-atlas.js.map +1 -1
  27. package/dist/es5/3d-tiles-converter/json-templates/tileset.js +0 -6
  28. package/dist/es5/3d-tiles-converter/json-templates/tileset.js.map +1 -1
  29. package/dist/es5/bundle.js +0 -1
  30. package/dist/es5/bundle.js.map +1 -1
  31. package/dist/es5/constants.js.map +1 -1
  32. package/dist/es5/converter-cli.js +25 -58
  33. package/dist/es5/converter-cli.js.map +1 -1
  34. package/dist/es5/deps-installer/deps-installer.js +73 -28
  35. package/dist/es5/deps-installer/deps-installer.js.map +1 -1
  36. package/dist/es5/i3s-attributes-worker.js +3 -6
  37. package/dist/es5/i3s-attributes-worker.js.map +1 -1
  38. package/dist/es5/i3s-converter/helpers/batch-ids-extensions.js +18 -29
  39. package/dist/es5/i3s-converter/helpers/batch-ids-extensions.js.map +1 -1
  40. package/dist/es5/i3s-converter/helpers/coordinate-converter.js +8 -25
  41. package/dist/es5/i3s-converter/helpers/coordinate-converter.js.map +1 -1
  42. package/dist/es5/i3s-converter/helpers/create-scene-server-path.js +0 -11
  43. package/dist/es5/i3s-converter/helpers/create-scene-server-path.js.map +1 -1
  44. package/dist/es5/i3s-converter/helpers/feature-attributes.js +184 -0
  45. package/dist/es5/i3s-converter/helpers/feature-attributes.js.map +1 -0
  46. package/dist/es5/i3s-converter/helpers/geometry-attributes.js +60 -51
  47. package/dist/es5/i3s-converter/helpers/geometry-attributes.js.map +1 -1
  48. package/dist/es5/i3s-converter/helpers/geometry-converter.js +504 -350
  49. package/dist/es5/i3s-converter/helpers/geometry-converter.js.map +1 -1
  50. package/dist/es5/i3s-converter/helpers/gltf-attributes.js +57 -57
  51. package/dist/es5/i3s-converter/helpers/gltf-attributes.js.map +1 -1
  52. package/dist/es5/i3s-converter/helpers/node-debug.js +4 -23
  53. package/dist/es5/i3s-converter/helpers/node-debug.js.map +1 -1
  54. package/dist/es5/i3s-converter/helpers/node-index-document.js +507 -0
  55. package/dist/es5/i3s-converter/helpers/node-index-document.js.map +1 -0
  56. package/dist/es5/i3s-converter/helpers/node-pages.js +478 -168
  57. package/dist/es5/i3s-converter/helpers/node-pages.js.map +1 -1
  58. package/dist/es5/i3s-converter/i3s-converter.js +794 -1125
  59. package/dist/es5/i3s-converter/i3s-converter.js.map +1 -1
  60. package/dist/es5/i3s-converter/json-templates/geometry-definitions.js +107 -0
  61. package/dist/es5/i3s-converter/json-templates/geometry-definitions.js.map +1 -0
  62. package/dist/es5/i3s-converter/json-templates/layers.js +2 -107
  63. package/dist/es5/i3s-converter/json-templates/layers.js.map +1 -1
  64. package/dist/es5/i3s-converter/json-templates/metadata.js +0 -2
  65. package/dist/es5/i3s-converter/json-templates/metadata.js.map +1 -1
  66. package/dist/es5/i3s-converter/json-templates/node.js +2 -12
  67. package/dist/es5/i3s-converter/json-templates/node.js.map +1 -1
  68. package/dist/es5/i3s-converter/json-templates/scene-server.js +0 -2
  69. package/dist/es5/i3s-converter/json-templates/scene-server.js.map +1 -1
  70. package/dist/es5/i3s-converter/json-templates/shared-resources.js +9 -32
  71. package/dist/es5/i3s-converter/json-templates/shared-resources.js.map +1 -1
  72. package/dist/es5/i3s-converter/json-templates/store.js.map +1 -1
  73. package/dist/es5/i3s-converter/types.js.map +1 -1
  74. package/dist/es5/i3s-server/app.js +0 -5
  75. package/dist/es5/i3s-server/app.js.map +1 -1
  76. package/dist/es5/i3s-server/controllers/index-controller.js +0 -16
  77. package/dist/es5/i3s-server/controllers/index-controller.js.map +1 -1
  78. package/dist/es5/i3s-server/routes/index.js +1 -10
  79. package/dist/es5/i3s-server/routes/index.js.map +1 -1
  80. package/dist/es5/index.js +0 -3
  81. package/dist/es5/index.js.map +1 -1
  82. package/dist/es5/lib/utils/compress-util.js +19 -74
  83. package/dist/es5/lib/utils/compress-util.js.map +1 -1
  84. package/dist/es5/lib/utils/file-utils.js +103 -47
  85. package/dist/es5/lib/utils/file-utils.js.map +1 -1
  86. package/dist/es5/lib/utils/lod-conversion-utils.js +0 -7
  87. package/dist/es5/lib/utils/lod-conversion-utils.js.map +1 -1
  88. package/dist/es5/lib/utils/queue.js +0 -14
  89. package/dist/es5/lib/utils/queue.js.map +1 -1
  90. package/dist/es5/lib/utils/statistic-utills.js +1 -46
  91. package/dist/es5/lib/utils/statistic-utills.js.map +1 -1
  92. package/dist/es5/lib/utils/write-queue.js +86 -87
  93. package/dist/es5/lib/utils/write-queue.js.map +1 -1
  94. package/dist/es5/pgm-loader.js +1 -8
  95. package/dist/es5/pgm-loader.js.map +1 -1
  96. package/dist/es5/workers/3d-tiles-attributes-worker.js +2 -9
  97. package/dist/es5/workers/3d-tiles-attributes-worker.js.map +1 -1
  98. package/dist/es5/workers/i3s-attributes-worker.js +2 -10
  99. package/dist/es5/workers/i3s-attributes-worker.js.map +1 -1
  100. package/dist/esm/3d-tiles-attributes-worker.js +4 -2
  101. package/dist/esm/3d-tiles-attributes-worker.js.map +1 -1
  102. package/dist/esm/3d-tiles-converter/3d-tiles-converter.js +60 -77
  103. package/dist/esm/3d-tiles-converter/3d-tiles-converter.js.map +1 -1
  104. package/dist/esm/3d-tiles-converter/helpers/b3dm-converter.js +29 -50
  105. package/dist/esm/3d-tiles-converter/helpers/b3dm-converter.js.map +1 -1
  106. package/dist/esm/3d-tiles-converter/helpers/i3s-obb-to-3d-tiles-obb.js +1 -0
  107. package/dist/esm/3d-tiles-converter/helpers/i3s-obb-to-3d-tiles-obb.js.map +1 -1
  108. package/dist/esm/3d-tiles-converter/helpers/texture-atlas.js +1 -4
  109. package/dist/esm/3d-tiles-converter/helpers/texture-atlas.js.map +1 -1
  110. package/dist/esm/3d-tiles-converter/json-templates/tileset.js +0 -3
  111. package/dist/esm/3d-tiles-converter/json-templates/tileset.js.map +1 -1
  112. package/dist/esm/bundle.js +1 -1
  113. package/dist/esm/bundle.js.map +1 -1
  114. package/dist/esm/constants.js.map +1 -1
  115. package/dist/esm/converter-cli.js +26 -43
  116. package/dist/esm/converter-cli.js.map +1 -1
  117. package/dist/esm/deps-installer/deps-installer.js +30 -4
  118. package/dist/esm/deps-installer/deps-installer.js.map +1 -1
  119. package/dist/esm/i3s-attributes-worker.js +3 -1
  120. package/dist/esm/i3s-attributes-worker.js.map +1 -1
  121. package/dist/esm/i3s-converter/helpers/batch-ids-extensions.js +20 -24
  122. package/dist/esm/i3s-converter/helpers/batch-ids-extensions.js.map +1 -1
  123. package/dist/esm/i3s-converter/helpers/coordinate-converter.js +11 -12
  124. package/dist/esm/i3s-converter/helpers/coordinate-converter.js.map +1 -1
  125. package/dist/esm/i3s-converter/helpers/create-scene-server-path.js +1 -0
  126. package/dist/esm/i3s-converter/helpers/create-scene-server-path.js.map +1 -1
  127. package/dist/esm/i3s-converter/helpers/feature-attributes.js +158 -0
  128. package/dist/esm/i3s-converter/helpers/feature-attributes.js.map +1 -0
  129. package/dist/esm/i3s-converter/helpers/geometry-attributes.js +39 -33
  130. package/dist/esm/i3s-converter/helpers/geometry-attributes.js.map +1 -1
  131. package/dist/esm/i3s-converter/helpers/geometry-converter.js +286 -192
  132. package/dist/esm/i3s-converter/helpers/geometry-converter.js.map +1 -1
  133. package/dist/esm/i3s-converter/helpers/gltf-attributes.js +59 -48
  134. package/dist/esm/i3s-converter/helpers/gltf-attributes.js.map +1 -1
  135. package/dist/esm/i3s-converter/helpers/node-debug.js +3 -13
  136. package/dist/esm/i3s-converter/helpers/node-debug.js.map +1 -1
  137. package/dist/esm/i3s-converter/helpers/node-index-document.js +197 -0
  138. package/dist/esm/i3s-converter/helpers/node-index-document.js.map +1 -0
  139. package/dist/esm/i3s-converter/helpers/node-pages.js +161 -87
  140. package/dist/esm/i3s-converter/helpers/node-pages.js.map +1 -1
  141. package/dist/esm/i3s-converter/i3s-converter.js +235 -508
  142. package/dist/esm/i3s-converter/i3s-converter.js.map +1 -1
  143. package/dist/esm/i3s-converter/json-templates/geometry-definitions.js +89 -0
  144. package/dist/esm/i3s-converter/json-templates/geometry-definitions.js.map +1 -0
  145. package/dist/esm/i3s-converter/json-templates/layers.js +2 -95
  146. package/dist/esm/i3s-converter/json-templates/layers.js.map +1 -1
  147. package/dist/esm/i3s-converter/json-templates/metadata.js.map +1 -1
  148. package/dist/esm/i3s-converter/json-templates/node.js +0 -4
  149. package/dist/esm/i3s-converter/json-templates/node.js.map +1 -1
  150. package/dist/esm/i3s-converter/json-templates/scene-server.js.map +1 -1
  151. package/dist/esm/i3s-converter/json-templates/shared-resources.js +3 -15
  152. package/dist/esm/i3s-converter/json-templates/shared-resources.js.map +1 -1
  153. package/dist/esm/i3s-converter/json-templates/store.js.map +1 -1
  154. package/dist/esm/i3s-converter/types.js.map +1 -1
  155. package/dist/esm/i3s-server/app.js +0 -5
  156. package/dist/esm/i3s-server/app.js.map +1 -1
  157. package/dist/esm/i3s-server/controllers/index-controller.js +0 -5
  158. package/dist/esm/i3s-server/controllers/index-controller.js.map +1 -1
  159. package/dist/esm/i3s-server/routes/index.js +0 -3
  160. package/dist/esm/i3s-server/routes/index.js.map +1 -1
  161. package/dist/esm/index.js.map +1 -1
  162. package/dist/esm/lib/utils/compress-util.js +19 -12
  163. package/dist/esm/lib/utils/compress-util.js.map +1 -1
  164. package/dist/esm/lib/utils/file-utils.js +54 -11
  165. package/dist/esm/lib/utils/file-utils.js.map +1 -1
  166. package/dist/esm/lib/utils/lod-conversion-utils.js +2 -6
  167. package/dist/esm/lib/utils/lod-conversion-utils.js.map +1 -1
  168. package/dist/esm/lib/utils/queue.js +0 -4
  169. package/dist/esm/lib/utils/queue.js.map +1 -1
  170. package/dist/esm/lib/utils/statistic-utills.js +0 -11
  171. package/dist/esm/lib/utils/statistic-utills.js.map +1 -1
  172. package/dist/esm/lib/utils/write-queue.js +29 -28
  173. package/dist/esm/lib/utils/write-queue.js.map +1 -1
  174. package/dist/esm/pgm-loader.js +3 -1
  175. package/dist/esm/pgm-loader.js.map +1 -1
  176. package/dist/esm/workers/3d-tiles-attributes-worker.js +4 -1
  177. package/dist/esm/workers/3d-tiles-attributes-worker.js.map +1 -1
  178. package/dist/esm/workers/i3s-attributes-worker.js +4 -1
  179. package/dist/esm/workers/i3s-attributes-worker.js.map +1 -1
  180. package/dist/i3s-attributes-worker.d.ts +7 -3
  181. package/dist/i3s-attributes-worker.d.ts.map +1 -1
  182. package/dist/i3s-attributes-worker.js +2 -3
  183. package/dist/i3s-attributes-worker.js.map +3 -3
  184. package/dist/i3s-converter/helpers/batch-ids-extensions.d.ts +5 -6
  185. package/dist/i3s-converter/helpers/batch-ids-extensions.d.ts.map +1 -1
  186. package/dist/i3s-converter/helpers/batch-ids-extensions.js +18 -4
  187. package/dist/i3s-converter/helpers/coordinate-converter.d.ts +2 -2
  188. package/dist/i3s-converter/helpers/coordinate-converter.d.ts.map +1 -1
  189. package/dist/i3s-converter/helpers/coordinate-converter.js +8 -6
  190. package/dist/i3s-converter/helpers/feature-attributes.d.ts +56 -0
  191. package/dist/i3s-converter/helpers/feature-attributes.d.ts.map +1 -0
  192. package/dist/i3s-converter/helpers/feature-attributes.js +216 -0
  193. package/dist/i3s-converter/helpers/geometry-attributes.d.ts.map +1 -1
  194. package/dist/i3s-converter/helpers/geometry-attributes.js +42 -17
  195. package/dist/i3s-converter/helpers/geometry-converter.d.ts +18 -6
  196. package/dist/i3s-converter/helpers/geometry-converter.d.ts.map +1 -1
  197. package/dist/i3s-converter/helpers/geometry-converter.js +337 -92
  198. package/dist/i3s-converter/helpers/gltf-attributes.d.ts.map +1 -1
  199. package/dist/i3s-converter/helpers/gltf-attributes.js +51 -32
  200. package/dist/i3s-converter/helpers/node-index-document.d.ts +91 -0
  201. package/dist/i3s-converter/helpers/node-index-document.d.ts.map +1 -0
  202. package/dist/i3s-converter/helpers/node-index-document.js +242 -0
  203. package/dist/i3s-converter/helpers/node-pages.d.ts +81 -42
  204. package/dist/i3s-converter/helpers/node-pages.d.ts.map +1 -1
  205. package/dist/i3s-converter/helpers/node-pages.js +200 -92
  206. package/dist/i3s-converter/i3s-converter.d.ts +52 -108
  207. package/dist/i3s-converter/i3s-converter.d.ts.map +1 -1
  208. package/dist/i3s-converter/i3s-converter.js +234 -420
  209. package/dist/i3s-converter/json-templates/geometry-definitions.d.ts +7 -0
  210. package/dist/i3s-converter/json-templates/geometry-definitions.d.ts.map +1 -0
  211. package/dist/i3s-converter/json-templates/geometry-definitions.js +87 -0
  212. package/dist/i3s-converter/json-templates/layers.d.ts +1 -30
  213. package/dist/i3s-converter/json-templates/layers.d.ts.map +1 -1
  214. package/dist/i3s-converter/json-templates/layers.js +2 -86
  215. package/dist/i3s-converter/json-templates/shared-resources.js +3 -3
  216. package/dist/i3s-converter/types.d.ts +37 -55
  217. package/dist/i3s-converter/types.d.ts.map +1 -1
  218. package/dist/lib/utils/file-utils.d.ts +17 -1
  219. package/dist/lib/utils/file-utils.d.ts.map +1 -1
  220. package/dist/lib/utils/file-utils.js +64 -7
  221. package/dist/lib/utils/write-queue.d.ts +19 -2
  222. package/dist/lib/utils/write-queue.d.ts.map +1 -1
  223. package/dist/lib/utils/write-queue.js +26 -7
  224. package/dist/pgm-loader.d.ts.map +1 -1
  225. package/dist/pgm-loader.js +2 -1
  226. package/dist/workers/3d-tiles-attributes-worker.js +1 -1
  227. package/dist/workers/i3s-attributes-worker.js +1 -1
  228. package/package.json +18 -16
  229. package/src/3d-tiles-attributes-worker.ts +1 -1
  230. package/src/3d-tiles-converter/3d-tiles-converter.ts +71 -55
  231. package/src/3d-tiles-converter/helpers/b3dm-converter.ts +25 -18
  232. package/src/converter-cli.ts +38 -4
  233. package/src/deps-installer/deps-installer.ts +38 -2
  234. package/src/i3s-attributes-worker.ts +5 -1
  235. package/src/i3s-converter/helpers/batch-ids-extensions.ts +38 -14
  236. package/src/i3s-converter/helpers/coordinate-converter.ts +10 -8
  237. package/src/i3s-converter/helpers/feature-attributes.ts +247 -0
  238. package/src/i3s-converter/helpers/geometry-attributes.ts +46 -18
  239. package/src/i3s-converter/helpers/geometry-converter.ts +405 -108
  240. package/src/i3s-converter/helpers/gltf-attributes.ts +55 -35
  241. package/src/i3s-converter/helpers/node-index-document.ts +306 -0
  242. package/src/i3s-converter/helpers/node-pages.ts +222 -109
  243. package/src/i3s-converter/i3s-converter.ts +279 -499
  244. package/src/i3s-converter/json-templates/geometry-definitions.ts +83 -0
  245. package/src/i3s-converter/json-templates/layers.ts +2 -91
  246. package/src/i3s-converter/json-templates/shared-resources.ts +3 -3
  247. package/src/i3s-converter/types.ts +31 -51
  248. package/src/lib/utils/file-utils.ts +62 -7
  249. package/src/lib/utils/write-queue.ts +43 -10
  250. package/src/pgm-loader.ts +2 -2
  251. package/src/workers/3d-tiles-attributes-worker.ts +1 -1
  252. package/src/workers/i3s-attributes-worker.ts +2 -1
@@ -1,4 +1,14 @@
1
- import type {Image, MeshPrimitive} from 'modules/gltf/src/lib/types/gltf-postprocessed-schema';
1
+ import type {B3DMContent, FeatureTableJson} from '@loaders.gl/3d-tiles';
2
+ import type {
3
+ GLTF_EXT_feature_metadata,
4
+ GLTFAccessorPostprocessed,
5
+ GLTFMaterialPostprocessed,
6
+ GLTFNodePostprocessed,
7
+ GLTFImagePostprocessed,
8
+ GLTFMeshPrimitivePostprocessed,
9
+ GLTFMeshPostprocessed,
10
+ GLTFTexturePostprocessed
11
+ } from '@loaders.gl/gltf';
2
12
 
3
13
  import {Vector3, Matrix4, Vector4} from '@math.gl/core';
4
14
  import {Ellipsoid} from '@math.gl/geospatial';
@@ -7,16 +17,16 @@ import {DracoWriterWorker} from '@loaders.gl/draco';
7
17
  import {assert, encode} from '@loaders.gl/core';
8
18
  import {concatenateArrayBuffers, concatenateTypedArrays} from '@loaders.gl/loader-utils';
9
19
  import md5 from 'md5';
20
+ import {v4 as uuidv4} from 'uuid';
10
21
  import {generateAttributes} from './geometry-attributes';
11
22
  import {createBoundingVolumesFromGeometry} from './coordinate-converter';
12
23
  import {
13
24
  ConvertedAttributes,
14
25
  I3SConvertedResources,
15
26
  I3SMaterialWithTexture,
27
+ MergedMaterial,
16
28
  SharedResourcesArrays
17
29
  } from '../types';
18
- import {B3DMContent} from '@loaders.gl/3d-tiles';
19
- import {GLTFMaterialPostprocessed, GLTFNodePostprocessed} from '@loaders.gl/gltf';
20
30
  import {
21
31
  AttributeStorageInfo,
22
32
  I3SMaterialDefinition,
@@ -25,14 +35,11 @@ import {
25
35
  } from '@loaders.gl/i3s';
26
36
  import {TypedArray} from '@loaders.gl/schema';
27
37
  import {Geoid} from '@math.gl/geoid';
28
- import {
29
- GLTFAccessorPostprocessed,
30
- GLTFMeshPostprocessed,
31
- GLTFTexturePostprocessed
32
- } from 'modules/gltf/src/lib/types/gltf-types';
33
- import {B3DMAttributesData /*transformI3SAttributesOnWorker */} from '../../i3s-attributes-worker';
38
+ /** Usage of worker here brings more overhead than advantage */
39
+ import {B3DMAttributesData /*, transformI3SAttributesOnWorker*/} from '../../i3s-attributes-worker';
34
40
  import {prepareDataForAttributesConversion} from './gltf-attributes';
35
41
  import {handleBatchIdsExtensions} from './batch-ids-extensions';
42
+ import {checkPropertiesLength, flattenPropertyTableByFeatureIds} from './feature-attributes';
36
43
 
37
44
  // Spec - https://github.com/Esri/i3s-spec/blob/master/docs/1.7/pbrMetallicRoughness.cmn.md
38
45
  const DEFAULT_ROUGHNESS_FACTOR = 1;
@@ -53,90 +60,89 @@ const OBJECT_ID_TYPE = 'Oid32';
53
60
  */
54
61
  const BATCHED_ID_POSSIBLE_ATTRIBUTE_NAMES = ['CUSTOM_ATTRIBUTE_2', '_BATCHID', 'BATCHID'];
55
62
 
63
+ const EXT_FEATURE_METADATA = 'EXT_feature_metadata';
64
+ const EXT_MESH_FEATURES = 'EXT_mesh_features';
65
+
56
66
  let scratchVector = new Vector3();
57
67
 
58
68
  /**
59
69
  * Convert binary data from b3dm file to i3s resources
60
70
  *
61
71
  * @param tileContent - 3d tile content
62
- * @param nodeId - target nodeId. If a few nodes will be created - ids will be nodeId+n where n - index in the resulting array
72
+ * @param addNodeToNodePage - function to add new node to node pages
73
+ * @param propertyTable - batch table (corresponding to feature attributes data)
63
74
  * @param featuresHashArray - hash array of features that is needed to not to mix up same features in parent and child nodes
64
75
  * @param attributeStorageInfo - attributes metadata from 3DSceneLayer json
65
76
  * @param draco - is converter should create draco compressed geometry
66
77
  * @param generateBoundingVolumes - is converter should create accurate bounding voulmes from geometry attributes
78
+ * @param shouldMergeMaterials - Try to merge similar materials to be able to merge meshes into one node
67
79
  * @param geoidHeightModel - model to convert elevation from elipsoidal to geoid
80
+ * @param workerSource - source code of used workers
68
81
  * @returns Array of node resources to create one or more i3s nodes
69
82
  */
70
83
  export default async function convertB3dmToI3sGeometry(
71
84
  tileContent: B3DMContent,
72
- nodeId: number,
85
+ addNodeToNodePage: () => Promise<number>,
86
+ propertyTable: FeatureTableJson | null,
73
87
  featuresHashArray: string[],
74
88
  attributeStorageInfo: AttributeStorageInfo[] | undefined,
75
89
  draco: boolean,
76
90
  generateBoundingVolumes: boolean,
91
+ shouldMergeMaterials: boolean,
77
92
  geoidHeightModel: Geoid,
78
93
  workerSource: {[key: string]: string}
79
- ) {
94
+ ): Promise<I3SConvertedResources[] | null> {
80
95
  const useCartesianPositions = generateBoundingVolumes;
81
- const materialAndTextureList: I3SMaterialWithTexture[] = convertMaterials(
82
- tileContent.gltf?.materials
96
+ const materialAndTextureList: I3SMaterialWithTexture[] = await convertMaterials(
97
+ tileContent.gltf?.materials,
98
+ shouldMergeMaterials
83
99
  );
84
100
 
85
101
  const dataForAttributesConversion = prepareDataForAttributesConversion(tileContent);
86
-
87
102
  const convertedAttributesMap: Map<string, ConvertedAttributes> = await convertAttributes(
88
103
  dataForAttributesConversion,
104
+ materialAndTextureList,
89
105
  useCartesianPositions
90
106
  );
91
- // TODO uncomment it when worker will be published on CDN.
92
- /*
93
- const convertedAttributesMap: Map<string, ConvertedAttributes> =
94
- await transformI3SAttributesOnWorker(dataForAttributesConversion, {
95
- useCartesianPositions,
96
- source: workerSource.I3SAttributes
97
- });
98
- */
107
+ /** Usage of worker here brings more overhead than advantage */
108
+ // const convertedAttributesMap: Map<string, ConvertedAttributes> =
109
+ // await transformI3SAttributesOnWorker(dataForAttributesConversion, {
110
+ // reuseWorkers: true,
111
+ // _nodeWorkers: true,
112
+ // useCartesianPositions,
113
+ // source: workerSource.I3SAttributes
114
+ // });
99
115
 
100
116
  if (generateBoundingVolumes) {
101
117
  _generateBoundingVolumesFromGeometry(convertedAttributesMap, geoidHeightModel);
102
118
  }
103
119
 
104
- if (convertedAttributesMap.has('default')) {
105
- materialAndTextureList.push({
106
- material: getDefaultMaterial()
107
- });
108
- }
109
-
110
120
  const result: I3SConvertedResources[] = [];
111
- let nodesCounter = nodeId;
112
- let {materials = []} = tileContent.gltf || {materials: []};
113
- if (!materials?.length) {
114
- materials.push({id: 'default'});
115
- }
116
- for (let i = 0; i < materials.length; i++) {
117
- const sourceMaterial = materials[i];
118
- if (!convertedAttributesMap.has(sourceMaterial.id)) {
121
+ for (const materialAndTexture of materialAndTextureList) {
122
+ const originarMaterialId = materialAndTexture.mergedMaterials[0].originalMaterialId;
123
+ if (!convertedAttributesMap.has(originarMaterialId)) {
119
124
  continue; // eslint-disable-line no-continue
120
125
  }
121
- const convertedAttributes = convertedAttributesMap.get(sourceMaterial.id);
126
+ const convertedAttributes = convertedAttributesMap.get(originarMaterialId);
122
127
  if (!convertedAttributes) {
123
128
  continue;
124
129
  }
125
- const {material, texture} = materialAndTextureList[i];
130
+ const {material, texture} = materialAndTexture;
131
+ const nodeId = await addNodeToNodePage();
126
132
  result.push(
127
133
  await _makeNodeResources({
128
134
  convertedAttributes,
129
135
  material,
130
136
  texture,
131
137
  tileContent,
132
- nodeId: nodesCounter,
138
+ nodeId,
133
139
  featuresHashArray,
140
+ propertyTable,
134
141
  attributeStorageInfo,
135
142
  draco,
136
143
  workerSource
137
144
  })
138
145
  );
139
- nodesCounter++;
140
146
  }
141
147
 
142
148
  if (!result.length) {
@@ -183,8 +189,10 @@ function _generateBoundingVolumesFromGeometry(
183
189
  * @param params.tileContent - B3DM decoded content
184
190
  * @param params.nodeId - new node ID
185
191
  * @param params.featuresHashArray - hash array of features that is needed to not to mix up same features in parent and child nodes
186
- * @param params.attributesStorageInfo - attributes metadata from 3DSceneLayer json
192
+ * @param params.propertyTable - batch table (corresponding to feature attributes data)
193
+ * @param params.attributeStorageInfo - attributes metadata from 3DSceneLayer json
187
194
  * @param params.draco - is converter should create draco compressed geometry
195
+ * @param params.workerSource - source code of used workers
188
196
  * @returns Array of I3S node resources
189
197
  */
190
198
  async function _makeNodeResources({
@@ -194,6 +202,7 @@ async function _makeNodeResources({
194
202
  tileContent,
195
203
  nodeId,
196
204
  featuresHashArray,
205
+ propertyTable,
197
206
  attributeStorageInfo,
198
207
  draco,
199
208
  workerSource
@@ -204,13 +213,14 @@ async function _makeNodeResources({
204
213
  tileContent: B3DMContent;
205
214
  nodeId: number;
206
215
  featuresHashArray: string[];
216
+ propertyTable: FeatureTableJson | null;
207
217
  attributeStorageInfo?: AttributeStorageInfo[];
208
218
  draco: boolean;
209
219
  workerSource: {[key: string]: string};
210
220
  }): Promise<I3SConvertedResources> {
211
221
  const boundingVolumes = convertedAttributes.boundingVolumes;
212
222
  const vertexCount = convertedAttributes.positions.length / VALUES_PER_VERTEX;
213
- const {faceRange, featureIds, positions, normals, colors, texCoords, featureCount} =
223
+ const {faceRange, featureIds, positions, normals, colors, uvRegions, texCoords, featureCount} =
214
224
  generateAttributes(convertedAttributes);
215
225
 
216
226
  if (tileContent.batchTableJson) {
@@ -233,6 +243,7 @@ async function _makeNodeResources({
233
243
  normals.buffer,
234
244
  texture ? texCoords.buffer : new ArrayBuffer(0),
235
245
  colors.buffer,
246
+ uvRegions,
236
247
  typedFeatureIds.buffer,
237
248
  faceRange.buffer
238
249
  )
@@ -246,6 +257,7 @@ async function _makeNodeResources({
246
257
  normals,
247
258
  texCoords: texture ? texCoords : new Float32Array(0),
248
259
  colors,
260
+ uvRegions,
249
261
  featureIds,
250
262
  faceRange
251
263
  },
@@ -253,16 +265,22 @@ async function _makeNodeResources({
253
265
  )
254
266
  : null;
255
267
 
256
- const attributes = convertBatchTableToAttributeBuffers(
257
- tileContent.batchTableJson,
258
- featureIds,
259
- attributeStorageInfo
260
- );
268
+ let attributes: ArrayBuffer[] = [];
269
+
270
+ if (attributeStorageInfo && propertyTable) {
271
+ attributes = convertPropertyTableToAttributeBuffers(
272
+ featureIds,
273
+ propertyTable,
274
+ attributeStorageInfo
275
+ );
276
+ }
261
277
 
262
278
  return {
279
+ nodeId,
263
280
  geometry: fileBuffer,
264
281
  compressedGeometry,
265
282
  texture,
283
+ hasUvRegions: Boolean(uvRegions.length),
266
284
  sharedResources: getSharedResources(tileContent.gltf?.materials || [], nodeId),
267
285
  meshMaterial: material,
268
286
  vertexCount,
@@ -274,32 +292,40 @@ async function _makeNodeResources({
274
292
 
275
293
  /**
276
294
  * Convert attributes from the gltf nodes tree to i3s plain geometry
277
- * @param tileContent - 3d tile content
295
+ * @param attributesData - geometry attributes from gltf
296
+ * @param materialAndTextureList - array of data about materials and textures of the content
278
297
  * @param useCartesianPositions - convert positions to absolute cartesian coordinates instead of cartographic offsets.
279
298
  * Cartesian coordinates will be required for creating bounding voulmest from geometry positions
280
299
  * @returns map of converted geometry attributes
281
300
  */
282
301
  export async function convertAttributes(
283
302
  attributesData: B3DMAttributesData,
303
+ materialAndTextureList: I3SMaterialWithTexture[],
284
304
  useCartesianPositions: boolean
285
305
  ): Promise<Map<string, ConvertedAttributes>> {
286
- const {gltfMaterials, nodes, cartographicOrigin, cartesianModelMatrix} = attributesData;
306
+ const {nodes, images, cartographicOrigin, cartesianModelMatrix} = attributesData;
287
307
  const attributesMap = new Map<string, ConvertedAttributes>();
288
308
 
289
- for (const material of gltfMaterials || [{id: 'default'}]) {
290
- attributesMap.set(material.id, {
309
+ for (const materialAndTexture of materialAndTextureList) {
310
+ const attributes = {
291
311
  positions: new Float32Array(0),
292
312
  normals: new Float32Array(0),
293
313
  texCoords: new Float32Array(0),
294
314
  colors: new Uint8Array(0),
315
+ uvRegions: new Uint16Array(0),
295
316
  featureIndicesGroups: [],
296
317
  featureIndices: [],
297
- boundingVolumes: null
298
- });
318
+ boundingVolumes: null,
319
+ mergedMaterials: materialAndTexture.mergedMaterials
320
+ };
321
+ for (const mergedMaterial of materialAndTexture.mergedMaterials) {
322
+ attributesMap.set(mergedMaterial.originalMaterialId, attributes);
323
+ }
299
324
  }
300
325
 
301
326
  convertNodes(
302
327
  nodes,
328
+ images,
303
329
  cartographicOrigin,
304
330
  cartesianModelMatrix,
305
331
  attributesMap,
@@ -330,7 +356,9 @@ export async function convertAttributes(
330
356
  * Gltf has hierarchical structure of nodes. This function converts nodes starting from those which are in gltf scene object.
331
357
  * The goal is applying tranformation matrix for all children. Functions "convertNodes" and "convertNode" work together recursively.
332
358
  * @param nodes - gltf nodes array
333
- * @param tileContent - 3d tile content
359
+ * @param images - gltf images array
360
+ * @param cartographicOrigin - cartographic origin of bounding volume
361
+ * @param cartesianModelMatrix - cartesian model matrix to convert coordinates to cartographic
334
362
  * @param attributesMap - for recursive concatenation of attributes
335
363
  * @param useCartesianPositions - convert positions to absolute cartesian coordinates instead of cartographic offsets.
336
364
  * Cartesian coordinates will be required for creating bounding voulmest from geometry positions
@@ -339,6 +367,7 @@ export async function convertAttributes(
339
367
  */
340
368
  function convertNodes(
341
369
  nodes: GLTFNodePostprocessed[],
370
+ images: GLTFImagePostprocessed[],
342
371
  cartographicOrigin: Vector3,
343
372
  cartesianModelMatrix: Matrix4,
344
373
  attributesMap: Map<string, ConvertedAttributes>,
@@ -349,6 +378,7 @@ function convertNodes(
349
378
  for (const node of nodes) {
350
379
  convertNode(
351
380
  node,
381
+ images,
352
382
  cartographicOrigin,
353
383
  cartesianModelMatrix,
354
384
  attributesMap,
@@ -365,7 +395,7 @@ function convertNodes(
365
395
  * @param node
366
396
  * @param matrix
367
397
  */
368
- function getCompositeTransformationMatrix(node, matrix) {
398
+ function getCompositeTransformationMatrix(node: GLTFNodePostprocessed, matrix: Matrix4) {
369
399
  let transformationMatrix = matrix;
370
400
 
371
401
  const {matrix: nodeMatrix, rotation, scale, translation} = node;
@@ -392,7 +422,9 @@ function getCompositeTransformationMatrix(node, matrix) {
392
422
  /**
393
423
  * Convert all primitives of node and all children nodes
394
424
  * @param node - gltf node
395
- * @param {Object} tileContent - 3d tile content
425
+ * @param images - gltf images array
426
+ * @param cartographicOrigin - cartographic origin of bounding volume
427
+ * @param cartesianModelMatrix - cartesian model matrix to convert coordinates to cartographic
396
428
  * @param {Map} attributesMap Map<{positions: Float32Array, normals: Float32Array, texCoords: Float32Array, colors: Uint8Array, featureIndices: Array}> - for recursive concatenation of
397
429
  * attributes
398
430
  * @param useCartesianPositions - convert positions to absolute cartesian coordinates instead of cartographic offsets.
@@ -401,6 +433,7 @@ function getCompositeTransformationMatrix(node, matrix) {
401
433
  */
402
434
  function convertNode(
403
435
  node: GLTFNodePostprocessed,
436
+ images: GLTFImagePostprocessed[],
404
437
  cartographicOrigin: Vector3,
405
438
  cartesianModelMatrix: Matrix4,
406
439
  attributesMap: Map<string, ConvertedAttributes>,
@@ -410,7 +443,6 @@ function convertNode(
410
443
  const transformationMatrix = getCompositeTransformationMatrix(node, matrix);
411
444
 
412
445
  const mesh = node.mesh;
413
- const images = node.images;
414
446
 
415
447
  if (mesh) {
416
448
  convertMesh(
@@ -426,6 +458,7 @@ function convertNode(
426
458
 
427
459
  convertNodes(
428
460
  node.children || [],
461
+ images,
429
462
  cartographicOrigin,
430
463
  cartesianModelMatrix,
431
464
  attributesMap,
@@ -435,9 +468,13 @@ function convertNode(
435
468
  }
436
469
 
437
470
  /**
438
- * Convert all primitives of node and all children nodes
439
- * @param mesh - gltf node
440
- * @param content - 3d tile content
471
+ * Convert all primitives of the mesh
472
+ * @param mesh - gltf mesh data
473
+ * @param images - gltf images array
474
+ * @param cartographicOrigin - cartographic origin of bounding volume
475
+ * @param cartesianModelMatrix - cartesian model matrix to convert coordinates to cartographic
476
+ * @param attributesMap Map<{positions: Float32Array, normals: Float32Array, texCoords: Float32Array, colors: Uint8Array, featureIndices: Array}> - for recursive concatenation of
477
+ * attributes
441
478
  * @param useCartesianPositions - convert positions to absolute cartesian coordinates instead of cartographic offsets.
442
479
  * Cartesian coordinates will be required for creating bounding voulmest from geometry positions
443
480
  * @param attributesMap Map<{positions: Float32Array, normals: Float32Array, texCoords: Float32Array, colors: Uint8Array, featureIndices: Array}> - for recursive concatenation of
@@ -447,7 +484,7 @@ function convertNode(
447
484
  */
448
485
  function convertMesh(
449
486
  mesh: GLTFMeshPostprocessed,
450
- images: Image[],
487
+ images: GLTFImagePostprocessed[],
451
488
  cartographicOrigin: Vector3,
452
489
  cartesianModelMatrix: Matrix4,
453
490
  attributesMap: Map<string, ConvertedAttributes>,
@@ -456,8 +493,12 @@ function convertMesh(
456
493
  ) {
457
494
  for (const primitive of mesh.primitives) {
458
495
  let outputAttributes: ConvertedAttributes | null | undefined = null;
496
+ let materialUvRegion: Uint16Array | undefined;
459
497
  if (primitive.material) {
460
- outputAttributes = attributesMap.get(primitive.material.id);
498
+ outputAttributes = attributesMap.get(primitive.material.uniqueId);
499
+ materialUvRegion = outputAttributes?.mergedMaterials.find(
500
+ ({originalMaterialId}) => originalMaterialId === primitive.material?.uniqueId
501
+ )?.uvRegion;
461
502
  } else if (attributesMap.has('default')) {
462
503
  outputAttributes = attributesMap.get('default');
463
504
  }
@@ -503,6 +544,13 @@ function convertMesh(
503
544
  flattenColors(attributes.COLOR_0, primitive.indices?.value)
504
545
  );
505
546
 
547
+ if (materialUvRegion) {
548
+ outputAttributes.uvRegions = concatenateTypedArrays(
549
+ outputAttributes.uvRegions,
550
+ createUvRegion(materialUvRegion, primitive.indices?.value)
551
+ );
552
+ }
553
+
506
554
  outputAttributes.featureIndicesGroups = outputAttributes.featureIndicesGroups || [];
507
555
  outputAttributes.featureIndicesGroups.push(
508
556
  flattenBatchIds(getBatchIds(attributes, primitive, images), primitive.indices?.value)
@@ -653,6 +701,20 @@ function flattenColors(
653
701
  return newColors;
654
702
  }
655
703
 
704
+ /**
705
+ * Create per-vertex uv-region array
706
+ * @param materialUvRegion - uv-region fragment for a single vertex
707
+ * @param indices - geometry indices data
708
+ * @returns - uv-region array
709
+ */
710
+ function createUvRegion(materialUvRegion: Uint16Array, indices: Uint8Array): Uint16Array {
711
+ const result = new Uint16Array(indices.length * 4);
712
+ for (let i = 0; i < result.length; i += 4) {
713
+ result.set(materialUvRegion, i);
714
+ }
715
+ return result;
716
+ }
717
+
656
718
  /**
657
719
  * Flatten batchedIds list based on indices to right ordered array, compatible with i3s
658
720
  * @param batchedIds - gltf primitive
@@ -673,16 +735,16 @@ function flattenBatchIds(batchedIds: number[], indices: Uint8Array): number[] {
673
735
 
674
736
  /**
675
737
  * Get batchIds for featureIds creation
676
- * @param attributes
677
- * @param primitive
678
- * @param textures
738
+ * @param attributes - gltf accessors
739
+ * @param primitive - gltf primitive data
740
+ * @param images - gltf texture images
679
741
  */
680
742
  function getBatchIds(
681
743
  attributes: {
682
744
  [key: string]: GLTFAccessorPostprocessed;
683
745
  },
684
- primitive: MeshPrimitive,
685
- images: Image[]
746
+ primitive: GLTFMeshPrimitivePostprocessed,
747
+ images: GLTFImagePostprocessed[]
686
748
  ): number[] {
687
749
  const batchIds: number[] = handleBatchIdsExtensions(attributes, primitive, images);
688
750
 
@@ -706,18 +768,127 @@ function getBatchIds(
706
768
  /**
707
769
  * Convert GLTF material to I3S material definitions and textures
708
770
  * @param sourceMaterials Source GLTF materials
771
+ * @param shouldMergeMaterials - if true - the converter will try to merge similar materials
772
+ * to be able to merge primitives having those materials
709
773
  * @returns Array of Couples I3SMaterialDefinition + texture content
710
774
  */
711
- function convertMaterials(
712
- sourceMaterials: GLTFMaterialPostprocessed[] = []
713
- ): I3SMaterialWithTexture[] {
714
- const result: I3SMaterialWithTexture[] = [];
775
+ async function convertMaterials(
776
+ sourceMaterials: GLTFMaterialPostprocessed[] = [],
777
+ shouldMergeMaterials: boolean
778
+ ): Promise<I3SMaterialWithTexture[]> {
779
+ let materials: I3SMaterialWithTexture[] = [];
715
780
  for (const sourceMaterial of sourceMaterials) {
716
- result.push(convertMaterial(sourceMaterial));
781
+ materials.push(convertMaterial(sourceMaterial));
782
+ }
783
+
784
+ if (shouldMergeMaterials) {
785
+ materials = await mergeAllMaterials(materials);
786
+ }
787
+
788
+ return materials;
789
+ }
790
+
791
+ /**
792
+ * Merge materials when possible
793
+ * @param materials materials array
794
+ * @returns merged materials array
795
+ */
796
+ async function mergeAllMaterials(
797
+ materials: I3SMaterialWithTexture[]
798
+ ): Promise<I3SMaterialWithTexture[]> {
799
+ const result: I3SMaterialWithTexture[] = [];
800
+ while (materials.length > 0) {
801
+ let newMaterial = materials.splice(0, 1)[0];
802
+ const mergedIndices: number[] = [];
803
+ for (let i = 0; i < materials.length; i++) {
804
+ const material = materials[i];
805
+ if (
806
+ (newMaterial.texture && material.texture) ||
807
+ (!newMaterial.texture && !material.texture)
808
+ ) {
809
+ newMaterial = await mergeMaterials(newMaterial, material);
810
+ mergedIndices.push(i);
811
+ }
812
+ }
813
+ if (newMaterial.texture && mergedIndices.length) {
814
+ const newWidth = newMaterial.mergedMaterials?.reduce(
815
+ (accum, {textureSize}) => accum + (textureSize?.width || 0),
816
+ 0
817
+ );
818
+ const newHeight = newMaterial.mergedMaterials?.reduce(
819
+ (accum, {textureSize}) => Math.max(accum, textureSize?.height || 0),
820
+ 0
821
+ );
822
+ let currentX = -1;
823
+ for (const aTextureMetadata of newMaterial.mergedMaterials) {
824
+ if (aTextureMetadata.textureSize) {
825
+ const newX =
826
+ currentX +
827
+ 1 +
828
+ (aTextureMetadata.textureSize.width / newWidth) *
829
+ 2 ** (Uint16Array.BYTES_PER_ELEMENT * 8) -
830
+ 1;
831
+ aTextureMetadata.uvRegion = new Uint16Array([
832
+ currentX + 1,
833
+ 0,
834
+ newX,
835
+ (aTextureMetadata.textureSize.height / newHeight) *
836
+ 2 ** (Uint16Array.BYTES_PER_ELEMENT * 8) -
837
+ 1
838
+ ]);
839
+ currentX = newX;
840
+ }
841
+ }
842
+
843
+ newMaterial.texture.image.width = newWidth;
844
+ newMaterial.texture.image.height = newHeight;
845
+ }
846
+ for (const index of mergedIndices.reverse()) {
847
+ materials.splice(index, 1);
848
+ }
849
+ result.push(newMaterial);
850
+ }
851
+
852
+ if (!result.length) {
853
+ result.push({
854
+ material: getDefaultMaterial(),
855
+ mergedMaterials: [{originalMaterialId: 'default'}]
856
+ });
717
857
  }
718
858
  return result;
719
859
  }
720
860
 
861
+ /**
862
+ * Merge 2 materials including texture
863
+ * @param material1
864
+ * @param material2
865
+ * @returns
866
+ */
867
+ async function mergeMaterials(
868
+ material1: I3SMaterialWithTexture,
869
+ material2: I3SMaterialWithTexture
870
+ ): Promise<I3SMaterialWithTexture> {
871
+ if (
872
+ material1.texture?.bufferView &&
873
+ material2.texture?.bufferView &&
874
+ material1.mergedMaterials &&
875
+ material2.mergedMaterials
876
+ ) {
877
+ const buffer1 = Buffer.from(material1.texture.bufferView.data);
878
+ const buffer2 = Buffer.from(material2.texture.bufferView.data);
879
+ // @ts-ignore
880
+ const {joinImages} = await import('join-images');
881
+ const sharpData = await joinImages([buffer1, buffer2], {direction: 'horizontal'});
882
+ material1.texture.bufferView.data = await sharpData
883
+ .toFormat(material1.texture.mimeType === 'image/png' ? 'png' : 'jpeg')
884
+ .toBuffer();
885
+ // @ts-ignore
886
+ material1.material.pbrMetallicRoughness.baseColorTexture.textureSetDefinitionId = 1;
887
+ }
888
+ material1.mergedMaterials = material1.mergedMaterials.concat(material2.mergedMaterials);
889
+ return material1;
890
+ }
891
+
721
892
  /**
722
893
  * Convert texture and material from gltf 2.0 material object
723
894
  * @param sourceMaterial - material object
@@ -756,6 +927,9 @@ function convertMaterial(sourceMaterial: GLTFMaterialPostprocessed): I3SMaterial
756
927
  };
757
928
  }
758
929
 
930
+ const uniqueId = uuidv4();
931
+ sourceMaterial.uniqueId = uniqueId;
932
+ let mergedMaterials: MergedMaterial[] = [{originalMaterialId: uniqueId}];
759
933
  if (!texture) {
760
934
  // Should use default baseColorFactor if it is not present in source material
761
935
  // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#reference-pbrmetallicroughness
@@ -767,9 +941,11 @@ function convertMaterial(sourceMaterial: GLTFMaterialPostprocessed): I3SMaterial
767
941
  number,
768
942
  number
769
943
  ]) || undefined;
944
+ } else {
945
+ mergedMaterials[0].textureSize = {width: texture.image.width, height: texture.image.height};
770
946
  }
771
947
 
772
- return {material, texture};
948
+ return {material, texture, mergedMaterials};
773
949
  }
774
950
 
775
951
  /**
@@ -912,7 +1088,9 @@ function extractSharedResourcesMaterialInfo(
912
1088
  const specular = dielectricSpecular.lerp(dielectricSpecular, baseColorVector, metallicFactor);
913
1089
  return {
914
1090
  params: {
1091
+ // @ts-expect-error NumericArray
915
1092
  diffuse: diffuse.toArray(),
1093
+ // @ts-expect-error NumericArray
916
1094
  specular: specular.toArray(),
917
1095
  renderMode: 'solid'
918
1096
  }
@@ -944,13 +1122,13 @@ function extractSharedResourcesTextureInfo(
944
1122
  }
945
1123
 
946
1124
  /**
947
- * Formula for counting imageId:
1125
+ * Formula for calculating imageId:
948
1126
  * https://github.com/Esri/i3s-spec/blob/0a6366a9249b831db8436c322f8d27521e86cf07/format/Indexed%203d%20Scene%20Layer%20Format%20Specification.md#generating-image-ids
949
1127
  * @param texture - texture image info
950
1128
  * @param nodeId - I3S node ID
951
1129
  * @returns calculate image ID according to the spec
952
1130
  */
953
- function generateImageId(texture: GLTFTexturePostprocessed, nodeId) {
1131
+ function generateImageId(texture: GLTFTexturePostprocessed, nodeId: number) {
954
1132
  const {width, height} = texture.source?.image;
955
1133
  const levelCountOfTexture = 1;
956
1134
  const indexOfLevel = 0;
@@ -1051,49 +1229,66 @@ function replaceIndicesByUnique(indicesArray, featureMap) {
1051
1229
  }
1052
1230
 
1053
1231
  /**
1054
- * Convert batch table data to attribute buffers.
1055
- * @param {Object} batchTable - table with metadata for particular feature.
1232
+ * Convert property table data to attribute buffers.
1056
1233
  * @param {Array} featureIds
1234
+ * @param {Object} propertyTable - table with metadata for particular feature.
1057
1235
  * @param {Array} attributeStorageInfo
1058
1236
  * @returns {Array} - Array of file buffers.
1059
1237
  */
1060
- function convertBatchTableToAttributeBuffers(batchTable, featureIds, attributeStorageInfo) {
1238
+ function convertPropertyTableToAttributeBuffers(
1239
+ featureIds: number[],
1240
+ propertyTable: FeatureTableJson,
1241
+ attributeStorageInfo: AttributeStorageInfo[]
1242
+ ) {
1061
1243
  const attributeBuffers: ArrayBuffer[] = [];
1062
1244
 
1063
- if (batchTable) {
1064
- const batchTableWithFeatureIds = {
1065
- OBJECTID: featureIds,
1066
- ...batchTable
1067
- };
1245
+ const needFlattenPropertyTable = checkPropertiesLength(featureIds, propertyTable);
1246
+ const properties = needFlattenPropertyTable
1247
+ ? flattenPropertyTableByFeatureIds(featureIds, propertyTable)
1248
+ : propertyTable;
1068
1249
 
1069
- for (const key in batchTableWithFeatureIds) {
1070
- const type = getAttributeType(key, attributeStorageInfo);
1071
-
1072
- let attributeBuffer: ArrayBuffer | null = null;
1073
-
1074
- switch (type) {
1075
- case OBJECT_ID_TYPE:
1076
- case SHORT_INT_TYPE:
1077
- attributeBuffer = generateShortIntegerAttributeBuffer(batchTableWithFeatureIds[key]);
1078
- break;
1079
- case DOUBLE_TYPE:
1080
- attributeBuffer = generateDoubleAttributeBuffer(batchTableWithFeatureIds[key]);
1081
- break;
1082
- case STRING_TYPE:
1083
- attributeBuffer = generateStringAttributeBuffer(batchTableWithFeatureIds[key]);
1084
- break;
1085
- default:
1086
- attributeBuffer = generateStringAttributeBuffer(batchTableWithFeatureIds[key]);
1087
- }
1250
+ const propertyTableWithObjectIds = {
1251
+ OBJECTID: featureIds,
1252
+ ...properties
1253
+ };
1088
1254
 
1089
- if (attributeBuffer) {
1090
- attributeBuffers.push(attributeBuffer);
1091
- }
1092
- }
1255
+ for (const propertyName in propertyTableWithObjectIds) {
1256
+ const type = getAttributeType(propertyName, attributeStorageInfo);
1257
+ const value = propertyTableWithObjectIds[propertyName];
1258
+ const attributeBuffer = generateAttributeBuffer(type, value);
1259
+
1260
+ attributeBuffers.push(attributeBuffer);
1093
1261
  }
1094
1262
 
1095
1263
  return attributeBuffers;
1096
1264
  }
1265
+
1266
+ /**
1267
+ * Generates attribute buffer based on attribute type
1268
+ * @param type
1269
+ * @param value
1270
+ */
1271
+ function generateAttributeBuffer(type: string, value: any): ArrayBuffer {
1272
+ let attributeBuffer: ArrayBuffer;
1273
+
1274
+ switch (type) {
1275
+ case OBJECT_ID_TYPE:
1276
+ case SHORT_INT_TYPE:
1277
+ attributeBuffer = generateShortIntegerAttributeBuffer(value);
1278
+ break;
1279
+ case DOUBLE_TYPE:
1280
+ attributeBuffer = generateDoubleAttributeBuffer(value);
1281
+ break;
1282
+ case STRING_TYPE:
1283
+ attributeBuffer = generateStringAttributeBuffer(value);
1284
+ break;
1285
+ default:
1286
+ attributeBuffer = generateStringAttributeBuffer(value);
1287
+ }
1288
+
1289
+ return attributeBuffer;
1290
+ }
1291
+
1097
1292
  /**
1098
1293
  * Return attribute type.
1099
1294
  * @param {String} key
@@ -1186,7 +1381,7 @@ async function generateCompressedGeometry(
1186
1381
  attributes,
1187
1382
  dracoWorkerSoure
1188
1383
  ) {
1189
- const {positions, normals, texCoords, colors, featureIds, faceRange} = attributes;
1384
+ const {positions, normals, texCoords, colors, uvRegions, featureIds, faceRange} = attributes;
1190
1385
  const indices = new Uint32Array(vertexCount);
1191
1386
 
1192
1387
  for (let index = 0; index < indices.length; index++) {
@@ -1205,6 +1400,7 @@ async function generateCompressedGeometry(
1205
1400
  colors: TypedArray;
1206
1401
  'feature-index': TypedArray;
1207
1402
  texCoords?: TypedArray;
1403
+ 'uv-region'?: TypedArray;
1208
1404
  } = {
1209
1405
  positions,
1210
1406
  normals,
@@ -1223,6 +1419,13 @@ async function generateCompressedGeometry(
1223
1419
  }
1224
1420
  };
1225
1421
 
1422
+ if (uvRegions.length) {
1423
+ compressedAttributes['uv-region'] = uvRegions;
1424
+ attributesMetadata['uv-region'] = {
1425
+ 'i3s-attribute-type': 'uv-region'
1426
+ };
1427
+ }
1428
+
1226
1429
  return encode({attributes: compressedAttributes, indices}, DracoWriterWorker, {
1227
1430
  ...DracoWriterWorker.options,
1228
1431
  source: dracoWorkerSoure,
@@ -1257,3 +1460,97 @@ function generateFeatureIndexAttribute(featureIndex, faceRange) {
1257
1460
 
1258
1461
  return orderedFeatureIndices;
1259
1462
  }
1463
+
1464
+ /**
1465
+ * Find property table in tile
1466
+ * For example it can be batchTable for b3dm files or property table in gLTF extension.
1467
+ * @param sourceTile
1468
+ * @return batch table from b3dm / feature properties from EXT_FEATURE_METADATA
1469
+ */
1470
+ export function getPropertyTable(tileContent: B3DMContent): FeatureTableJson | null {
1471
+ const batchTableJson = tileContent?.batchTableJson;
1472
+
1473
+ if (batchTableJson) {
1474
+ return batchTableJson;
1475
+ }
1476
+
1477
+ const {extensionName, extension} = getPropertyTableExtension(tileContent);
1478
+
1479
+ switch (extensionName) {
1480
+ case EXT_MESH_FEATURES: {
1481
+ console.warn('The I3S converter does not yet support the EXT_mesh_features extension');
1482
+ return null;
1483
+ }
1484
+ case EXT_FEATURE_METADATA: {
1485
+ return getPropertyTableFromExtFeatureMetadata(extension);
1486
+ }
1487
+ default:
1488
+ return null;
1489
+ }
1490
+ }
1491
+
1492
+ /**
1493
+ * Check extensions which can be with property table inside.
1494
+ * @param sourceTile
1495
+ */
1496
+ function getPropertyTableExtension(tileContent: B3DMContent) {
1497
+ const extensionsWithPropertyTables = [EXT_FEATURE_METADATA, EXT_MESH_FEATURES];
1498
+ const extensionsUsed = tileContent?.gltf?.extensionsUsed;
1499
+
1500
+ if (!extensionsUsed) {
1501
+ return {extensionName: null, extension: null};
1502
+ }
1503
+
1504
+ let extensionName: string = '';
1505
+
1506
+ for (const extensionItem of tileContent?.gltf?.extensionsUsed || []) {
1507
+ if (extensionsWithPropertyTables.includes(extensionItem)) {
1508
+ extensionName = extensionItem;
1509
+ break;
1510
+ }
1511
+ }
1512
+
1513
+ const extension = tileContent?.gltf?.extensions?.[extensionName];
1514
+
1515
+ return {extensionName, extension};
1516
+ }
1517
+
1518
+ /**
1519
+ * Handle EXT_feature_metadata to get property table
1520
+ * @param extension
1521
+ * TODO add EXT_feature_metadata feature textures support.
1522
+ */
1523
+ function getPropertyTableFromExtFeatureMetadata(
1524
+ extension: GLTF_EXT_feature_metadata
1525
+ ): FeatureTableJson | null {
1526
+ if (extension?.featureTextures) {
1527
+ console.warn(
1528
+ 'The I3S converter does not yet support the EXT_feature_metadata feature textures'
1529
+ );
1530
+ return null;
1531
+ }
1532
+
1533
+ if (extension?.featureTables) {
1534
+ /**
1535
+ * Take only first feature table to generate attributes storage info object.
1536
+ * TODO: Think about getting data from all feature tables?
1537
+ * It can be tricky just because 3dTiles is able to have multiple featureId attributes and multiple feature tables.
1538
+ * In I3S we should decide which featureIds attribute will be passed to geometry data.
1539
+ */
1540
+ const firstFeatureTableName = Object.keys(extension.featureTables)?.[0];
1541
+
1542
+ if (firstFeatureTableName) {
1543
+ const featureTable = extension?.featureTables[firstFeatureTableName];
1544
+ const propertyTable = {};
1545
+
1546
+ for (const propertyName in featureTable.properties) {
1547
+ propertyTable[propertyName] = featureTable.properties[propertyName].data;
1548
+ }
1549
+
1550
+ return propertyTable;
1551
+ }
1552
+ }
1553
+
1554
+ console.warn("The I3S converter couldn't handle EXT_feature_metadata extension");
1555
+ return null;
1556
+ }