@cesium/engine 7.0.0 → 9.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (200) hide show
  1. package/Build/ThirdParty/Workers/z-worker-pako.js +1 -5
  2. package/Build/Workers/{chunk-7XEAYGZK.js → chunk-24YTYWNB.js} +10 -10
  3. package/Build/Workers/{chunk-IQBYFRVW.js → chunk-2632RVPI.js} +7 -7
  4. package/Build/Workers/chunk-2KACWKS4.js +501 -0
  5. package/Build/Workers/{chunk-QZAD5O7I.js → chunk-2XPLH3JY.js} +7 -7
  6. package/Build/Workers/{chunk-JY5YEZFA.js → chunk-2ZBL3MVO.js} +8 -8
  7. package/Build/Workers/{chunk-ZK5JOS3D.js → chunk-3NCVAGDA.js} +14 -14
  8. package/Build/Workers/{chunk-AR5DNBJ4.js → chunk-5R6VWLMH.js} +6 -6
  9. package/Build/Workers/{chunk-PTQQUQC3.js → chunk-5TIV3L26.js} +13 -13
  10. package/Build/Workers/{chunk-BZP4T2JJ.js → chunk-6WF3KIF5.js} +10 -10
  11. package/Build/Workers/{chunk-5WQ523AW.js → chunk-73FKKY52.js} +5 -5
  12. package/Build/Workers/{chunk-F6SE42BK.js → chunk-7COR472O.js} +15 -472
  13. package/Build/Workers/{chunk-72SANQJV.js → chunk-ADOVHYWO.js} +9 -5
  14. package/Build/Workers/{chunk-5YLJ77FF.js → chunk-BCU2LH5T.js} +12 -11
  15. package/Build/Workers/{chunk-4EBHOMFX.js → chunk-C3XBUYBO.js} +17 -17
  16. package/Build/Workers/{chunk-IX2JCCNM.js → chunk-C6OI26DR.js} +1 -1
  17. package/Build/Workers/{chunk-2HJWSU7B.js → chunk-CO35JNNE.js} +4 -4
  18. package/Build/Workers/{chunk-OVLG3FRS.js → chunk-DGDUKCJJ.js} +6 -6
  19. package/Build/Workers/{chunk-DTAIXKTO.js → chunk-DPUSFA7S.js} +6 -6
  20. package/Build/Workers/{chunk-R5X4OQT4.js → chunk-E6WXPSJS.js} +7 -7
  21. package/Build/Workers/{chunk-VK3EJHWI.js → chunk-EOXYZ34O.js} +2 -2
  22. package/Build/Workers/{chunk-RAEV7K66.js → chunk-EPKE7GE3.js} +5 -5
  23. package/Build/Workers/{chunk-GV56Q4LU.js → chunk-GFA4SMXV.js} +11 -11
  24. package/Build/Workers/{chunk-NKPBIX7F.js → chunk-GXUXEOE2.js} +1 -1
  25. package/Build/Workers/{chunk-NY3K4IM3.js → chunk-HBQPB6IH.js} +12 -12
  26. package/Build/Workers/{chunk-6HZQPRUS.js → chunk-I37B3MZ2.js} +1 -1
  27. package/Build/Workers/{chunk-VRGFV2UO.js → chunk-L4BW3RUA.js} +10 -10
  28. package/Build/Workers/{chunk-6VJVYK2V.js → chunk-LAQP3SCC.js} +2 -2
  29. package/Build/Workers/{chunk-PNBGBETF.js → chunk-LQJ5FFFR.js} +10 -10
  30. package/Build/Workers/{chunk-UAEW6HKG.js → chunk-M2AYBTNH.js} +13 -13
  31. package/Build/Workers/{chunk-YUCVWAY6.js → chunk-MWV7IZK4.js} +7 -7
  32. package/Build/Workers/{chunk-JXDC723O.js → chunk-N4KXMWQU.js} +2 -2
  33. package/Build/Workers/{chunk-XWXM2O2R.js → chunk-NP2GYYE5.js} +6 -6
  34. package/Build/Workers/{chunk-GEJTYLCO.js → chunk-NZWNZA6S.js} +5 -5
  35. package/Build/Workers/{chunk-LZGHD6NY.js → chunk-P2YAAMT2.js} +15 -15
  36. package/Build/Workers/{chunk-S6SKF6DT.js → chunk-P4XKB3QZ.js} +5 -5
  37. package/Build/Workers/{chunk-U2VCRRQW.js → chunk-PXB7T27O.js} +6 -6
  38. package/Build/Workers/{chunk-RV7ZYPFT.js → chunk-QCQUZGXI.js} +4 -4
  39. package/Build/Workers/{chunk-JJ4VBOQ3.js → chunk-QKBGRKKG.js} +4 -4
  40. package/Build/Workers/{chunk-ODW7WYM4.js → chunk-RMOEYCZW.js} +2 -2
  41. package/Build/Workers/{chunk-ZUA2UUNV.js → chunk-RSJXEO2A.js} +2 -2
  42. package/Build/Workers/{chunk-UDO6BFSF.js → chunk-RV7ZOSS6.js} +13 -13
  43. package/Build/Workers/{chunk-LZ7JIV3K.js → chunk-SE4PXOEA.js} +17 -17
  44. package/Build/Workers/{chunk-S4MAZ3SS.js → chunk-SS4ESNE3.js} +2 -2
  45. package/Build/Workers/{chunk-AIPU2VSX.js → chunk-TJBU6GML.js} +6 -6
  46. package/Build/Workers/{chunk-5M3U6ZMA.js → chunk-TZORKRNK.js} +1 -1
  47. package/Build/Workers/{chunk-MY3VNFGQ.js → chunk-VR5RBW52.js} +7 -7
  48. package/Build/Workers/{chunk-FP6GYBFX.js → chunk-WHUSTDIB.js} +10 -10
  49. package/Build/Workers/{chunk-5HDYHG3F.js → chunk-X2F6BEPY.js} +13 -13
  50. package/Build/Workers/{chunk-WZU2YLWG.js → chunk-X6XOMPWL.js} +3 -3
  51. package/Build/Workers/{chunk-UGK3FCDY.js → chunk-YDVSBWEO.js} +1 -1
  52. package/Build/Workers/{chunk-46UD5ABS.js → chunk-YV4H2Y7M.js} +4 -4
  53. package/Build/Workers/{chunk-WBQCVXR3.js → chunk-Z7FQLK6N.js} +4 -4
  54. package/Build/Workers/{chunk-L2ZN645J.js → chunk-ZNVSKMQ2.js} +6 -6
  55. package/Build/Workers/{chunk-JCNXK6EL.js → chunk-ZYPTP7GS.js} +11 -11
  56. package/Build/Workers/combineGeometry.js +24 -23
  57. package/Build/Workers/createBoxGeometry.js +18 -17
  58. package/Build/Workers/createBoxOutlineGeometry.js +16 -15
  59. package/Build/Workers/createCircleGeometry.js +26 -25
  60. package/Build/Workers/createCircleOutlineGeometry.js +19 -18
  61. package/Build/Workers/createCoplanarPolygonGeometry.js +33 -32
  62. package/Build/Workers/createCoplanarPolygonOutlineGeometry.js +31 -30
  63. package/Build/Workers/createCorridorGeometry.js +29 -28
  64. package/Build/Workers/createCorridorOutlineGeometry.js +28 -27
  65. package/Build/Workers/createCylinderGeometry.js +20 -19
  66. package/Build/Workers/createCylinderOutlineGeometry.js +18 -17
  67. package/Build/Workers/createEllipseGeometry.js +26 -25
  68. package/Build/Workers/createEllipseOutlineGeometry.js +19 -18
  69. package/Build/Workers/createEllipsoidGeometry.js +19 -18
  70. package/Build/Workers/createEllipsoidOutlineGeometry.js +18 -17
  71. package/Build/Workers/createFrustumGeometry.js +18 -17
  72. package/Build/Workers/createFrustumOutlineGeometry.js +18 -17
  73. package/Build/Workers/createGeometry.js +54 -33
  74. package/Build/Workers/createGroundPolylineGeometry.js +22 -21
  75. package/Build/Workers/createPlaneGeometry.js +16 -15
  76. package/Build/Workers/createPlaneOutlineGeometry.js +15 -14
  77. package/Build/Workers/createPolygonGeometry.js +33 -32
  78. package/Build/Workers/createPolygonOutlineGeometry.js +30 -29
  79. package/Build/Workers/createPolylineGeometry.js +25 -24
  80. package/Build/Workers/createPolylineVolumeGeometry.js +31 -30
  81. package/Build/Workers/createPolylineVolumeOutlineGeometry.js +27 -26
  82. package/Build/Workers/createRectangleGeometry.js +27 -26
  83. package/Build/Workers/createRectangleOutlineGeometry.js +20 -19
  84. package/Build/Workers/createSimplePolylineGeometry.js +23 -22
  85. package/Build/Workers/createSphereGeometry.js +19 -18
  86. package/Build/Workers/createSphereOutlineGeometry.js +18 -17
  87. package/Build/Workers/createTaskProcessorWorker.js +3 -3
  88. package/Build/Workers/createVectorTileClampedPolylines.js +14 -14
  89. package/Build/Workers/createVectorTileGeometries.js +24 -23
  90. package/Build/Workers/createVectorTilePoints.js +12 -12
  91. package/Build/Workers/createVectorTilePolygons.js +22 -21
  92. package/Build/Workers/createVectorTilePolylines.js +14 -14
  93. package/Build/Workers/createVerticesFromGoogleEarthEnterpriseBuffer.js +22 -21
  94. package/Build/Workers/createVerticesFromHeightmap.js +22 -21
  95. package/Build/Workers/createVerticesFromQuantizedTerrainMesh.js +19 -18
  96. package/Build/Workers/createWallGeometry.js +24 -23
  97. package/Build/Workers/createWallOutlineGeometry.js +23 -22
  98. package/Build/Workers/decodeDraco.js +11 -11
  99. package/Build/Workers/decodeGoogleEarthEnterprisePacket.js +5 -5
  100. package/Build/Workers/decodeI3S.js +601 -92
  101. package/Build/Workers/transcodeKTX2.js +7 -7
  102. package/Build/Workers/transferTypedArrayTest.js +1 -1
  103. package/Build/Workers/upsampleQuantizedTerrainMesh.js +22 -21
  104. package/Source/Core/Check.d.ts +127 -0
  105. package/Source/Core/Check.js +0 -1
  106. package/Source/Core/Ellipsoid.js +6 -0
  107. package/Source/Core/Geometry.js +1 -1
  108. package/Source/Core/IntersectionTests.js +6 -3
  109. package/Source/Core/Ion.js +1 -1
  110. package/Source/Core/PixelFormat.js +5 -0
  111. package/Source/Core/PolygonGeometry.js +1 -1
  112. package/Source/Core/Transforms.js +3 -0
  113. package/Source/Core/VerticalExaggeration.js +2 -1
  114. package/Source/Core/srgbToLinear.js +32 -0
  115. package/Source/DataSources/CzmlDataSource.js +51 -23
  116. package/Source/DataSources/DataSourceDisplay.js +27 -0
  117. package/Source/DataSources/Entity.js +20 -2
  118. package/Source/DataSources/GeometryUpdaterSet.js +114 -0
  119. package/Source/DataSources/GeometryVisualizer.js +19 -83
  120. package/Source/Renderer/Context.js +10 -0
  121. package/Source/Renderer/ContextLimits.js +2 -0
  122. package/Source/Renderer/demodernizeShader.js +4 -1
  123. package/Source/Scene/ArcGisMapService.js +1 -1
  124. package/Source/Scene/Axis.js +12 -7
  125. package/Source/Scene/Billboard.js +32 -0
  126. package/Source/Scene/BillboardCollection.js +1 -1
  127. package/Source/Scene/BingMapsImageryProvider.js +4 -0
  128. package/Source/Scene/Camera.js +46 -4
  129. package/Source/Scene/Cesium3DTilesVoxelProvider.js +2 -9
  130. package/Source/Scene/Cesium3DTileset.js +10 -7
  131. package/Source/Scene/Cesium3DTilesetBaseTraversal.js +2 -4
  132. package/Source/Scene/FrameState.js +5 -0
  133. package/Source/Scene/Globe.js +0 -67
  134. package/Source/Scene/GlobeTranslucencyState.js +1 -1
  135. package/Source/Scene/GltfPipeline/updateVersion.js +69 -68
  136. package/Source/Scene/I3SDataProvider.js +270 -53
  137. package/Source/Scene/I3SDecoder.js +8 -1
  138. package/Source/Scene/I3SFeature.js +2 -5
  139. package/Source/Scene/I3SField.js +136 -31
  140. package/Source/Scene/I3SGeometry.js +70 -2
  141. package/Source/Scene/I3SLayer.js +55 -10
  142. package/Source/Scene/I3SNode.js +175 -18
  143. package/Source/Scene/I3SStatistics.js +94 -0
  144. package/Source/Scene/I3SSublayer.js +176 -0
  145. package/Source/Scene/I3SSymbology.js +337 -0
  146. package/Source/Scene/KeyframeNode.js +1 -1
  147. package/Source/Scene/Label.js +33 -0
  148. package/Source/Scene/LabelCollection.js +2 -1
  149. package/Source/Scene/Model/pickModel.js +25 -7
  150. package/Source/Scene/PickFramebuffer.js +37 -2
  151. package/Source/Scene/Picking.js +113 -39
  152. package/Source/Scene/Primitive.js +6 -5
  153. package/Source/Scene/Scene.js +126 -42
  154. package/Source/Scene/ScreenSpaceCameraController.js +21 -7
  155. package/Source/Scene/SensorVolumePortionToDisplay.js +69 -0
  156. package/Source/Scene/SpatialNode.js +12 -19
  157. package/Source/Scene/StructuralMetadata.js +1 -1
  158. package/Source/Scene/VoxelBoxShape.js +67 -6
  159. package/Source/Scene/VoxelCell.js +273 -0
  160. package/Source/Scene/VoxelCylinderShape.js +117 -163
  161. package/Source/Scene/VoxelEllipsoidShape.js +255 -304
  162. package/Source/Scene/VoxelPrimitive.js +109 -15
  163. package/Source/Scene/VoxelRenderResources.js +12 -3
  164. package/Source/Scene/VoxelShape.js +7 -4
  165. package/Source/Scene/VoxelTraversal.js +76 -54
  166. package/Source/Scene/buildVoxelDrawCommands.js +23 -0
  167. package/Source/Scene/createGooglePhotorealistic3DTileset.js +1 -0
  168. package/Source/Scene/processVoxelProperties.js +3 -0
  169. package/Source/Shaders/Voxels/IntersectBox.glsl +21 -47
  170. package/Source/Shaders/Voxels/IntersectBox.js +21 -47
  171. package/Source/Shaders/Voxels/IntersectClippingPlanes.glsl +1 -1
  172. package/Source/Shaders/Voxels/IntersectClippingPlanes.js +1 -1
  173. package/Source/Shaders/Voxels/IntersectCylinder.glsl +76 -203
  174. package/Source/Shaders/Voxels/IntersectCylinder.js +76 -203
  175. package/Source/Shaders/Voxels/IntersectEllipsoid.glsl +220 -229
  176. package/Source/Shaders/Voxels/IntersectEllipsoid.js +220 -229
  177. package/Source/Shaders/Voxels/IntersectLongitude.glsl +102 -0
  178. package/Source/Shaders/Voxels/IntersectLongitude.js +104 -0
  179. package/Source/Shaders/Voxels/IntersectionUtils.glsl +33 -11
  180. package/Source/Shaders/Voxels/IntersectionUtils.js +33 -11
  181. package/Source/Shaders/Voxels/Megatexture.glsl +1 -2
  182. package/Source/Shaders/Voxels/Megatexture.js +1 -2
  183. package/Source/Shaders/Voxels/Octree.glsl +14 -9
  184. package/Source/Shaders/Voxels/Octree.js +14 -9
  185. package/Source/Shaders/Voxels/VoxelFS.glsl +128 -40
  186. package/Source/Shaders/Voxels/VoxelFS.js +128 -40
  187. package/Source/Shaders/Voxels/VoxelUtils.glsl +31 -0
  188. package/Source/Shaders/Voxels/VoxelUtils.js +33 -0
  189. package/Source/Shaders/Voxels/convertUvToBox.glsl +24 -3
  190. package/Source/Shaders/Voxels/convertUvToBox.js +24 -4
  191. package/Source/Shaders/Voxels/convertUvToCylinder.glsl +64 -40
  192. package/Source/Shaders/Voxels/convertUvToCylinder.js +64 -40
  193. package/Source/Shaders/Voxels/convertUvToEllipsoid.glsl +100 -91
  194. package/Source/Shaders/Voxels/convertUvToEllipsoid.js +100 -91
  195. package/Source/ThirdParty/Workers/z-worker-pako.js +1 -1
  196. package/Source/Workers/createGeometry.js +40 -11
  197. package/Source/Workers/decodeI3S.js +720 -94
  198. package/index.d.ts +542 -40
  199. package/index.js +75 -66
  200. package/package.json +2 -2
@@ -1,12 +1,15 @@
1
1
  import createTaskProcessorWorker from "./createTaskProcessorWorker.js";
2
+ import defaultValue from "../Core/defaultValue.js";
2
3
  import defined from "../Core/defined.js";
3
4
  import WebMercatorProjection from "../Core/WebMercatorProjection.js";
4
5
  import Ellipsoid from "../Core/Ellipsoid.js";
5
6
  import Cartographic from "../Core/Cartographic.js";
6
7
  import Cartesian3 from "../Core/Cartesian3.js";
8
+ import Color from "../Core/Color.js";
7
9
  import Matrix3 from "../Core/Matrix3.js";
8
10
  import CesiumMath from "../Core/Math.js";
9
11
  import dracoModule from "draco3d/draco_decoder_nodejs.js";
12
+ import srgbToLinear from "../Core/srgbToLinear.js";
10
13
 
11
14
  let draco;
12
15
 
@@ -196,13 +199,440 @@ function cropUVs(vertexCount, uv0s, uvRegions) {
196
199
  }
197
200
  }
198
201
 
202
+ function generateIndexArray(
203
+ vertexCount,
204
+ indices,
205
+ colors,
206
+ splitGeometryByColorTransparency
207
+ ) {
208
+ // Allocate array
209
+ const indexArray = new Uint32Array(vertexCount);
210
+ const vertexIndexFn = defined(indices)
211
+ ? (vertexIndex) => indices[vertexIndex]
212
+ : (vertexIndex) => vertexIndex;
213
+
214
+ let transparentVertexOffset = 0;
215
+ if (splitGeometryByColorTransparency && defined(colors)) {
216
+ // The blending alpha mode for opaque colors is not rendered properly.
217
+ // If geometry contains both opaque and transparent colors we need to split vertices into two mesh primitives.
218
+ // Each mesh primitive could use a separate material with the specific alpha mode depending on the vertex trancparency.
219
+ const isVertexTransparentFn = (vertexIndex) =>
220
+ colors[vertexIndexFn(vertexIndex) * 4 + 3] < 255;
221
+ // Copy opaque vertices first
222
+ for (let vertexIndex = 0; vertexIndex < vertexCount; vertexIndex += 3) {
223
+ if (
224
+ !isVertexTransparentFn(vertexIndex) &&
225
+ !isVertexTransparentFn(vertexIndex + 1) &&
226
+ !isVertexTransparentFn(vertexIndex + 2)
227
+ ) {
228
+ indexArray[transparentVertexOffset++] = vertexIndexFn(vertexIndex);
229
+ indexArray[transparentVertexOffset++] = vertexIndexFn(vertexIndex + 1);
230
+ indexArray[transparentVertexOffset++] = vertexIndexFn(vertexIndex + 2);
231
+ }
232
+ }
233
+ if (transparentVertexOffset > 0) {
234
+ // Copy transparent vertices
235
+ let offset = transparentVertexOffset;
236
+ for (let vertexIndex = 0; vertexIndex < vertexCount; vertexIndex += 3) {
237
+ if (
238
+ isVertexTransparentFn(vertexIndex) ||
239
+ isVertexTransparentFn(vertexIndex + 1) ||
240
+ isVertexTransparentFn(vertexIndex + 2)
241
+ ) {
242
+ indexArray[offset++] = vertexIndexFn(vertexIndex);
243
+ indexArray[offset++] = vertexIndexFn(vertexIndex + 1);
244
+ indexArray[offset++] = vertexIndexFn(vertexIndex + 2);
245
+ }
246
+ }
247
+ } else {
248
+ // All vertices are tranparent
249
+ for (let vertexIndex = 0; vertexIndex < vertexCount; ++vertexIndex) {
250
+ indexArray[vertexIndex] = vertexIndexFn(vertexIndex);
251
+ }
252
+ }
253
+ } else {
254
+ // All vertices are considered opaque
255
+ transparentVertexOffset = vertexCount;
256
+ for (let vertexIndex = 0; vertexIndex < vertexCount; ++vertexIndex) {
257
+ indexArray[vertexIndex] = vertexIndexFn(vertexIndex);
258
+ }
259
+ }
260
+
261
+ return {
262
+ indexArray: indexArray,
263
+ transparentVertexOffset: transparentVertexOffset,
264
+ };
265
+ }
266
+
267
+ function getFeatureHash(symbologyData, outlinesHash, featureIndex) {
268
+ const featureHash = outlinesHash[featureIndex];
269
+ if (defined(featureHash)) {
270
+ return featureHash;
271
+ }
272
+ const newFeatureHash = (outlinesHash[featureIndex] = {
273
+ positions: {},
274
+ indices: {},
275
+ edges: {},
276
+ });
277
+ const featureSymbology = defaultValue(
278
+ symbologyData[featureIndex],
279
+ symbologyData.default
280
+ );
281
+ newFeatureHash.hasOutline = defined(featureSymbology?.edges);
282
+ return newFeatureHash;
283
+ }
284
+
285
+ function addVertexToHash(indexHash, positionHash, vertexIndex, positions) {
286
+ if (!defined(indexHash[vertexIndex])) {
287
+ const startPositionIndex = vertexIndex * 3;
288
+ let coordinateHash = positionHash;
289
+ for (let index = 0; index < 3; index++) {
290
+ const coordinate = positions[startPositionIndex + index];
291
+ if (!defined(coordinateHash[coordinate])) {
292
+ coordinateHash[coordinate] = {};
293
+ }
294
+ coordinateHash = coordinateHash[coordinate];
295
+ }
296
+ if (!defined(coordinateHash.index)) {
297
+ coordinateHash.index = vertexIndex;
298
+ }
299
+ indexHash[vertexIndex] = coordinateHash.index;
300
+ }
301
+ }
302
+
303
+ function addEdgeToHash(
304
+ edgeHash,
305
+ vertexAIndex,
306
+ vertexBIndex,
307
+ vertexAIndexUnique,
308
+ vertexBIndexUnique,
309
+ normalIndex
310
+ ) {
311
+ let startVertexIndex;
312
+ let endVertexIndex;
313
+ if (vertexAIndexUnique < vertexBIndexUnique) {
314
+ startVertexIndex = vertexAIndexUnique;
315
+ endVertexIndex = vertexBIndexUnique;
316
+ } else {
317
+ startVertexIndex = vertexBIndexUnique;
318
+ endVertexIndex = vertexAIndexUnique;
319
+ }
320
+ let edgeStart = edgeHash[startVertexIndex];
321
+ if (!defined(edgeStart)) {
322
+ edgeStart = edgeHash[startVertexIndex] = {};
323
+ }
324
+ let edgeEnd = edgeStart[endVertexIndex];
325
+ if (!defined(edgeEnd)) {
326
+ edgeEnd = edgeStart[endVertexIndex] = {
327
+ normalsIndex: [],
328
+ outlines: [],
329
+ };
330
+ }
331
+ edgeEnd.normalsIndex.push(normalIndex);
332
+ if (
333
+ edgeEnd.outlines.length === 0 ||
334
+ vertexAIndex !== vertexAIndexUnique ||
335
+ vertexBIndex !== vertexBIndexUnique
336
+ ) {
337
+ edgeEnd.outlines.push(vertexAIndex, vertexBIndex);
338
+ }
339
+ }
340
+
341
+ function generateOutlinesHash(
342
+ symbologyData,
343
+ featureIndexArray,
344
+ indexArray,
345
+ positions
346
+ ) {
347
+ const outlinesHash = [];
348
+ for (let i = 0; i < indexArray.length; i += 3) {
349
+ const featureIndex = defined(featureIndexArray)
350
+ ? featureIndexArray[indexArray[i]]
351
+ : "default";
352
+ const featureHash = getFeatureHash(
353
+ symbologyData,
354
+ outlinesHash,
355
+ featureIndex
356
+ );
357
+ if (!featureHash.hasOutline) {
358
+ continue;
359
+ }
360
+
361
+ const indexHash = featureHash.indices;
362
+ const positionHash = featureHash.positions;
363
+ for (let vertex = 0; vertex < 3; vertex++) {
364
+ const vertexIndex = indexArray[i + vertex];
365
+ addVertexToHash(indexHash, positionHash, vertexIndex, positions);
366
+ }
367
+
368
+ const edgeHash = featureHash.edges;
369
+ for (let vertex = 0; vertex < 3; vertex++) {
370
+ const vertexIndex = indexArray[i + vertex];
371
+ const nextVertexIndex = indexArray[i + ((vertex + 1) % 3)];
372
+ const uniqueVertexIndex = indexHash[vertexIndex];
373
+ const uniqueNextVertexIndex = indexHash[nextVertexIndex];
374
+ addEdgeToHash(
375
+ edgeHash,
376
+ vertexIndex,
377
+ nextVertexIndex,
378
+ uniqueVertexIndex,
379
+ uniqueNextVertexIndex,
380
+ i
381
+ );
382
+ }
383
+ }
384
+ return outlinesHash;
385
+ }
386
+
387
+ const calculateFaceNormalA = new Cartesian3();
388
+ const calculateFaceNormalB = new Cartesian3();
389
+ const calculateFaceNormalC = new Cartesian3();
390
+ function calculateFaceNormal(normals, vertexAIndex, indexArray, positions) {
391
+ const positionAIndex = indexArray[vertexAIndex] * 3;
392
+ const positionBIndex = indexArray[vertexAIndex + 1] * 3;
393
+ const positionCIndex = indexArray[vertexAIndex + 2] * 3;
394
+ Cartesian3.fromArray(positions, positionAIndex, calculateFaceNormalA);
395
+ Cartesian3.fromArray(positions, positionBIndex, calculateFaceNormalB);
396
+ Cartesian3.fromArray(positions, positionCIndex, calculateFaceNormalC);
397
+
398
+ Cartesian3.subtract(
399
+ calculateFaceNormalB,
400
+ calculateFaceNormalA,
401
+ calculateFaceNormalB
402
+ );
403
+ Cartesian3.subtract(
404
+ calculateFaceNormalC,
405
+ calculateFaceNormalA,
406
+ calculateFaceNormalC
407
+ );
408
+ Cartesian3.cross(
409
+ calculateFaceNormalB,
410
+ calculateFaceNormalC,
411
+ calculateFaceNormalA
412
+ );
413
+ const magnitude = Cartesian3.magnitude(calculateFaceNormalA);
414
+ if (magnitude !== 0) {
415
+ Cartesian3.divideByScalar(
416
+ calculateFaceNormalA,
417
+ magnitude,
418
+ calculateFaceNormalA
419
+ );
420
+ }
421
+ const normalAIndex = vertexAIndex * 3;
422
+ const normalBIndex = (vertexAIndex + 1) * 3;
423
+ const normalCIndex = (vertexAIndex + 2) * 3;
424
+ Cartesian3.pack(calculateFaceNormalA, normals, normalAIndex);
425
+ Cartesian3.pack(calculateFaceNormalA, normals, normalBIndex);
426
+ Cartesian3.pack(calculateFaceNormalA, normals, normalCIndex);
427
+ }
428
+
429
+ const isEdgeSmoothA = new Cartesian3();
430
+ const isEdgeSmoothB = new Cartesian3();
431
+ function isEdgeSmooth(normals, normalAIndex, normalBIndex) {
432
+ Cartesian3.fromArray(normals, normalAIndex, isEdgeSmoothA);
433
+ Cartesian3.fromArray(normals, normalBIndex, isEdgeSmoothB);
434
+ const cosine = Cartesian3.dot(isEdgeSmoothA, isEdgeSmoothB);
435
+ const sine = Cartesian3.magnitude(
436
+ Cartesian3.cross(isEdgeSmoothA, isEdgeSmoothB, isEdgeSmoothA)
437
+ );
438
+ return Math.atan2(sine, cosine) < 0.25;
439
+ }
440
+
441
+ function addOutlinesForEdge(
442
+ outlines,
443
+ edgeData,
444
+ indexArray,
445
+ positions,
446
+ normals
447
+ ) {
448
+ if (edgeData.normalsIndex.length > 1) {
449
+ const normalsByIndex = positions.length === normals.length;
450
+ for (let indexA = 0; indexA < edgeData.normalsIndex.length; indexA++) {
451
+ const vertexAIndex = edgeData.normalsIndex[indexA];
452
+ if (!defined(normals[vertexAIndex * 3])) {
453
+ calculateFaceNormal(normals, vertexAIndex, indexArray, positions);
454
+ }
455
+ if (indexA === 0) {
456
+ continue;
457
+ }
458
+ for (let indexB = 0; indexB < indexA; indexB++) {
459
+ const vertexBIndex = edgeData.normalsIndex[indexB];
460
+ const normalAIndex = normalsByIndex
461
+ ? indexArray[vertexAIndex] * 3
462
+ : vertexAIndex * 3;
463
+ const normalBIndex = normalsByIndex
464
+ ? indexArray[vertexBIndex] * 3
465
+ : vertexBIndex * 3;
466
+ if (isEdgeSmooth(normals, normalAIndex, normalBIndex)) {
467
+ return;
468
+ }
469
+ }
470
+ }
471
+ }
472
+ outlines.push(...edgeData.outlines);
473
+ }
474
+
475
+ function addOutlinesForFeature(
476
+ outlines,
477
+ edgeHash,
478
+ indexArray,
479
+ positions,
480
+ normals
481
+ ) {
482
+ const edgeStartKeys = Object.keys(edgeHash);
483
+ for (let startIndex = 0; startIndex < edgeStartKeys.length; startIndex++) {
484
+ const edgeEnds = edgeHash[edgeStartKeys[startIndex]];
485
+ const edgeEndKeys = Object.keys(edgeEnds);
486
+ for (let endIndex = 0; endIndex < edgeEndKeys.length; endIndex++) {
487
+ const edgeData = edgeEnds[edgeEndKeys[endIndex]];
488
+ addOutlinesForEdge(outlines, edgeData, indexArray, positions, normals);
489
+ }
490
+ }
491
+ }
492
+
493
+ function generateOutlinesFromHash(
494
+ outlinesHash,
495
+ indexArray,
496
+ positions,
497
+ normals
498
+ ) {
499
+ const outlines = [];
500
+ const features = Object.keys(outlinesHash);
501
+ for (let featureIndex = 0; featureIndex < features.length; featureIndex++) {
502
+ const edgeHash = outlinesHash[features[featureIndex]].edges;
503
+ addOutlinesForFeature(outlines, edgeHash, indexArray, positions, normals);
504
+ }
505
+ return outlines;
506
+ }
507
+
508
+ function generateOutlinesIndexArray(
509
+ symbologyData,
510
+ featureIndexArray,
511
+ indexArray,
512
+ positions,
513
+ normals
514
+ ) {
515
+ if (!defined(symbologyData) || Object.keys(symbologyData).length === 0) {
516
+ return undefined;
517
+ }
518
+ const outlinesHash = generateOutlinesHash(
519
+ symbologyData,
520
+ featureIndexArray,
521
+ indexArray,
522
+ positions
523
+ );
524
+ if (!defined(normals) || indexArray.length * 3 !== normals.length) {
525
+ // Need to calculate flat normals per faces
526
+ normals = [];
527
+ }
528
+ const outlines = generateOutlinesFromHash(
529
+ outlinesHash,
530
+ indexArray,
531
+ positions,
532
+ normals
533
+ );
534
+ const outlinesIndexArray =
535
+ outlines.length > 0 ? new Uint32Array(outlines) : undefined;
536
+ return outlinesIndexArray;
537
+ }
538
+
539
+ function convertColorsArray(colors) {
540
+ // Colors are assumed to be normalized sRGB [0,255] while in glTF they are interpreted as linear.
541
+ // All values RGBA need to be stored as float to keep the precision after sRGB to linear conversion.
542
+ const colorsArray = new Float32Array(colors.length);
543
+ for (let index = 0; index < colors.length; index += 4) {
544
+ colorsArray[index] = srgbToLinear(Color.byteToFloat(colors[index]));
545
+ colorsArray[index + 1] = srgbToLinear(Color.byteToFloat(colors[index + 1]));
546
+ colorsArray[index + 2] = srgbToLinear(Color.byteToFloat(colors[index + 2]));
547
+ colorsArray[index + 3] = Color.byteToFloat(colors[index + 3]);
548
+ }
549
+ return colorsArray;
550
+ }
551
+
552
+ function generateNormals(
553
+ vertexCount,
554
+ indices,
555
+ positions,
556
+ normals,
557
+ uv0s,
558
+ colors,
559
+ featureIndex
560
+ ) {
561
+ const result = {
562
+ normals: undefined,
563
+ positions: undefined,
564
+ uv0s: undefined,
565
+ colors: undefined,
566
+ featureIndex: undefined,
567
+ vertexCount: undefined,
568
+ };
569
+ if (
570
+ vertexCount === 0 ||
571
+ !defined(positions) ||
572
+ positions.length === 0 ||
573
+ defined(normals)
574
+ ) {
575
+ return result;
576
+ }
577
+
578
+ if (defined(indices)) {
579
+ result.vertexCount = indices.length;
580
+ result.positions = new Float32Array(indices.length * 3);
581
+ result.uv0s = defined(uv0s)
582
+ ? new Float32Array(indices.length * 2)
583
+ : undefined;
584
+ result.colors = defined(colors)
585
+ ? new Uint8Array(indices.length * 4)
586
+ : undefined;
587
+ result.featureIndex = defined(featureIndex)
588
+ ? new Array(indices.length)
589
+ : undefined;
590
+ for (let i = 0; i < indices.length; i++) {
591
+ const index = indices[i];
592
+ result.positions[i * 3] = positions[index * 3];
593
+ result.positions[i * 3 + 1] = positions[index * 3 + 1];
594
+ result.positions[i * 3 + 2] = positions[index * 3 + 2];
595
+ if (defined(result.uv0s)) {
596
+ result.uv0s[i * 2] = uv0s[index * 2];
597
+ result.uv0s[i * 2 + 1] = uv0s[index * 2 + 1];
598
+ }
599
+ if (defined(result.colors)) {
600
+ result.colors[i * 4] = colors[index * 4];
601
+ result.colors[i * 4 + 1] = colors[index * 4 + 1];
602
+ result.colors[i * 4 + 2] = colors[index * 4 + 2];
603
+ result.colors[i * 4 + 3] = colors[index * 4 + 3];
604
+ }
605
+ if (defined(result.featureIndex)) {
606
+ result.featureIndex[i] = featureIndex[index];
607
+ }
608
+ }
609
+
610
+ vertexCount = indices.length;
611
+ positions = result.positions;
612
+ }
613
+
614
+ indices = new Array(vertexCount);
615
+ for (let i = 0; i < vertexCount; i++) {
616
+ indices[i] = i;
617
+ }
618
+
619
+ result.normals = new Float32Array(indices.length * 3);
620
+ for (let i = 0; i < indices.length; i += 3) {
621
+ calculateFaceNormal(result.normals, i, indices, positions);
622
+ }
623
+
624
+ return result;
625
+ }
626
+
199
627
  function generateGltfBuffer(
200
628
  vertexCount,
201
629
  indices,
202
630
  positions,
203
631
  normals,
204
632
  uv0s,
205
- colors
633
+ colors,
634
+ featureIndex,
635
+ parameters
206
636
  ) {
207
637
  if (vertexCount === 0 || !defined(positions) || positions.length === 0) {
208
638
  return {
@@ -221,6 +651,8 @@ function generateGltfBuffer(
221
651
  const meshes = [];
222
652
  const nodes = [];
223
653
  const nodesInScene = [];
654
+ const rootExtensions = {};
655
+ const extensionsUsed = [];
224
656
 
225
657
  // If we provide indices, then the vertex count is the length
226
658
  // of that array, otherwise we assume non-indexed triangle
@@ -228,24 +660,13 @@ function generateGltfBuffer(
228
660
  vertexCount = indices.length;
229
661
  }
230
662
 
231
- // Allocate array
232
- const indexArray = new Uint32Array(vertexCount);
233
-
234
- if (defined(indices)) {
235
- // Set the indices
236
- for (let vertexIndex = 0; vertexIndex < vertexCount; ++vertexIndex) {
237
- indexArray[vertexIndex] = indices[vertexIndex];
238
- }
239
- } else {
240
- // Generate indices
241
- for (
242
- let newVertexIndex = 0;
243
- newVertexIndex < vertexCount;
244
- ++newVertexIndex
245
- ) {
246
- indexArray[newVertexIndex] = newVertexIndex;
247
- }
248
- }
663
+ // Generate index array
664
+ const { indexArray, transparentVertexOffset } = generateIndexArray(
665
+ vertexCount,
666
+ indices,
667
+ colors,
668
+ parameters.splitGeometryByColorTransparency
669
+ );
249
670
 
250
671
  // Push to the buffers, bufferViews and accessors
251
672
  const indicesBlob = new Blob([indexArray], { type: "application/binary" });
@@ -253,6 +674,40 @@ function generateGltfBuffer(
253
674
 
254
675
  const endIndex = vertexCount;
255
676
 
677
+ // Feature index array gives a higher level of detail, each feature object can be accessed separately
678
+ const featureIndexArray =
679
+ parameters.enableFeatures && defined(featureIndex)
680
+ ? new Float32Array(featureIndex.length)
681
+ : undefined;
682
+ let featureCount = 0;
683
+
684
+ if (defined(featureIndexArray)) {
685
+ for (let index = 0; index < featureIndex.length; ++index) {
686
+ featureIndexArray[index] = featureIndex[index];
687
+ const countByIndex = featureIndex[index] + 1;
688
+ if (featureCount < countByIndex) {
689
+ // Feature count is defined by the maximum feature index
690
+ featureCount = countByIndex;
691
+ }
692
+ }
693
+ }
694
+
695
+ // Outlines indices
696
+ let outlinesIndicesURL;
697
+ const outlinesIndexArray = generateOutlinesIndexArray(
698
+ parameters.symbologyData,
699
+ featureIndex,
700
+ indexArray,
701
+ positions,
702
+ normals
703
+ );
704
+ if (defined(outlinesIndexArray)) {
705
+ const outlinesIndicesBlob = new Blob([outlinesIndexArray], {
706
+ type: "application/binary",
707
+ });
708
+ outlinesIndicesURL = URL.createObjectURL(outlinesIndicesBlob);
709
+ }
710
+
256
711
  // POSITIONS
257
712
  const meshPositions = positions.subarray(0, endIndex * 3);
258
713
  const positionsBlob = new Blob([meshPositions], {
@@ -296,7 +751,7 @@ function generateGltfBuffer(
296
751
 
297
752
  // COLORS
298
753
  const meshColorsInBytes = defined(colors)
299
- ? colors.subarray(0, endIndex * 4)
754
+ ? convertColorsArray(colors.subarray(0, endIndex * 4))
300
755
  : undefined;
301
756
  let colorsURL;
302
757
  if (defined(meshColorsInBytes)) {
@@ -306,33 +761,56 @@ function generateGltfBuffer(
306
761
  colorsURL = URL.createObjectURL(colorsBlob);
307
762
  }
308
763
 
309
- const posIndex = 0;
310
- let normalIndex = 0;
311
- let uv0Index = 0;
312
- let colorIndex = 0;
313
- let indicesIndex = 0;
764
+ // _FEATURE_ID_0
765
+ // The actual feature identifiers don't make much sense for reading attribute values, it is enough to use feature index
766
+ const meshFeatureId0 = defined(featureIndexArray)
767
+ ? featureIndexArray.subarray(0, endIndex)
768
+ : undefined;
769
+ let featureId0URL;
770
+ if (defined(meshFeatureId0)) {
771
+ const featureId0Blob = new Blob([meshFeatureId0], {
772
+ type: "application/binary",
773
+ });
774
+ featureId0URL = URL.createObjectURL(featureId0Blob);
775
+ }
314
776
 
315
- let currentIndex = posIndex;
777
+ // Feature index property table
778
+ // This table has no practical use, but at least one property table is required to build a feature table
779
+ const meshPropertyTable0 = defined(featureIndexArray)
780
+ ? new Float32Array(featureCount)
781
+ : undefined;
782
+ let propertyTable0URL;
783
+ if (defined(meshPropertyTable0)) {
784
+ // This table just maps the feature index to itself
785
+ for (let index = 0; index < meshPropertyTable0.length; ++index) {
786
+ meshPropertyTable0[index] = index;
787
+ }
788
+ const propertyTable0Blob = new Blob([meshPropertyTable0], {
789
+ type: "application/binary",
790
+ });
791
+ propertyTable0URL = URL.createObjectURL(propertyTable0Blob);
792
+ }
316
793
 
317
794
  const attributes = {};
795
+ const extensions = {};
318
796
 
319
797
  // POSITIONS
320
- attributes.POSITION = posIndex;
798
+ attributes.POSITION = accessors.length;
321
799
  buffers.push({
322
800
  uri: positionsURL,
323
801
  byteLength: meshPositions.byteLength,
324
802
  });
325
803
  bufferViews.push({
326
- buffer: posIndex,
804
+ buffer: buffers.length - 1,
327
805
  byteOffset: 0,
328
806
  byteLength: meshPositions.byteLength,
329
807
  target: 34962,
330
808
  });
331
809
  accessors.push({
332
- bufferView: posIndex,
810
+ bufferView: bufferViews.length - 1,
333
811
  byteOffset: 0,
334
812
  componentType: 5126,
335
- count: vertexCount,
813
+ count: meshPositions.length / 3,
336
814
  type: "VEC3",
337
815
  max: [minX, minY, minZ],
338
816
  min: [maxX, maxY, maxZ],
@@ -340,107 +818,230 @@ function generateGltfBuffer(
340
818
 
341
819
  // NORMALS
342
820
  if (defined(normalsURL)) {
343
- ++currentIndex;
344
- normalIndex = currentIndex;
345
- attributes.NORMAL = normalIndex;
821
+ attributes.NORMAL = accessors.length;
346
822
  buffers.push({
347
823
  uri: normalsURL,
348
824
  byteLength: meshNormals.byteLength,
349
825
  });
350
826
  bufferViews.push({
351
- buffer: normalIndex,
827
+ buffer: buffers.length - 1,
352
828
  byteOffset: 0,
353
829
  byteLength: meshNormals.byteLength,
354
830
  target: 34962,
355
831
  });
356
832
  accessors.push({
357
- bufferView: normalIndex,
833
+ bufferView: bufferViews.length - 1,
358
834
  byteOffset: 0,
359
835
  componentType: 5126,
360
- count: vertexCount,
836
+ count: meshNormals.length / 3,
361
837
  type: "VEC3",
362
838
  });
363
839
  }
364
840
 
365
841
  // UV0
366
842
  if (defined(uv0URL)) {
367
- ++currentIndex;
368
- uv0Index = currentIndex;
369
- attributes.TEXCOORD_0 = uv0Index;
843
+ attributes.TEXCOORD_0 = accessors.length;
370
844
  buffers.push({
371
845
  uri: uv0URL,
372
846
  byteLength: meshUv0s.byteLength,
373
847
  });
374
848
  bufferViews.push({
375
- buffer: uv0Index,
849
+ buffer: buffers.length - 1,
376
850
  byteOffset: 0,
377
851
  byteLength: meshUv0s.byteLength,
378
852
  target: 34962,
379
853
  });
380
854
  accessors.push({
381
- bufferView: uv0Index,
855
+ bufferView: bufferViews.length - 1,
382
856
  byteOffset: 0,
383
857
  componentType: 5126,
384
- count: vertexCount,
858
+ count: meshUv0s.length / 2,
385
859
  type: "VEC2",
386
860
  });
387
861
  }
388
862
 
389
863
  // COLORS
390
864
  if (defined(colorsURL)) {
391
- ++currentIndex;
392
- colorIndex = currentIndex;
393
- attributes.COLOR_0 = colorIndex;
865
+ attributes.COLOR_0 = accessors.length;
394
866
  buffers.push({
395
867
  uri: colorsURL,
396
868
  byteLength: meshColorsInBytes.byteLength,
397
869
  });
398
870
  bufferViews.push({
399
- buffer: colorIndex,
871
+ buffer: buffers.length - 1,
400
872
  byteOffset: 0,
401
873
  byteLength: meshColorsInBytes.byteLength,
402
874
  target: 34962,
403
875
  });
404
876
  accessors.push({
405
- bufferView: colorIndex,
877
+ bufferView: bufferViews.length - 1,
406
878
  byteOffset: 0,
407
- componentType: 5121,
408
- normalized: true,
409
- count: vertexCount,
879
+ componentType: 5126,
880
+ count: meshColorsInBytes.length / 4,
410
881
  type: "VEC4",
411
882
  });
412
883
  }
413
884
 
885
+ // _FEATURE_ID_0
886
+ if (defined(featureId0URL)) {
887
+ attributes._FEATURE_ID_0 = accessors.length;
888
+ buffers.push({
889
+ uri: featureId0URL,
890
+ byteLength: meshFeatureId0.byteLength,
891
+ });
892
+ bufferViews.push({
893
+ buffer: buffers.length - 1,
894
+ byteOffset: 0,
895
+ byteLength: meshFeatureId0.byteLength,
896
+ target: 34963,
897
+ });
898
+ accessors.push({
899
+ bufferView: bufferViews.length - 1,
900
+ byteOffset: 0,
901
+ componentType: 5126,
902
+ count: meshFeatureId0.length,
903
+ type: "SCALAR",
904
+ });
905
+
906
+ // Mesh features extension associates feature ids by vertex
907
+ extensions.EXT_mesh_features = {
908
+ featureIds: [
909
+ {
910
+ attribute: 0,
911
+ propertyTable: 0,
912
+ featureCount: featureCount,
913
+ },
914
+ ],
915
+ };
916
+ extensionsUsed.push("EXT_mesh_features");
917
+ }
918
+
919
+ // Feature index property table
920
+ if (defined(propertyTable0URL)) {
921
+ buffers.push({
922
+ uri: propertyTable0URL,
923
+ byteLength: meshPropertyTable0.byteLength,
924
+ });
925
+ bufferViews.push({
926
+ buffer: buffers.length - 1,
927
+ byteOffset: 0,
928
+ byteLength: meshPropertyTable0.byteLength,
929
+ target: 34963,
930
+ });
931
+
932
+ rootExtensions.EXT_structural_metadata = {
933
+ schema: {
934
+ id: "i3s-metadata-schema-001",
935
+ name: "I3S metadata schema 001",
936
+ description: "The schema for I3S metadata",
937
+ version: "1.0",
938
+ classes: {
939
+ feature: {
940
+ name: "feature",
941
+ description: "Feature metadata",
942
+ properties: {
943
+ index: {
944
+ description: "The feature index",
945
+ type: "SCALAR",
946
+ componentType: "FLOAT32",
947
+ required: true,
948
+ },
949
+ },
950
+ },
951
+ },
952
+ },
953
+ propertyTables: [
954
+ {
955
+ name: "feature-indices-mapping",
956
+ class: "feature",
957
+ count: featureCount,
958
+ properties: {
959
+ index: {
960
+ values: bufferViews.length - 1,
961
+ },
962
+ },
963
+ },
964
+ ],
965
+ };
966
+ extensionsUsed.push("EXT_structural_metadata");
967
+ }
968
+
969
+ // Outlines indices
970
+ if (defined(outlinesIndicesURL)) {
971
+ buffers.push({
972
+ uri: outlinesIndicesURL,
973
+ byteLength: outlinesIndexArray.byteLength,
974
+ });
975
+ bufferViews.push({
976
+ buffer: buffers.length - 1,
977
+ byteOffset: 0,
978
+ byteLength: outlinesIndexArray.byteLength,
979
+ target: 34963,
980
+ });
981
+ accessors.push({
982
+ bufferView: bufferViews.length - 1,
983
+ byteOffset: 0,
984
+ componentType: 5125,
985
+ count: outlinesIndexArray.length,
986
+ type: "SCALAR",
987
+ });
988
+ extensions.CESIUM_primitive_outline = {
989
+ indices: accessors.length - 1,
990
+ };
991
+ extensionsUsed.push("CESIUM_primitive_outline");
992
+ }
993
+
414
994
  // INDICES
415
- ++currentIndex;
416
- indicesIndex = currentIndex;
417
995
  buffers.push({
418
996
  uri: indicesURL,
419
997
  byteLength: indexArray.byteLength,
420
998
  });
421
999
  bufferViews.push({
422
- buffer: indicesIndex,
1000
+ buffer: buffers.length - 1,
423
1001
  byteOffset: 0,
424
1002
  byteLength: indexArray.byteLength,
425
1003
  target: 34963,
426
1004
  });
427
- accessors.push({
428
- bufferView: indicesIndex,
429
- byteOffset: 0,
430
- componentType: 5125,
431
- count: vertexCount,
432
- type: "SCALAR",
433
- });
434
1005
 
435
- // Create a new mesh for this page
436
- meshes.push({
437
- primitives: [
438
- {
439
- attributes: attributes,
440
- indices: indicesIndex,
441
- material: 0,
1006
+ const meshPrimitives = [];
1007
+ if (transparentVertexOffset > 0) {
1008
+ // Add opaque mesh primitive
1009
+ accessors.push({
1010
+ bufferView: bufferViews.length - 1,
1011
+ byteOffset: 0,
1012
+ componentType: 5125,
1013
+ count: transparentVertexOffset,
1014
+ type: "SCALAR",
1015
+ });
1016
+ meshPrimitives.push({
1017
+ attributes: attributes,
1018
+ indices: accessors.length - 1,
1019
+ material: meshPrimitives.length,
1020
+ extensions: extensions,
1021
+ });
1022
+ }
1023
+ if (transparentVertexOffset < vertexCount) {
1024
+ // Add transparent mesh primitive
1025
+ accessors.push({
1026
+ bufferView: bufferViews.length - 1,
1027
+ byteOffset: 4 * transparentVertexOffset, // skip 4 bytes for each opaque vertex
1028
+ componentType: 5125,
1029
+ count: vertexCount - transparentVertexOffset,
1030
+ type: "SCALAR",
1031
+ });
1032
+ // Indicate the vertices transparancy for the mesh primitive
1033
+ meshPrimitives.push({
1034
+ attributes: attributes,
1035
+ indices: accessors.length - 1,
1036
+ material: meshPrimitives.length,
1037
+ extensions: extensions,
1038
+ extra: {
1039
+ isTransparent: true,
442
1040
  },
443
- ],
1041
+ });
1042
+ }
1043
+ meshes.push({
1044
+ primitives: meshPrimitives,
444
1045
  });
445
1046
  nodesInScene.push(0);
446
1047
  nodes.push({ mesh: 0 });
@@ -452,6 +1053,8 @@ function generateGltfBuffer(
452
1053
  meshes: meshes,
453
1054
  nodes: nodes,
454
1055
  nodesInScene: nodesInScene,
1056
+ rootExtensions: rootExtensions,
1057
+ extensionsUsed: extensionsUsed,
455
1058
  };
456
1059
  }
457
1060
 
@@ -954,32 +1557,12 @@ function decodeAndCreateGltf(parameters) {
954
1557
  );
955
1558
  }
956
1559
 
957
- // Create the final buffer
958
- const meshData = generateGltfBuffer(
959
- geometryData.vertexCount,
960
- geometryData.indices,
961
- geometryData.positions,
962
- geometryData.normals,
963
- geometryData.uv0s,
964
- geometryData.colors
965
- );
966
-
967
- const customAttributes = {};
1560
+ let featureIndex;
968
1561
  if (defined(geometryData["feature-index"])) {
969
- customAttributes.positions = geometryData.positions;
970
- customAttributes.indices = geometryData.indices;
971
- customAttributes.featureIndex = geometryData["feature-index"];
972
- customAttributes.cartesianCenter = parameters.cartesianCenter;
973
- customAttributes.parentRotation = parameters.parentRotation;
1562
+ featureIndex = geometryData["feature-index"];
974
1563
  } else if (defined(geometryData["faceRange"])) {
975
- customAttributes.positions = geometryData.positions;
976
- customAttributes.indices = geometryData.indices;
977
- customAttributes.sourceURL = parameters.url;
978
- customAttributes.cartesianCenter = parameters.cartesianCenter;
979
- customAttributes.parentRotation = parameters.parentRotation;
980
-
981
1564
  // Build the feature index array from the faceRange.
982
- customAttributes.featureIndex = new Array(geometryData.positions.length);
1565
+ featureIndex = new Array(geometryData.vertexCount);
983
1566
  for (
984
1567
  let range = 0;
985
1568
  range < geometryData["faceRange"].length - 1;
@@ -989,13 +1572,56 @@ function decodeAndCreateGltf(parameters) {
989
1572
  const rangeStart = geometryData["faceRange"][range];
990
1573
  const rangeEnd = geometryData["faceRange"][range + 1];
991
1574
  for (let i = rangeStart; i <= rangeEnd; i++) {
992
- customAttributes.featureIndex[i * 3] = curIndex;
993
- customAttributes.featureIndex[i * 3 + 1] = curIndex;
994
- customAttributes.featureIndex[i * 3 + 2] = curIndex;
1575
+ featureIndex[i * 3] = curIndex;
1576
+ featureIndex[i * 3 + 1] = curIndex;
1577
+ featureIndex[i * 3 + 2] = curIndex;
995
1578
  }
996
1579
  }
997
1580
  }
998
1581
 
1582
+ if (parameters.calculateNormals) {
1583
+ const data = generateNormals(
1584
+ geometryData.vertexCount,
1585
+ geometryData.indices,
1586
+ geometryData.positions,
1587
+ geometryData.normals,
1588
+ geometryData.uv0s,
1589
+ geometryData.colors,
1590
+ featureIndex
1591
+ );
1592
+ if (defined(data.normals)) {
1593
+ geometryData.normals = data.normals;
1594
+ if (defined(data.vertexCount)) {
1595
+ geometryData.vertexCount = data.vertexCount;
1596
+ geometryData.indices = data.indices;
1597
+ geometryData.positions = data.positions;
1598
+ geometryData.uv0s = data.uv0s;
1599
+ geometryData.colors = data.colors;
1600
+ featureIndex = data.featureIndex;
1601
+ }
1602
+ }
1603
+ }
1604
+
1605
+ // Create the final buffer
1606
+ const meshData = generateGltfBuffer(
1607
+ geometryData.vertexCount,
1608
+ geometryData.indices,
1609
+ geometryData.positions,
1610
+ geometryData.normals,
1611
+ geometryData.uv0s,
1612
+ geometryData.colors,
1613
+ featureIndex,
1614
+ parameters
1615
+ );
1616
+
1617
+ const customAttributes = {
1618
+ positions: geometryData.positions,
1619
+ indices: geometryData.indices,
1620
+ featureIndex: featureIndex,
1621
+ sourceURL: parameters.url,
1622
+ cartesianCenter: parameters.cartesianCenter,
1623
+ parentRotation: parameters.parentRotation,
1624
+ };
999
1625
  meshData._customAttributes = customAttributes;
1000
1626
 
1001
1627
  const results = {