@cesium/engine 23.0.1 → 24.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 (226) hide show
  1. package/Build/Workers/{chunk-G6MJ3ZW3.js → chunk-2N4KDHS3.js} +10 -10
  2. package/Build/Workers/{chunk-C6HHBKT5.js → chunk-44EMEGKW.js} +5 -5
  3. package/Build/Workers/{chunk-TNXOPEIG.js → chunk-4TIG36AW.js} +12 -12
  4. package/Build/Workers/{chunk-PQTSXJBJ.js → chunk-5A2SW66E.js} +16 -16
  5. package/Build/Workers/{chunk-TXYQNXNW.js → chunk-5GXYJQ2K.js} +3 -3
  6. package/Build/Workers/{chunk-O67UP5YO.js → chunk-63SIWPLS.js} +13 -13
  7. package/Build/Workers/{chunk-CVAAIRNP.js → chunk-6MPGQEHA.js} +2 -2
  8. package/Build/Workers/{chunk-LHFC4R7Z.js → chunk-6RMS4S72.js} +6 -6
  9. package/Build/Workers/{chunk-77DJBHMI.js → chunk-6WLHJFD3.js} +7 -7
  10. package/Build/Workers/{chunk-HXEPZWJN.js → chunk-72VYSVEW.js} +9 -9
  11. package/Build/Workers/{chunk-VPWYHFQA.js → chunk-7MDYBRYJ.js} +4 -4
  12. package/Build/Workers/{chunk-XPMXRJDD.js → chunk-7O5XJTVE.js} +5 -5
  13. package/Build/Workers/{chunk-UEWYSOFD.js → chunk-7QRFIKWQ.js} +2 -2
  14. package/Build/Workers/{chunk-3UQ2YMPP.js → chunk-7TYLCBGK.js} +8 -8
  15. package/Build/Workers/{chunk-GLCPE2BJ.js → chunk-7X322WP2.js} +13 -13
  16. package/Build/Workers/{chunk-2OBWHTIC.js → chunk-A47HVBC5.js} +7 -7
  17. package/Build/Workers/{chunk-CID5SY7L.js → chunk-AF3MU2RL.js} +5 -5
  18. package/Build/Workers/{chunk-BTP3634E.js → chunk-AJLTU6PF.js} +1 -1
  19. package/Build/Workers/{chunk-YSJRB2UZ.js → chunk-AMIHNSST.js} +2 -2
  20. package/Build/Workers/{chunk-QPXGGVHC.js → chunk-B6SCUUFP.js} +10 -10
  21. package/Build/Workers/{chunk-QNABVTTP.js → chunk-BJD6QGXZ.js} +12 -12
  22. package/Build/Workers/{chunk-RZX6LOG6.js → chunk-C6P4IG5P.js} +6 -6
  23. package/Build/Workers/{chunk-4JJQRZYL.js → chunk-D4EJ2NXG.js} +17 -17
  24. package/Build/Workers/{chunk-K7UTK4OM.js → chunk-DHKPFLSJ.js} +1 -1
  25. package/Build/Workers/{chunk-S53HSRT6.js → chunk-DVB56LG7.js} +6 -6
  26. package/Build/Workers/{chunk-PBECJOWF.js → chunk-EDXL4W76.js} +2 -2
  27. package/Build/Workers/{chunk-ALTCIHRH.js → chunk-EV3VGO6Y.js} +17 -17
  28. package/Build/Workers/{chunk-UOQB7XQI.js → chunk-GOQBUCXH.js} +10 -10
  29. package/Build/Workers/{chunk-TMCTZ5E3.js → chunk-GQUNK2XC.js} +14 -14
  30. package/Build/Workers/{chunk-PAFMAR7A.js → chunk-HKUES6UG.js} +12 -12
  31. package/Build/Workers/{chunk-6U5QMZU3.js → chunk-HRHRYFHS.js} +9 -9
  32. package/Build/Workers/{chunk-PUO7BYDY.js → chunk-HXJMS2ZI.js} +1 -1
  33. package/Build/Workers/{chunk-FXSRA5UG.js → chunk-ILMFADZA.js} +4 -4
  34. package/Build/Workers/{chunk-U4SWB6TI.js → chunk-ISY4EZCA.js} +4 -4
  35. package/Build/Workers/{chunk-PGZ3B6CB.js → chunk-J6AW5YHS.js} +14 -14
  36. package/Build/Workers/{chunk-VX774SWE.js → chunk-JCI63T3K.js} +6 -6
  37. package/Build/Workers/{chunk-54O3AGOA.js → chunk-KLPGTXS3.js} +6 -6
  38. package/Build/Workers/{chunk-CNLXMOPM.js → chunk-LIB2H534.js} +10 -10
  39. package/Build/Workers/{chunk-H3TVRJLY.js → chunk-LXMCPFFS.js} +4 -4
  40. package/Build/Workers/{chunk-DNMASBMH.js → chunk-MKM27KGV.js} +2 -2
  41. package/Build/Workers/{chunk-66OWUDO7.js → chunk-N65BAKSH.js} +8 -8
  42. package/Build/Workers/{chunk-ZEMJQKHD.js → chunk-NKT5K3K3.js} +11 -11
  43. package/Build/Workers/{chunk-EIC3VAOZ.js → chunk-NPF7SSHZ.js} +7 -7
  44. package/Build/Workers/{chunk-YDR5LX5Z.js → chunk-PVV64VFW.js} +1 -1
  45. package/Build/Workers/{chunk-FKU77FNM.js → chunk-Q3C6VQH6.js} +4 -4
  46. package/Build/Workers/{chunk-CYOPNGPX.js → chunk-RQNJD3O4.js} +12 -12
  47. package/Build/Workers/{chunk-IJ3SUMK3.js → chunk-UIGVOKKI.js} +1 -1
  48. package/Build/Workers/{chunk-TFPG3ZKW.js → chunk-UQU4RXLT.js} +27 -19
  49. package/Build/Workers/{chunk-N6HRZLS6.js → chunk-VLDEUTOP.js} +2 -2
  50. package/Build/Workers/{chunk-MNSNOONX.js → chunk-VMVOUQ5J.js} +7 -7
  51. package/Build/Workers/{chunk-OZYB3AOR.js → chunk-XJRBB253.js} +11 -11
  52. package/Build/Workers/{chunk-B2VA6IEL.js → chunk-XY6HMDGI.js} +5 -5
  53. package/Build/Workers/{chunk-2M7DKGLW.js → chunk-Y7HNNPNK.js} +10 -10
  54. package/Build/Workers/{chunk-CJ7ZDY77.js → chunk-YAOZMOFL.js} +5 -5
  55. package/Build/Workers/{chunk-FCJQO4NC.js → chunk-YJZGW74L.js} +8 -8
  56. package/Build/Workers/{chunk-JUKGMJX7.js → chunk-YQFTYQMZ.js} +1 -1
  57. package/Build/Workers/{chunk-HNDE73JK.js → chunk-ZBZRTRJB.js} +10 -10
  58. package/Build/Workers/combineGeometry.js +24 -24
  59. package/Build/Workers/createBoxGeometry.js +18 -18
  60. package/Build/Workers/createBoxOutlineGeometry.js +16 -16
  61. package/Build/Workers/createCircleGeometry.js +26 -26
  62. package/Build/Workers/createCircleOutlineGeometry.js +19 -19
  63. package/Build/Workers/createCoplanarPolygonGeometry.js +33 -33
  64. package/Build/Workers/createCoplanarPolygonOutlineGeometry.js +31 -31
  65. package/Build/Workers/createCorridorGeometry.js +29 -29
  66. package/Build/Workers/createCorridorOutlineGeometry.js +28 -28
  67. package/Build/Workers/createCylinderGeometry.js +20 -20
  68. package/Build/Workers/createCylinderOutlineGeometry.js +18 -18
  69. package/Build/Workers/createEllipseGeometry.js +26 -26
  70. package/Build/Workers/createEllipseOutlineGeometry.js +19 -19
  71. package/Build/Workers/createEllipsoidGeometry.js +19 -19
  72. package/Build/Workers/createEllipsoidOutlineGeometry.js +18 -18
  73. package/Build/Workers/createFrustumGeometry.js +18 -18
  74. package/Build/Workers/createFrustumOutlineGeometry.js +18 -18
  75. package/Build/Workers/createGeometry.js +24 -24
  76. package/Build/Workers/createGroundPolylineGeometry.js +22 -22
  77. package/Build/Workers/createPlaneGeometry.js +16 -16
  78. package/Build/Workers/createPlaneOutlineGeometry.js +15 -15
  79. package/Build/Workers/createPolygonGeometry.js +32 -32
  80. package/Build/Workers/createPolygonOutlineGeometry.js +30 -30
  81. package/Build/Workers/createPolylineGeometry.js +25 -25
  82. package/Build/Workers/createPolylineVolumeGeometry.js +31 -31
  83. package/Build/Workers/createPolylineVolumeOutlineGeometry.js +27 -27
  84. package/Build/Workers/createRectangleGeometry.js +27 -27
  85. package/Build/Workers/createRectangleOutlineGeometry.js +20 -20
  86. package/Build/Workers/createSimplePolylineGeometry.js +23 -23
  87. package/Build/Workers/createSphereGeometry.js +19 -19
  88. package/Build/Workers/createSphereOutlineGeometry.js +18 -18
  89. package/Build/Workers/createTaskProcessorWorker.js +3 -3
  90. package/Build/Workers/createVectorTileClampedPolylines.js +14 -14
  91. package/Build/Workers/createVectorTileGeometries.js +24 -24
  92. package/Build/Workers/createVectorTilePoints.js +13 -13
  93. package/Build/Workers/createVectorTilePolygons.js +22 -22
  94. package/Build/Workers/createVectorTilePolylines.js +14 -14
  95. package/Build/Workers/createVerticesFromCesium3DTilesTerrain.js +25 -25
  96. package/Build/Workers/createVerticesFromGoogleEarthEnterpriseBuffer.js +22 -22
  97. package/Build/Workers/createVerticesFromHeightmap.js +22 -22
  98. package/Build/Workers/createVerticesFromQuantizedTerrainMesh.js +20 -20
  99. package/Build/Workers/createWallGeometry.js +25 -25
  100. package/Build/Workers/createWallOutlineGeometry.js +24 -24
  101. package/Build/Workers/decodeDraco.js +10 -10
  102. package/Build/Workers/decodeGoogleEarthEnterprisePacket.js +5 -5
  103. package/Build/Workers/decodeI3S.js +12 -12
  104. package/Build/Workers/gaussianSplatSorter.js +4 -4
  105. package/Build/Workers/gaussianSplatTextureGenerator.js +4 -4
  106. package/Build/Workers/incrementallyBuildTerrainPicker.js +10 -10
  107. package/Build/Workers/transcodeKTX2.js +6 -6
  108. package/Build/Workers/transferTypedArrayTest.js +1 -1
  109. package/Build/Workers/upsampleQuantizedTerrainMesh.js +22 -22
  110. package/Build/Workers/upsampleVerticesFromCesium3DTilesTerrain.js +25 -25
  111. package/Source/Core/BoundingSphere.js +1 -1
  112. package/Source/Core/Cartesian2.js +7 -5
  113. package/Source/Core/Cartesian3.js +8 -6
  114. package/Source/Core/Cartesian4.js +8 -6
  115. package/Source/Core/Color.js +5 -3
  116. package/Source/Core/DeveloperError.js +2 -1
  117. package/Source/Core/ITwinPlatform.js +1 -0
  118. package/Source/Core/Ion.js +1 -1
  119. package/Source/Core/S2Cell.js +2 -2
  120. package/Source/Core/TerrainMesh.js +10 -1
  121. package/Source/Core/TerrainPicker.js +1 -0
  122. package/Source/Core/WallGeometry.js +1 -1
  123. package/Source/Core/WallOutlineGeometry.js +1 -1
  124. package/Source/Core/assert.js +27 -0
  125. package/Source/Core/globalTypes.js +4 -0
  126. package/Source/DataSources/CzmlDataSource.js +9 -0
  127. package/Source/DataSources/PathGraphics.js +13 -0
  128. package/Source/DataSources/PathVisualizer.js +330 -18
  129. package/Source/DataSources/StaticGeometryColorBatch.js +7 -2
  130. package/Source/DataSources/StaticGeometryPerMaterialBatch.js +7 -2
  131. package/Source/DataSources/StaticGroundGeometryPerMaterialBatch.js +3 -1
  132. package/Source/DataSources/StaticGroundPolylinePerMaterialBatch.js +3 -1
  133. package/Source/Renderer/Context.js +1 -1
  134. package/Source/Renderer/RenderState.js +2 -2
  135. package/Source/Renderer/VertexArray.js +80 -0
  136. package/Source/Scene/ArcGisMapService.js +1 -1
  137. package/Source/Scene/BillboardCollection.js +65 -364
  138. package/Source/Scene/BufferPoint.js +148 -0
  139. package/Source/Scene/BufferPointCollection.js +135 -0
  140. package/Source/Scene/BufferPointMaterial.js +95 -0
  141. package/Source/Scene/BufferPolygon.js +516 -0
  142. package/Source/Scene/BufferPolygonCollection.js +368 -0
  143. package/Source/Scene/BufferPolygonMaterial.js +41 -0
  144. package/Source/Scene/BufferPolyline.js +185 -0
  145. package/Source/Scene/BufferPolylineCollection.js +136 -0
  146. package/Source/Scene/BufferPolylineMaterial.js +93 -0
  147. package/Source/Scene/BufferPrimitive.js +347 -0
  148. package/Source/Scene/BufferPrimitiveCollection.js +702 -0
  149. package/Source/Scene/BufferPrimitiveMaterial.js +140 -0
  150. package/Source/Scene/Cesium3DTileContent.js +5 -1
  151. package/Source/Scene/Cesium3DTileContentFactory.js +9 -0
  152. package/Source/Scene/Cesium3DTileStyle.js +22 -0
  153. package/Source/Scene/Cesium3DTileset.js +1 -0
  154. package/Source/Scene/ClippingPolygonCollection.js +270 -101
  155. package/Source/Scene/CubeMapPanorama.js +4 -4
  156. package/Source/Scene/GaussianSplat3DTileContent.js +40 -46
  157. package/Source/Scene/GaussianSplatPrimitive.js +413 -70
  158. package/Source/Scene/GetFeatureInfoFormat.js +3 -3
  159. package/Source/Scene/GltfLoader.js +215 -34
  160. package/Source/Scene/GltfSpzLoader.js +109 -0
  161. package/Source/Scene/ITwinData.js +1 -0
  162. package/Source/Scene/Label.js +32 -0
  163. package/Source/Scene/LabelCollection.js +14 -13
  164. package/Source/Scene/Material.js +2 -0
  165. package/Source/Scene/Megatexture.js +1 -0
  166. package/Source/Scene/MetadataClassProperty.js +24 -10
  167. package/Source/Scene/MetadataComponentType.js +115 -23
  168. package/Source/Scene/Model/CustomShaderPipelineStage.js +3 -1
  169. package/Source/Scene/Model/EdgeVisibilityPipelineStage.js +761 -263
  170. package/Source/Scene/Model/MaterialPipelineStage.js +147 -0
  171. package/Source/Scene/Model/MetadataPipelineStage.js +3 -3
  172. package/Source/Scene/Model/ModelDrawCommand.js +6 -0
  173. package/Source/Scene/Model/ModelReader.js +1 -1
  174. package/Source/Scene/Model/ModelUtility.js +3 -1
  175. package/Source/Scene/Model/createVectorTileBuffersFromModelComponents.js +330 -0
  176. package/Source/Scene/ModelComponents.js +1632 -1542
  177. package/Source/Scene/PickedMetadataInfo.js +1 -0
  178. package/Source/Scene/ScreenSpaceCameraController.js +13 -0
  179. package/Source/Scene/SkyBox.js +17 -8
  180. package/Source/Scene/TileBoundingRegion.js +1 -1
  181. package/Source/Scene/TileBoundingS2Cell.js +1 -1
  182. package/Source/Scene/TileBoundingSphere.js +1 -1
  183. package/Source/Scene/TweenCollection.js +7 -0
  184. package/Source/Scene/VectorGltf3DTileContent.js +382 -0
  185. package/Source/Scene/VertexAttributeSemantic.js +14 -0
  186. package/Source/Scene/WebMapServiceImageryProvider.js +2 -2
  187. package/Source/Scene/WebMapTileServiceImageryProvider.js +366 -131
  188. package/Source/Scene/parseStructuralMetadata.js +97 -37
  189. package/Source/Scene/renderBufferPointCollection.js +334 -0
  190. package/Source/Scene/renderBufferPolygonCollection.js +386 -0
  191. package/Source/Scene/renderBufferPolylineCollection.js +529 -0
  192. package/Source/Shaders/BillboardCollectionFS.glsl +2 -77
  193. package/Source/Shaders/BillboardCollectionFS.js +2 -77
  194. package/Source/Shaders/BillboardCollectionVS.glsl +2 -60
  195. package/Source/Shaders/BillboardCollectionVS.js +2 -60
  196. package/Source/Shaders/BufferPointMaterialFS.glsl +27 -0
  197. package/Source/Shaders/BufferPointMaterialFS.js +29 -0
  198. package/Source/Shaders/BufferPointMaterialVS.glsl +48 -0
  199. package/Source/Shaders/BufferPointMaterialVS.js +50 -0
  200. package/Source/Shaders/BufferPolygonMaterialFS.glsl +13 -0
  201. package/Source/Shaders/BufferPolygonMaterialFS.js +15 -0
  202. package/Source/Shaders/BufferPolygonMaterialVS.glsl +30 -0
  203. package/Source/Shaders/BufferPolygonMaterialVS.js +32 -0
  204. package/Source/Shaders/BufferPolylineMaterialFS.glsl +13 -0
  205. package/Source/Shaders/BufferPolylineMaterialFS.js +15 -0
  206. package/Source/Shaders/BufferPolylineMaterialVS.glsl +49 -0
  207. package/Source/Shaders/BufferPolylineMaterialVS.js +51 -0
  208. package/Source/Shaders/Model/EdgeVisibilityStageFS.glsl +34 -48
  209. package/Source/Shaders/Model/EdgeVisibilityStageFS.js +34 -49
  210. package/Source/Shaders/Model/EdgeVisibilityStageVS.glsl +98 -0
  211. package/Source/Shaders/Model/EdgeVisibilityStageVS.js +100 -0
  212. package/Source/Shaders/Model/ModelFS.glsl +15 -0
  213. package/Source/Shaders/Model/ModelFS.js +15 -0
  214. package/Source/Shaders/Model/ModelVS.glsl +8 -0
  215. package/Source/Shaders/Model/ModelVS.js +8 -0
  216. package/Source/Shaders/PolygonSignedDistanceFS.glsl +64 -33
  217. package/Source/Shaders/PolygonSignedDistanceFS.js +64 -33
  218. package/Source/Shaders/PrimitiveGaussianSplatVS.glsl +9 -2
  219. package/Source/Shaders/PrimitiveGaussianSplatVS.js +9 -2
  220. package/Source/Shaders/Voxels/VoxelFS.glsl +1 -1
  221. package/Source/Shaders/Voxels/VoxelFS.js +1 -1
  222. package/Source/Workers/decodeDraco.js +3 -0
  223. package/Source/Workers/decodeI3S.js +5 -2
  224. package/index.d.ts +1007 -111
  225. package/index.js +394 -369
  226. package/package.json +2 -2
@@ -20,6 +20,7 @@ import TextureWrap from "../Renderer/TextureWrap.js";
20
20
  import ClippingPolygon from "./ClippingPolygon.js";
21
21
  import ComputeCommand from "../Renderer/ComputeCommand.js";
22
22
  import PolygonSignedDistanceFS from "../Shaders/PolygonSignedDistanceFS.js";
23
+ import Pass from "../Renderer/Pass.js";
23
24
 
24
25
  /**
25
26
  * Specifies a set of clipping polygons. Clipping polygons selectively disable rendering in a region
@@ -34,6 +35,7 @@ import PolygonSignedDistanceFS from "../Shaders/PolygonSignedDistanceFS.js";
34
35
  * @param {ClippingPolygon[]} [options.polygons=[]] An array of {@link ClippingPolygon} objects used to selectively disable rendering on the inside of each polygon.
35
36
  * @param {boolean} [options.enabled=true] Determines whether the clipping polygons are active.
36
37
  * @param {boolean} [options.inverse=false] If true, a region will be clipped if it is outside of every polygon in the collection. Otherwise, a region will only be clipped if it is on the inside of any polygon.
38
+ * @param {number} [options.quality=1.0] A scalar that controls the resolution of the signed distance texture used for clipping. Values greater than 1.0 increase quality, values less than 1.0 decrease it. Must be greater than 0.0.
37
39
  *
38
40
  * @example
39
41
  * const positions = Cesium.Cartesian3.fromRadiansArray([
@@ -63,6 +65,8 @@ function ClippingPolygonCollection(options) {
63
65
  this._polygons = [];
64
66
  this._totalPositions = 0;
65
67
 
68
+ this.debugShowDistanceTexture = options.debugShowDistanceTexture ?? false;
69
+
66
70
  /**
67
71
  * If true, clipping will be enabled.
68
72
  *
@@ -81,6 +85,15 @@ function ClippingPolygonCollection(options) {
81
85
  */
82
86
  this.inverse = options.inverse ?? false;
83
87
 
88
+ /**
89
+ * A scalar that controls the resolution of the signed distance texture used for clipping.
90
+ * Values greater than 1.0 increase quality, values less than 1.0 decrease it. Must be greater than 0.0.
91
+ *
92
+ * @type {number}
93
+ * @default 1.0
94
+ */
95
+ this.quality = options.quality ?? 1.0;
96
+
84
97
  /**
85
98
  * An event triggered when a new clipping polygon is added to the collection. Event handlers
86
99
  * are passed the new polygon and the index at which it was added.
@@ -204,8 +217,8 @@ Object.defineProperties(ClippingPolygonCollection.prototype, {
204
217
  pixelsNeededForPolygonPositions: {
205
218
  get: function () {
206
219
  // In an RG FLOAT texture, each polygon position is 2 floats packed to a RG.
207
- // Each polygon is the number of positions of that polygon, followed by the list of positions
208
- return this.totalPositions + this.length;
220
+ // Each polygon has a 1-pixel header + 2 pixels for individual extents + the list of positions
221
+ return this.totalPositions + 3 * this.length;
209
222
  },
210
223
  },
211
224
 
@@ -362,91 +375,160 @@ ClippingPolygonCollection.prototype.remove = function (polygon) {
362
375
  return true;
363
376
  };
364
377
 
365
- const scratchRectangle = new Rectangle();
378
+ /**
379
+ * Computes padded extents for a polygon's bounding rectangle, clamped to valid spherical ranges.
380
+ *
381
+ * @param {Rectangle} extents The original spherical extents to pad.
382
+ * @param {number} padding A multiplier applied to the extents' width and height to determine the padding amount.
383
+ * @param {Rectangle} [result] An optional rectangle to store the result in.
384
+ * @returns {Rectangle} The padded and clamped rectangle.
385
+ *
386
+ * @private
387
+ */
388
+ function computePaddedExtents(extents, padding, result) {
389
+ const height = Math.max(extents.height * padding, 0);
390
+ const width = Math.max(extents.width * padding, 0);
391
+ const paddedExtents = Rectangle.clone(extents, result);
392
+
393
+ // Pad
394
+ paddedExtents.south -= height;
395
+ paddedExtents.west -= width;
396
+ paddedExtents.north += height;
397
+ paddedExtents.east += width;
398
+
399
+ // Clamp
400
+ paddedExtents.south = Math.max(paddedExtents.south, -Math.PI);
401
+ paddedExtents.west = Math.max(paddedExtents.west, -Math.PI);
402
+ paddedExtents.north = Math.min(paddedExtents.north, Math.PI);
403
+ paddedExtents.east = Math.min(paddedExtents.east, Math.PI);
404
+
405
+ return paddedExtents;
406
+ }
407
+
408
+ /**
409
+ * @typedef {object} ExtentsResult
410
+ * @property {Rectangle[]} extentsList The list of merged padded extents, one per group.
411
+ * @property {Map<number, number>} extentsIndexByPolygon A map from polygon index to the index of its group in extentsList.
412
+ * @private
413
+ */
414
+
415
+ /**
416
+ * Groups nearby ClippingPolygons based on their spherical extents. Overlapping extents will be merged
417
+ * into a single encompassing extent. Each Extent will later map into one region in the SignedDistanceTexture (atlas).
418
+ *
419
+ * Definitions:
420
+ * n = number of polygons
421
+ * g = number of resulting extents (merged) (g <= n)
422
+ * absorb = merge two extents into one
423
+ * restart = redo intersection check with previous groups
424
+ *
425
+ * Algorithm:
426
+ * For each polygon we scan existing groups for a first overlap (O(g)),
427
+ * then on each subsequent overlap we absorb the group and restart the
428
+ * inner scan. Each group can be absorbed at most once per polygon, and
429
+ * each restart reduces the group count by one, so the absorb-loop does
430
+ * at most O(g) restarts per polygon. Overall: O(n * g) where g ≤ n,
431
+ * giving O(n²) worst case when all polygons overlap transitively, but
432
+ * typically much better when groups are few and disjoint.
433
+ *
434
+ * Note: Restarts are required because the new merged bounding box might
435
+ * be larger than the two individual that were merged and introduce new
436
+ * collisions. Example:
437
+ *
438
+ * Before merging A and B:
439
+ *
440
+ * ┌─────────┐
441
+ * │ A │
442
+ * │ ┌┼────────┐
443
+ * └─────────┘│ B │
444
+ * ┌────┐ │ │
445
+ * │ C │ └────────┘
446
+ * └────┘
447
+ *
448
+ * A overlaps B ✓
449
+ * A overlaps C ✗
450
+ * B overlaps C ✗
451
+ *
452
+ * After merging A ∪ B into one extent:
453
+ *
454
+ * ┌───────────────────┐
455
+ * │ │
456
+ * │ A ∪ B │
457
+ * ├────┐ │
458
+ * │ C │ │
459
+ * └────┘──────────────┘
460
+ *
461
+ * (A ∪ B) overlaps C ✓ ← new collision!
462
+ *
463
+ * @param {ClippingPolygon[]} polygons The array of clipping polygons to compute extents for.
464
+ * @param {Rectangle[]} polygonExtentsCache An array of pre-computed spherical extents for each polygon, indexed by polygon index.
465
+ * @returns {ExtentsResult} The merged extents and a mapping from polygon indices to their extent group indices.
466
+ *
467
+ * @private
468
+ */
469
+ function getExtents(polygons, polygonExtentsCache) {
470
+ // Pad extents to avoid floating point error when fragment culling at edges.
471
+ const PADDING = 2.5;
366
472
 
367
- // Map the polygons to a list of extents-- Overlapping extents will be merged
368
- // into a single encompassing extent
369
- function getExtents(polygons) {
370
- const extentsList = [];
371
- const polygonIndicesList = [];
473
+ // Each group: { extent: padded Rectangle, polygonIndices: number[] }
474
+ const groups = [];
372
475
 
373
476
  const length = polygons.length;
374
477
  for (let polygonIndex = 0; polygonIndex < length; ++polygonIndex) {
375
- const polygon = polygons[polygonIndex];
376
- const extents = polygon.computeSphericalExtents();
377
-
378
- let height = Math.max(extents.height * 2.5, 0.001);
379
- let width = Math.max(extents.width * 2.5, 0.001);
380
-
381
- // Pad extents to avoid floating point error when fragment culling at edges.
382
- let paddedExtents = Rectangle.clone(extents);
383
- paddedExtents.south -= height;
384
- paddedExtents.west -= width;
385
- paddedExtents.north += height;
386
- paddedExtents.east += width;
387
-
388
- paddedExtents.south = Math.max(paddedExtents.south, -Math.PI);
389
- paddedExtents.west = Math.max(paddedExtents.west, -Math.PI);
390
- paddedExtents.north = Math.min(paddedExtents.north, Math.PI);
391
- paddedExtents.east = Math.min(paddedExtents.east, Math.PI);
392
-
393
- const polygonIndices = [polygonIndex];
394
- for (let i = 0; i < extentsList.length; ++i) {
395
- const e = extentsList[i];
478
+ const paddedExtent = computePaddedExtents(
479
+ polygonExtentsCache[polygonIndex],
480
+ PADDING,
481
+ );
482
+
483
+ // Pass 1: Find the first overlapping group
484
+ let targetIdx = -1;
485
+ for (let g = 0; g < groups.length; ++g) {
396
486
  if (
397
- defined(e) &&
398
- defined(Rectangle.simpleIntersection(e, paddedExtents)) &&
399
- !Rectangle.equals(e, paddedExtents)
487
+ defined(Rectangle.simpleIntersection(groups[g].extent, paddedExtent))
400
488
  ) {
401
- const intersectingPolygons = polygonIndicesList[i];
402
- polygonIndices.push(...intersectingPolygons);
403
- intersectingPolygons.reduce(
404
- (extents, p) =>
405
- Rectangle.union(
406
- polygons[p].computeSphericalExtents(scratchRectangle),
407
- extents,
408
- extents,
409
- ),
410
- extents,
411
- );
412
-
413
- extentsList[i] = undefined;
414
- polygonIndicesList[i] = undefined;
415
-
416
- height = Math.max(extents.height * 2.5, 0.001);
417
- width = Math.max(extents.width * 2.5, 0.001);
418
-
419
- paddedExtents = Rectangle.clone(extents, paddedExtents);
420
- paddedExtents.south -= height;
421
- paddedExtents.west -= width;
422
- paddedExtents.north += height;
423
- paddedExtents.east += width;
424
-
425
- paddedExtents.south = Math.max(paddedExtents.south, -Math.PI);
426
- paddedExtents.west = Math.max(paddedExtents.west, -Math.PI);
427
- paddedExtents.north = Math.min(paddedExtents.north, Math.PI);
428
- paddedExtents.east = Math.min(paddedExtents.east, Math.PI);
429
-
430
- // Reiterate through the extents list until there are no more intersections
431
- i = -1;
489
+ targetIdx = g;
490
+ break;
432
491
  }
433
492
  }
434
493
 
435
- extentsList.push(paddedExtents);
436
- polygonIndicesList.push(polygonIndices);
494
+ if (targetIdx === -1) {
495
+ // No overlap — start a new group
496
+ groups.push({ extent: paddedExtent, polygonIndices: [polygonIndex] });
497
+ } else {
498
+ // Overlap - Merge the polygon into the target group
499
+ const target = groups[targetIdx];
500
+ target.polygonIndices.push(polygonIndex);
501
+ Rectangle.union(target.extent, paddedExtent, target.extent);
502
+
503
+ // Pass 2: Absorb all other groups that overlap the (growing) target
504
+ // extent. After each absorption the target grows, so restart the scan
505
+ // to catch groups that now transitively overlap.
506
+ for (let g = 0; g < groups.length; ++g) {
507
+ if (g === targetIdx) {
508
+ continue;
509
+ }
510
+ if (
511
+ defined(Rectangle.simpleIntersection(groups[g].extent, target.extent))
512
+ ) {
513
+ target.polygonIndices.push(...groups[g].polygonIndices);
514
+ Rectangle.union(target.extent, groups[g].extent, target.extent);
515
+ groups.splice(g, 1);
516
+ if (g < targetIdx) {
517
+ targetIdx--;
518
+ }
519
+ g = -1; // restart (loop increment brings it to 0)
520
+ }
521
+ }
522
+ }
437
523
  }
438
524
 
525
+ const extentsList = groups.map((g) => g.extent);
439
526
  const extentsIndexByPolygon = new Map();
440
- polygonIndicesList
441
- .filter(defined)
442
- .forEach((polygonIndices, e) =>
443
- polygonIndices.forEach((p) => extentsIndexByPolygon.set(p, e)),
444
- );
527
+ groups.forEach((g, extentIndex) =>
528
+ g.polygonIndices.forEach((p) => extentsIndexByPolygon.set(p, extentIndex)),
529
+ );
445
530
 
446
- return {
447
- extentsList: extentsList.filter(defined),
448
- extentsIndexByPolygon: extentsIndexByPolygon,
449
- };
531
+ return { extentsList, extentsIndexByPolygon };
450
532
  }
451
533
 
452
534
  /**
@@ -471,15 +553,52 @@ function packPolygonsAsFloats(clippingPolygonCollection) {
471
553
  const extentsFloat32View = clippingPolygonCollection._extentsFloat32View;
472
554
  const polygons = clippingPolygonCollection._polygons;
473
555
 
474
- const { extentsList, extentsIndexByPolygon } = getExtents(polygons);
556
+ /**
557
+ * Pre-calculate all polygon spherical extents as it an expensive operation
558
+ * @type {ReadonlyArray<Rectangle>}
559
+ * */
560
+ const polygonExtentsCache = polygons.map((polygon) =>
561
+ polygon.computeSphericalExtents(),
562
+ );
563
+
564
+ const { extentsList, extentsIndexByPolygon } = getExtents(
565
+ polygons,
566
+ polygonExtentsCache,
567
+ );
568
+
569
+ // Polygons are packed sequentially (ordered by extentsIndex) into polygonsFloat32View as follows:
570
+ // For each polygon:
571
+ // [0] vertexCount - the number of vertices in the polygon
572
+ // [1] extentsIndex - index into the extents texture for this polygon's bounding rectangle
573
+ // [2] south - southern boundary of the individual polygon extent (radians)
574
+ // [3] west - western boundary of the individual polygon extent (radians)
575
+ // [4] latitudeRange - (north - south) for the individual polygon extent
576
+ // [5] longitudeRange - (east - west) for the individual polygon extent
577
+ // [6..6+2*vertexCount-1] pairs of (latitude, longitude) for each vertex,
578
+ // computed as fastApproximateAtan2 values to match the shader
579
+
580
+ // Sort polygon indices by extentsIndex so polygons sharing the same extent are packed together
581
+ // Can enable optimizations in the shader
582
+ const sortedPolygonIndices = Array.from(polygons.keys()).sort(
583
+ (a, b) => extentsIndexByPolygon.get(a) - extentsIndexByPolygon.get(b),
584
+ );
475
585
 
476
586
  let floatIndex = 0;
477
- for (const [polygonIndex, polygon] of polygons.entries()) {
587
+ for (const polygonIndex of sortedPolygonIndices) {
588
+ const polygon = polygons[polygonIndex];
478
589
  // Pack the length of the polygon into the polygon texture array buffer
479
590
  const length = polygon.length;
480
591
  polygonsFloat32View[floatIndex++] = length;
481
592
  polygonsFloat32View[floatIndex++] = extentsIndexByPolygon.get(polygonIndex);
482
593
 
594
+ // Pack the individual polygon extent
595
+ const polygonExtent = polygonExtentsCache[polygonIndex];
596
+ polygonsFloat32View[floatIndex++] = polygonExtent.south;
597
+ polygonsFloat32View[floatIndex++] = polygonExtent.west;
598
+ polygonsFloat32View[floatIndex++] =
599
+ polygonExtent.north - polygonExtent.south;
600
+ polygonsFloat32View[floatIndex++] = polygonExtent.east - polygonExtent.west;
601
+
483
602
  // Pack the polygon positions into the polygon texture array buffer
484
603
  for (let i = 0; i < length; ++i) {
485
604
  const spherePoint = polygon.positions[i];
@@ -502,7 +621,12 @@ function packPolygonsAsFloats(clippingPolygonCollection) {
502
621
  }
503
622
  }
504
623
 
505
- // Pack extents
624
+ // Extents are packed sequentially into extentsFloat32View as follows:
625
+ // For each extent (maps to one RGBA pixel in the extents texture):
626
+ // [0] south - the southern boundary of the bounding rectangle (radians)
627
+ // [1] west - the western boundary of the bounding rectangle (radians)
628
+ // [2] latitudeRangeInverse - 1.0 / (north - south)
629
+ // [3] longitudeRangeInverse - 1.0 / (east - west)
506
630
  let extentsFloatIndex = 0;
507
631
  for (const extents of extentsList) {
508
632
  const longitudeRangeInverse = 1.0 / (extents.east - extents.west);
@@ -536,6 +660,16 @@ ClippingPolygonCollection.prototype.update = function (frameState) {
536
660
  );
537
661
  }
538
662
 
663
+ if (this.debugShowDistanceTexture && defined(this._signedDistanceTexture)) {
664
+ if (!defined(this.debugCommand)) {
665
+ this.debugCommand = createDebugCommand(
666
+ this._signedDistanceTexture,
667
+ frameState.context,
668
+ );
669
+ }
670
+ frameState.commandList.push(this.debugCommand);
671
+ }
672
+
539
673
  // It'd be expensive to validate any individual position has changed. Instead verify if the list of polygon positions has had elements added or removed, which should be good enough for most cases.
540
674
  const totalPositions = this._polygons.reduce(
541
675
  (totalPositions, polygon) => totalPositions + polygon.length,
@@ -685,6 +819,35 @@ ClippingPolygonCollection.prototype.update = function (frameState) {
685
819
  this._signedDistanceComputeCommand = createSignedDistanceTextureCommand(this);
686
820
  };
687
821
 
822
+ function createDebugCommand(texture, context) {
823
+ const fs =
824
+ "uniform highp sampler2D billboard_texture; \n" +
825
+ "in vec2 v_textureCoordinates; \n" +
826
+ "float getSignedDistance(vec2 uv, highp sampler2D clippingDistance) { \n" +
827
+ " float signedDistance = texture(clippingDistance, uv).r; \n" +
828
+ " return (signedDistance - 0.5) * 2.0; \n" +
829
+ "} \n" +
830
+ "void main() \n" +
831
+ "{ \n" +
832
+ " float dist = texture(billboard_texture, v_textureCoordinates).r; \n" +
833
+ " if (dist > 0.5) { \n" +
834
+ " out_FragColor = vec4(dist, 0.0, 0.0, 1.0); \n" + // outside
835
+ " } else {\n" +
836
+ " out_FragColor = vec4(0.0, dist, 0.0, 1.0); \n" + // inside
837
+ " } \n" +
838
+ "} \n";
839
+
840
+ const drawCommand = context.createViewportQuadCommand(fs, {
841
+ uniformMap: {
842
+ billboard_texture: function () {
843
+ return texture;
844
+ },
845
+ },
846
+ });
847
+ drawCommand.pass = Pass.OVERLAY;
848
+ return drawCommand;
849
+ }
850
+
688
851
  /**
689
852
  * Called when {@link Viewer} or {@link CesiumWidget} render the scene to
690
853
  * build the resources for clipping polygons.
@@ -731,6 +894,7 @@ function createSignedDistanceTextureCommand(collection) {
731
894
 
732
895
  const scratchRectangleTile = new Rectangle();
733
896
  const scratchRectangleIntersection = new Rectangle();
897
+ const scratchRectanglePolygon = new Rectangle();
734
898
  /**
735
899
  * Determines the type intersection with the polygons of this ClippingPolygonCollection instance and the specified {@link TileBoundingVolume}.
736
900
  * @private
@@ -750,30 +914,33 @@ ClippingPolygonCollection.prototype.computeIntersectionWithBoundingVolume =
750
914
  intersection = Intersect.INSIDE;
751
915
  }
752
916
 
917
+ let tileBoundingRectangle = tileBoundingVolume.rectangle;
918
+ if (
919
+ !defined(tileBoundingRectangle) &&
920
+ defined(tileBoundingVolume.boundingVolume?.computeCorners)
921
+ ) {
922
+ const points = tileBoundingVolume.boundingVolume.computeCorners();
923
+ tileBoundingRectangle = Rectangle.fromCartesianArray(
924
+ points,
925
+ ellipsoid,
926
+ scratchRectangleTile,
927
+ );
928
+ }
929
+
930
+ if (!defined(tileBoundingRectangle)) {
931
+ tileBoundingRectangle = Rectangle.fromBoundingSphere(
932
+ tileBoundingVolume.boundingSphere,
933
+ ellipsoid,
934
+ scratchRectangleTile,
935
+ );
936
+ }
937
+
753
938
  for (let i = 0; i < length; ++i) {
754
939
  const polygon = polygons[i];
755
940
 
756
- const polygonBoundingRectangle = polygon.computeRectangle();
757
- let tileBoundingRectangle = tileBoundingVolume.rectangle;
758
- if (
759
- !defined(tileBoundingRectangle) &&
760
- defined(tileBoundingVolume.boundingVolume?.computeCorners)
761
- ) {
762
- const points = tileBoundingVolume.boundingVolume.computeCorners();
763
- tileBoundingRectangle = Rectangle.fromCartesianArray(
764
- points,
765
- ellipsoid,
766
- scratchRectangleTile,
767
- );
768
- }
769
-
770
- if (!defined(tileBoundingRectangle)) {
771
- tileBoundingRectangle = Rectangle.fromBoundingSphere(
772
- tileBoundingVolume.boundingSphere,
773
- ellipsoid,
774
- scratchRectangleTile,
775
- );
776
- }
941
+ const polygonBoundingRectangle = polygon.computeRectangle(
942
+ scratchRectanglePolygon,
943
+ );
777
944
 
778
945
  const result = Rectangle.simpleIntersection(
779
946
  tileBoundingRectangle,
@@ -782,7 +949,7 @@ ClippingPolygonCollection.prototype.computeIntersectionWithBoundingVolume =
782
949
  );
783
950
 
784
951
  if (defined(result)) {
785
- intersection = Intersect.INTERSECTING;
952
+ return Intersect.INTERSECTING;
786
953
  }
787
954
  }
788
955
 
@@ -885,8 +1052,10 @@ ClippingPolygonCollection.getClippingDistanceTextureResolution = function (
885
1052
  return result;
886
1053
  }
887
1054
 
888
- result.x = Math.min(ContextLimits.maximumTextureSize, 4096);
889
- result.y = Math.min(ContextLimits.maximumTextureSize, 4096);
1055
+ const quality = clippingPolygonCollection.quality;
1056
+ const baseSize = Math.max(128, Math.ceil(4096 * quality));
1057
+ result.x = Math.min(ContextLimits.maximumTextureSize, baseSize);
1058
+ result.y = Math.min(ContextLimits.maximumTextureSize, baseSize);
890
1059
 
891
1060
  return result;
892
1061
  };
@@ -29,7 +29,7 @@ import Credit from "../Core/Credit.js";
29
29
  * Initialization options for the CubeMapPanorama constructor
30
30
  *
31
31
  * @property {object} [options.sources] The source URL or <code>Image</code> object for each of the six cube map faces. See the example below.
32
- * @property {Matrix4} [options.transform] A 4x4 transformation matrix that defines the panorama’s position and orientation
32
+ * @property {Matrix3} [options.transform] A 3x3 transformation matrix that defines the panorama’s orientation. If not specified, the default orientation is defined using the True Equator Mean Equinox (TEME) axes.
33
33
  * @property {boolean} [options.show=true] Determines if this primitive will be shown.
34
34
  * @property {Credit|string} [options.credit] A credit for the panorama, which is displayed on the canvas.
35
35
  *
@@ -86,7 +86,7 @@ function CubeMapPanorama(options) {
86
86
  this.sources = options.sources;
87
87
  this._sources = undefined;
88
88
 
89
- this._transform = options.transform ?? undefined;
89
+ this._transform = options.transform;
90
90
 
91
91
  /**
92
92
  * Determines if the cube map panorama will be shown.
@@ -122,9 +122,9 @@ function CubeMapPanorama(options) {
122
122
 
123
123
  Object.defineProperties(CubeMapPanorama.prototype, {
124
124
  /**
125
- * Gets the transform of the panorama.
125
+ * Gets the transform of the panorama. If undefined, the default orientation uses the True Equator Mean Equinox (TEME) axes.
126
126
  * @memberof CubeMapPanorama.prototype
127
- * @type {Matrix4}
127
+ * @type {Matrix3}
128
128
  * @readonly
129
129
  */
130
130
  transform: {
@@ -31,24 +31,23 @@ function GaussianSplat3DTileContent(loader, tileset, tile, resource) {
31
31
  }
32
32
 
33
33
  /**
34
- * Local copy of the position attribute buffer that has been transformed into root tile space. Originals are kept in the gltf loader.
35
- * Used for rendering
34
+ * Local copy of the position attribute buffer transformed into root tile space.
35
+ * The original glTF attribute data is kept untouched so rebuilds can re-apply
36
+ * transforms from the source coordinates.
36
37
  * @type {undefined|Float32Array}
37
38
  * @private
38
39
  */
39
40
  this._positions = undefined;
40
41
 
41
42
  /**
42
- * Local copy of the rotation attribute buffer that has been transformed into root tile space. Originals are kept in the gltf loader.
43
- * Used for rendering
43
+ * Local copy of the rotation attribute buffer transformed into root tile space.
44
44
  * @type {undefined|Float32Array}
45
45
  * @private
46
46
  */
47
47
  this._rotations = undefined;
48
48
 
49
49
  /**
50
- * Local copy of the scale attribute buffer that has been transformed into root tile space. Originals are kept in the gltf loader.
51
- * Used for rendering
50
+ * Local copy of the scale attribute buffer transformed into root tile space.
52
51
  * @type {undefined|Float32Array}
53
52
  * @private
54
53
  */
@@ -112,6 +111,14 @@ function GaussianSplat3DTileContent(loader, tileset, tile, resource) {
112
111
  * @private
113
112
  */
114
113
  this._packedSphericalHarmonicsData = undefined;
114
+
115
+ /**
116
+ * Cached local-space-to-root transform used for the last splat bake.
117
+ * When unchanged, the transformed buffers can be reused directly.
118
+ * @type {undefined|Matrix4}
119
+ * @private
120
+ */
121
+ this._lastSplatTransform = undefined;
115
122
  }
116
123
 
117
124
  /**
@@ -199,9 +206,7 @@ Object.defineProperties(GaussianSplat3DTileContent.prototype, {
199
206
  */
200
207
  geometryByteLength: {
201
208
  get: function () {
202
- return this.gltfPrimitive.attributes.reduce((totalLength, attribute) => {
203
- return totalLength + attribute.byteLength;
204
- }, 0);
209
+ return 0;
205
210
  },
206
211
  },
207
212
  /**
@@ -213,9 +218,12 @@ Object.defineProperties(GaussianSplat3DTileContent.prototype, {
213
218
  */
214
219
  texturesByteLength: {
215
220
  get: function () {
216
- const texture = this._tileset.gaussianSplatPrimitive.gaussianSplatTexture;
217
- const selectedTileLength =
218
- this._tileset.gaussianSplatPrimitive.selectedTileLength;
221
+ const primitive = this._tileset?.gaussianSplatPrimitive;
222
+ if (!defined(primitive)) {
223
+ return 0;
224
+ }
225
+ const texture = primitive.gaussianSplatTexture;
226
+ const selectedTileLength = primitive.selectedTileLength;
219
227
  if (!defined(texture) || selectedTileLength === 0) {
220
228
  return 0;
221
229
  }
@@ -363,7 +371,7 @@ Object.defineProperties(GaussianSplat3DTileContent.prototype, {
363
371
  * not part of the public Cesium API.
364
372
  * </p>
365
373
  *
366
- * @type {Cesium3DTileContentGroup|undefined}
374
+ * @type {Cesium3DContentGroup|undefined}
367
375
  *
368
376
  * @private
369
377
  * @experimental This feature is using part of the 3D Tiles spec that is not final and is subject to change without Cesium's standard deprecation policy.
@@ -650,11 +658,6 @@ GaussianSplat3DTileContent.prototype.update = function (primitive, frameState) {
650
658
  const loader = this._loader;
651
659
 
652
660
  if (this._ready) {
653
- if (!this._transformed && primitive.root.content.ready) {
654
- GaussianSplatPrimitive.transformTile(this._tile);
655
- this._transformed = true;
656
- }
657
-
658
661
  return;
659
662
  }
660
663
 
@@ -670,26 +673,24 @@ GaussianSplat3DTileContent.prototype.update = function (primitive, frameState) {
670
673
  this.worldTransform = loader.components.scene.nodes[0].matrix;
671
674
  this._ready = true;
672
675
 
673
- this._positions = new Float32Array(
674
- ModelUtility.getAttributeBySemantic(
675
- this.gltfPrimitive,
676
- VertexAttributeSemantic.POSITION,
677
- ).typedArray,
678
- );
679
-
680
- this._rotations = new Float32Array(
681
- ModelUtility.getAttributeBySemantic(
682
- this.gltfPrimitive,
683
- VertexAttributeSemantic.ROTATION,
684
- ).typedArray,
685
- );
686
-
687
- this._scales = new Float32Array(
688
- ModelUtility.getAttributeBySemantic(
689
- this.gltfPrimitive,
690
- VertexAttributeSemantic.SCALE,
691
- ).typedArray,
692
- );
676
+ // SPZ decode produces Float32Array attributes for these semantics, so
677
+ // typedArray.slice() preserves the expected runtime type for current data.
678
+ // If future splat encodings use quantized integer attributes here, revisit
679
+ // this assumption before relying on the copied array type.
680
+ this._positions = ModelUtility.getAttributeBySemantic(
681
+ this.gltfPrimitive,
682
+ VertexAttributeSemantic.POSITION,
683
+ ).typedArray.slice();
684
+
685
+ this._rotations = ModelUtility.getAttributeBySemantic(
686
+ this.gltfPrimitive,
687
+ VertexAttributeSemantic.ROTATION,
688
+ ).typedArray.slice();
689
+
690
+ this._scales = ModelUtility.getAttributeBySemantic(
691
+ this.gltfPrimitive,
692
+ VertexAttributeSemantic.SCALE,
693
+ ).typedArray.slice();
693
694
 
694
695
  const { l, n } = degreeAndCoefFromAttributes(this.gltfPrimitive.attributes);
695
696
  this._sphericalHarmonicsDegree = l;
@@ -799,14 +800,6 @@ GaussianSplat3DTileContent.prototype.isDestroyed = function () {
799
800
  GaussianSplat3DTileContent.prototype.destroy = function () {
800
801
  this.splatPrimitive = undefined;
801
802
 
802
- if (
803
- defined(this._tileset.gaussianSplatPrimitive) &&
804
- !this._tileset.gaussianSplatPrimitive.isDestroyed()
805
- ) {
806
- this._tileset.gaussianSplatPrimitive.destroy();
807
- }
808
- this._tileset.gaussianSplatPrimitive = undefined;
809
-
810
803
  this._tile = undefined;
811
804
  this._tileset = undefined;
812
805
  this._resource = undefined;
@@ -814,6 +807,7 @@ GaussianSplat3DTileContent.prototype.destroy = function () {
814
807
  this._group = undefined;
815
808
  this._metadata = undefined;
816
809
  this._resourcesLoaded = false;
810
+ this._lastSplatTransform = undefined;
817
811
 
818
812
  if (defined(this._loader)) {
819
813
  this._loader.destroy();