@cesium/engine 18.3.1-ion.1 → 20.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 (192) hide show
  1. package/Build/ThirdParty/Workers/pako_deflate.min.js +3 -3
  2. package/Build/ThirdParty/Workers/pako_inflate.min.js +3 -3
  3. package/Build/ThirdParty/Workers/z-worker-pako.js +80 -89
  4. package/Build/Workers/{chunk-G7F2CKBW.js → chunk-22LUVCO3.js} +2 -2
  5. package/Build/Workers/{chunk-AIBIEA2N.js → chunk-3BO4XBWM.js} +12 -12
  6. package/Build/Workers/{chunk-LPLMZKZS.js → chunk-3SQPZVG4.js} +1 -1
  7. package/Build/Workers/{chunk-KQ7OYXT6.js → chunk-4O5SZ2RE.js} +3 -3
  8. package/Build/Workers/{chunk-EF747DYS.js → chunk-4UIKSIEZ.js} +9 -9
  9. package/Build/Workers/{chunk-LDFRBRJO.js → chunk-5FZEM66Y.js} +12 -12
  10. package/Build/Workers/{chunk-Z7UO3S7L.js → chunk-5G56VVL3.js} +10 -10
  11. package/Build/Workers/{chunk-KUVAFSVU.js → chunk-5GKRDXYJ.js} +12 -12
  12. package/Build/Workers/{chunk-GIRJEZHU.js → chunk-5W4EBNO3.js} +14 -14
  13. package/Build/Workers/{chunk-XMFKOU5X.js → chunk-67RLCIDP.js} +7 -7
  14. package/Build/Workers/{chunk-ACOAKTBU.js → chunk-74VODBWB.js} +4 -4
  15. package/Build/Workers/{chunk-QTFE5TBC.js → chunk-7HOD2LGH.js} +10 -10
  16. package/Build/Workers/{chunk-GOSJZP7N.js → chunk-D25QOWHR.js} +1 -1
  17. package/Build/Workers/{chunk-5UWLMG6V.js → chunk-D63DK275.js} +7 -7
  18. package/Build/Workers/{chunk-4JMMKZ4N.js → chunk-EHOOC4HJ.js} +5 -5
  19. package/Build/Workers/{chunk-PFTYXAVG.js → chunk-ELI5ZYDR.js} +5 -5
  20. package/Build/Workers/{chunk-RQRKALHB.js → chunk-FGF4ETPY.js} +9 -9
  21. package/Build/Workers/{chunk-YPMSP4IH.js → chunk-FKWL63D4.js} +5 -5
  22. package/Build/Workers/{chunk-IC5M3JRR.js → chunk-FLH3ZH2X.js} +4 -4
  23. package/Build/Workers/{chunk-5DF22LFV.js → chunk-HDOFAYEE.js} +16 -16
  24. package/Build/Workers/{chunk-37V6UO2J.js → chunk-HHUHFFYN.js} +5 -5
  25. package/Build/Workers/{chunk-GSLSXQGX.js → chunk-IHUXLSNT.js} +5 -4
  26. package/Build/Workers/{chunk-K4HUWRWA.js → chunk-IJM2HVTV.js} +1 -1
  27. package/Build/Workers/{chunk-AKLRSDAY.js → chunk-IPXMWP5Z.js} +6 -6
  28. package/Build/Workers/{chunk-G6I5XO4E.js → chunk-IWKYS6RV.js} +6 -6
  29. package/Build/Workers/{chunk-RVQ7LHW3.js → chunk-JMX3P7DE.js} +8 -8
  30. package/Build/Workers/{chunk-OQNQNBEM.js → chunk-JQSMAZAT.js} +9 -9
  31. package/Build/Workers/{chunk-GGNZKIG3.js → chunk-JRLT2FQV.js} +8 -8
  32. package/Build/Workers/{chunk-GK5WVMVN.js → chunk-KRXL3KZL.js} +13 -13
  33. package/Build/Workers/{chunk-OVXYMPQ7.js → chunk-KWB7PPVO.js} +2 -2
  34. package/Build/Workers/{chunk-DG4CHTQN.js → chunk-M62PWLGC.js} +16 -16
  35. package/Build/Workers/{chunk-T3UE5LOS.js → chunk-MSLO3MQF.js} +5 -5
  36. package/Build/Workers/{chunk-ZGH3R3CO.js → chunk-MZZK44UI.js} +6 -6
  37. package/Build/Workers/{chunk-3T2QV5NN.js → chunk-NB2NKFJL.js} +6 -6
  38. package/Build/Workers/{chunk-W2EMENZQ.js → chunk-NJYFQE5B.js} +1 -1
  39. package/Build/Workers/{chunk-GG2NLIC6.js → chunk-O2O4FYNI.js} +2 -2
  40. package/Build/Workers/{chunk-6HT3OW6S.js → chunk-PZEPLREA.js} +2 -2
  41. package/Build/Workers/{chunk-MYMBUYST.js → chunk-S2RSJJQI.js} +4 -4
  42. package/Build/Workers/{chunk-QBRCP474.js → chunk-S3UYLP3X.js} +8 -8
  43. package/Build/Workers/{chunk-JVSY3BGV.js → chunk-TH3P77KJ.js} +5 -5
  44. package/Build/Workers/{chunk-4HDG7AFU.js → chunk-UGSQJYGE.js} +6 -6
  45. package/Build/Workers/{chunk-SMVRX64E.js → chunk-UUXOFY6G.js} +12 -12
  46. package/Build/Workers/{chunk-DPG3EG2U.js → chunk-V36BVRDX.js} +11 -11
  47. package/Build/Workers/{chunk-3HRMP3V7.js → chunk-VJ2DNCFT.js} +4 -4
  48. package/Build/Workers/{chunk-DH3XQXDD.js → chunk-VQUVJWBK.js} +4 -4
  49. package/Build/Workers/{chunk-AJANTRVW.js → chunk-VWQWZ7OL.js} +5 -5
  50. package/Build/Workers/{chunk-XPXBRZXF.js → chunk-VXBNLAG4.js} +7 -7
  51. package/Build/Workers/{chunk-GXEQK7P4.js → chunk-W3KNMQT2.js} +6 -6
  52. package/Build/Workers/{chunk-5RUDB5R4.js → chunk-WIGH3CPD.js} +2 -2
  53. package/Build/Workers/{chunk-GMNXNBM4.js → chunk-XVHLXVN3.js} +1 -1
  54. package/Build/Workers/{chunk-KSNUH6WJ.js → chunk-YHB3RNF2.js} +4 -4
  55. package/Build/Workers/{chunk-BTXGNWFF.js → chunk-ZSHDRKLT.js} +4 -4
  56. package/Build/Workers/combineGeometry.js +21 -21
  57. package/Build/Workers/createBoxGeometry.js +15 -15
  58. package/Build/Workers/createBoxOutlineGeometry.js +13 -13
  59. package/Build/Workers/createCircleGeometry.js +23 -23
  60. package/Build/Workers/createCircleOutlineGeometry.js +16 -16
  61. package/Build/Workers/createCoplanarPolygonGeometry.js +30 -30
  62. package/Build/Workers/createCoplanarPolygonOutlineGeometry.js +28 -28
  63. package/Build/Workers/createCorridorGeometry.js +26 -26
  64. package/Build/Workers/createCorridorOutlineGeometry.js +25 -25
  65. package/Build/Workers/createCylinderGeometry.js +17 -17
  66. package/Build/Workers/createCylinderOutlineGeometry.js +15 -15
  67. package/Build/Workers/createEllipseGeometry.js +23 -23
  68. package/Build/Workers/createEllipseOutlineGeometry.js +16 -16
  69. package/Build/Workers/createEllipsoidGeometry.js +16 -16
  70. package/Build/Workers/createEllipsoidOutlineGeometry.js +15 -15
  71. package/Build/Workers/createFrustumGeometry.js +15 -15
  72. package/Build/Workers/createFrustumOutlineGeometry.js +15 -15
  73. package/Build/Workers/createGeometry.js +21 -21
  74. package/Build/Workers/createGroundPolylineGeometry.js +19 -19
  75. package/Build/Workers/createPlaneGeometry.js +13 -13
  76. package/Build/Workers/createPlaneOutlineGeometry.js +12 -12
  77. package/Build/Workers/createPolygonGeometry.js +29 -29
  78. package/Build/Workers/createPolygonOutlineGeometry.js +27 -27
  79. package/Build/Workers/createPolylineGeometry.js +22 -22
  80. package/Build/Workers/createPolylineVolumeGeometry.js +28 -28
  81. package/Build/Workers/createPolylineVolumeOutlineGeometry.js +24 -24
  82. package/Build/Workers/createRectangleGeometry.js +24 -24
  83. package/Build/Workers/createRectangleOutlineGeometry.js +17 -17
  84. package/Build/Workers/createSimplePolylineGeometry.js +20 -20
  85. package/Build/Workers/createSphereGeometry.js +16 -16
  86. package/Build/Workers/createSphereOutlineGeometry.js +15 -15
  87. package/Build/Workers/createTaskProcessorWorker.js +3 -3
  88. package/Build/Workers/createVectorTileClampedPolylines.js +12 -12
  89. package/Build/Workers/createVectorTileGeometries.js +21 -21
  90. package/Build/Workers/createVectorTilePoints.js +11 -11
  91. package/Build/Workers/createVectorTilePolygons.js +19 -19
  92. package/Build/Workers/createVectorTilePolylines.js +12 -12
  93. package/Build/Workers/createVerticesFromGoogleEarthEnterpriseBuffer.js +19 -19
  94. package/Build/Workers/createVerticesFromHeightmap.js +25 -25
  95. package/Build/Workers/createVerticesFromQuantizedTerrainMesh.js +16 -16
  96. package/Build/Workers/createWallGeometry.js +21 -21
  97. package/Build/Workers/createWallOutlineGeometry.js +20 -20
  98. package/Build/Workers/decodeDraco.js +10 -10
  99. package/Build/Workers/decodeGoogleEarthEnterprisePacket.js +5 -5
  100. package/Build/Workers/decodeI3S.js +9 -9
  101. package/Build/Workers/gaussianSplatSorter.js +4 -4
  102. package/Build/Workers/gaussianSplatTextureGenerator.js +4 -4
  103. package/Build/Workers/transcodeKTX2.js +17 -16
  104. package/Build/Workers/transferTypedArrayTest.js +1 -1
  105. package/Build/Workers/upsampleQuantizedTerrainMesh.js +19 -19
  106. package/LICENSE.md +32 -25
  107. package/Source/Core/Ellipsoid.js +9 -0
  108. package/Source/Core/ITwinPlatform.js +8 -1
  109. package/Source/Core/Ion.js +1 -1
  110. package/Source/Core/IonResource.js +14 -8
  111. package/Source/Core/ScreenSpaceEventHandler.js +3 -3
  112. package/Source/Core/addAllToArray.js +40 -0
  113. package/Source/DataSources/StaticGroundGeometryPerMaterialBatch.js +54 -26
  114. package/Source/Renderer/Context.js +8 -4
  115. package/Source/Renderer/Renderbuffer.js +4 -2
  116. package/Source/Renderer/Sampler.js +13 -0
  117. package/Source/Renderer/ShaderBuilder.js +7 -6
  118. package/Source/Renderer/SharedContext.js +186 -0
  119. package/Source/Renderer/Texture.js +4 -5
  120. package/Source/Renderer/Texture3D.js +17 -7
  121. package/Source/Scene/ArcGisMapService.js +1 -1
  122. package/Source/Scene/BillboardCollection.js +1 -1
  123. package/Source/Scene/BingMapsImageryProvider.js +1 -1
  124. package/Source/Scene/Cesium3DTileBatchTable.js +6 -4
  125. package/Source/Scene/Cesium3DTileContentFactory.js +7 -16
  126. package/Source/Scene/Cesium3DTileStyle.js +4 -3
  127. package/Source/Scene/Cesium3DTileset.js +2 -2
  128. package/Source/Scene/ConditionsExpression.js +3 -2
  129. package/Source/Scene/GaussianSplat3DTileContent.js +253 -9
  130. package/Source/Scene/GaussianSplatPrimitive.js +167 -15
  131. package/Source/Scene/GltfLoader.js +23 -4
  132. package/Source/Scene/GltfPipeline/ForEach.js +7 -7
  133. package/Source/Scene/GltfPipeline/addDefaults.js +1 -2
  134. package/Source/Scene/GltfPipeline/addToArray.js +2 -0
  135. package/Source/Scene/GltfPipeline/findAccessorMinMax.js +1 -1
  136. package/Source/Scene/GltfPipeline/getComponentReader.js +16 -16
  137. package/Source/Scene/GltfPipeline/moveTechniqueRenderStates.js +1 -1
  138. package/Source/Scene/GltfPipeline/moveTechniquesToExtension.js +3 -3
  139. package/Source/Scene/GltfPipeline/parseGlb.js +1 -1
  140. package/Source/Scene/GltfPipeline/readAccessorPacked.js +2 -2
  141. package/Source/Scene/GltfPipeline/removeUnusedElements.js +5 -6
  142. package/Source/Scene/GltfPipeline/updateAccessorComponentTypes.js +1 -1
  143. package/Source/Scene/GltfPipeline/updateVersion.js +13 -13
  144. package/Source/Scene/GltfSpzLoader.js +3 -1
  145. package/Source/Scene/GltfVertexBufferLoader.js +56 -2
  146. package/Source/Scene/HeightReference.js +1 -1
  147. package/Source/Scene/ITwinData.js +49 -25
  148. package/Source/Scene/ImageBasedLighting.js +6 -2
  149. package/Source/Scene/ImageryLayer.js +10 -10
  150. package/Source/Scene/MetadataTableProperty.js +2 -1
  151. package/Source/Scene/Model/ClassificationModelDrawCommand.js +7 -6
  152. package/Source/Scene/Model/GeoJsonLoader.js +3 -1
  153. package/Source/Scene/Model/ImageryConfiguration.js +1 -0
  154. package/Source/Scene/Model/ImageryPipelineStage.js +8 -2
  155. package/Source/Scene/Model/InstancingPipelineStage.js +3 -8
  156. package/Source/Scene/Model/MaterialPipelineStage.js +10 -1
  157. package/Source/Scene/Model/Model.js +3 -0
  158. package/Source/Scene/Model/ModelClippingPolygonsPipelineStage.js +8 -2
  159. package/Source/Scene/Model/ModelImagery.js +3 -0
  160. package/Source/Scene/Model/ModelSceneGraph.js +2 -1
  161. package/Source/Scene/Model/ModelUtility.js +1 -0
  162. package/Source/Scene/Model/PntsLoader.js +7 -3
  163. package/Source/Scene/Picking.js +41 -1
  164. package/Source/Scene/PntsParser.js +6 -3
  165. package/Source/Scene/Primitive.js +0 -1
  166. package/Source/Scene/PrimitiveCollection.js +32 -6
  167. package/Source/Scene/PrimitiveLoadPlan.js +1 -37
  168. package/Source/Scene/PropertyTable.js +7 -12
  169. package/Source/Scene/Scene.js +41 -32
  170. package/Source/Scene/ScreenSpaceCameraController.js +2 -0
  171. package/Source/Scene/VertexAttributeSemantic.js +4 -2
  172. package/Source/Scene/WebMapServiceImageryProvider.js +3 -2
  173. package/Source/Scene/WebMapTileServiceImageryProvider.js +0 -22
  174. package/Source/Scene/getMeshPrimitives.js +72 -0
  175. package/Source/Shaders/Builtin/Functions/modelToWindowCoordinates.glsl +2 -1
  176. package/Source/Shaders/Builtin/Functions/modelToWindowCoordinates.js +2 -1
  177. package/Source/Shaders/EllipsoidVS.glsl +4 -4
  178. package/Source/Shaders/EllipsoidVS.js +4 -4
  179. package/Source/Shaders/FXAA3_11.glsl +2 -0
  180. package/Source/Shaders/FXAA3_11.js +2 -0
  181. package/Source/Shaders/GlobeVS.glsl +2 -1
  182. package/Source/Shaders/GlobeVS.js +2 -1
  183. package/Source/Shaders/PrimitiveGaussianSplatFS.glsl +5 -5
  184. package/Source/Shaders/PrimitiveGaussianSplatFS.js +5 -5
  185. package/Source/Shaders/PrimitiveGaussianSplatVS.glsl +102 -5
  186. package/Source/Shaders/PrimitiveGaussianSplatVS.js +102 -5
  187. package/Source/Shaders/SkyAtmosphereVS.glsl +2 -1
  188. package/Source/Shaders/SkyAtmosphereVS.js +2 -1
  189. package/Source/ThirdParty/Workers/z-worker-pako.js +1 -1
  190. package/index.d.ts +191 -54
  191. package/index.js +93 -90
  192. package/package.json +4 -4
@@ -7,16 +7,16 @@ import GaussianSplatPrimitive from "./GaussianSplatPrimitive.js";
7
7
  import destroyObject from "../Core/destroyObject.js";
8
8
  import ModelUtility from "./Model/ModelUtility.js";
9
9
  import VertexAttributeSemantic from "./VertexAttributeSemantic.js";
10
+ import deprecationWarning from "../Core/deprecationWarning.js";
10
11
 
11
12
  /**
12
- * Represents the contents of a glTF or glb using the {@link https://github.com/CesiumGS/glTF/tree/draft-spz-splat-compression/extensions/2.0/Khronos/KHR_spz_gaussian_splats_compression|KHR_spz_gaussian_splats_compression} extension.
13
+ * Represents the contents of a glTF or glb using the {@link https://github.com/CesiumGS/glTF/tree/draft-splat-spz/extensions/2.0/Khronos/KHR_gaussian_splatting | KHR_gaussian_splatting} and {@link https://github.com/CesiumGS/glTF/tree/draft-splat-spz/extensions/2.0/Khronos/KHR_gaussian_splatting_compression_spz_2 | KHR_gaussian_splatting_compression_spz_2} extensions.
13
14
  * <p>
14
15
  * Implements the {@link Cesium3DTileContent} interface.
15
16
  * </p>
16
17
  *
17
18
  * @alias GaussianSplat3DTileContent
18
19
  * @constructor
19
- * @private
20
20
  */
21
21
  function GaussianSplat3DTileContent(loader, tileset, tile, resource) {
22
22
  this._tileset = tileset;
@@ -46,7 +46,7 @@ function GaussianSplat3DTileContent(loader, tileset, tile, resource) {
46
46
  * @type {undefined|Primitive}
47
47
  * @private
48
48
  */
49
- this.splatPrimitive = undefined;
49
+ this.gltfPrimitive = undefined;
50
50
 
51
51
  /**
52
52
  * Transform matrix to turn model coordinates into world coordinates.
@@ -78,8 +78,66 @@ function GaussianSplat3DTileContent(loader, tileset, tile, resource) {
78
78
  * @private
79
79
  */
80
80
  this._transformed = false;
81
+
82
+ /**
83
+ * The degree of the spherical harmonics used for the Gaussian splats.
84
+ * @type {number}
85
+ * @private
86
+ */
87
+ this._sphericalHarmonicsDegree = 0;
88
+
89
+ /**
90
+ * The number of spherical harmonic coefficients used for the Gaussian splats.
91
+ * @type {number}
92
+ * @private
93
+ */
94
+ this._sphericalHarmonicsCoefficientCount = 0;
95
+
96
+ /**
97
+ * Spherical Harmonic data that has been packed for use in a texture or shader.
98
+ * @type {undefined|Uint32Array}
99
+ * @private
100
+ */
101
+ this._packedSphericalHarmonicsData = undefined;
81
102
  }
82
103
 
104
+ /**
105
+ * Performs checks to ensure that the provided tileset has the Gaussian Splatting extensions.
106
+ *
107
+ * @param {Cesium3DTileset} tileset The tileset to check for the extensions.
108
+ * @returns {boolean} Returns <code>true</code> if the necessary extensions are included in the tileset.
109
+ * @static
110
+ */
111
+ GaussianSplat3DTileContent.tilesetRequiresGaussianSplattingExt = function (
112
+ tileset,
113
+ ) {
114
+ let hasGaussianSplatExtension = false;
115
+ let hasLegacyGaussianSplatExtension = false;
116
+ if (tileset.isGltfExtensionRequired instanceof Function) {
117
+ hasGaussianSplatExtension =
118
+ tileset.isGltfExtensionRequired("KHR_gaussian_splatting") &&
119
+ tileset.isGltfExtensionRequired(
120
+ "KHR_gaussian_splatting_compression_spz_2",
121
+ );
122
+
123
+ hasLegacyGaussianSplatExtension = tileset.isGltfExtensionRequired(
124
+ "KHR_spz_gaussian_splats_compression",
125
+ );
126
+ }
127
+
128
+ if (hasLegacyGaussianSplatExtension) {
129
+ deprecationWarning(
130
+ "KHR_spz_gaussian_splats_compression",
131
+ "Support for the original KHR_spz_gaussian_splats_compression extension has been deprecated in favor " +
132
+ "of the up to date KHR_gaussian_splatting and KHR_gaussian_splatting_compression_spz_2 extensions and will be " +
133
+ "removed in CesiumJS 1.135.\n\nPlease retile your tileset with the KHR_gaussian_splatting and " +
134
+ "KHR_gaussian_splatting_compression_spz_2 extensions.",
135
+ );
136
+ }
137
+
138
+ return hasGaussianSplatExtension || hasLegacyGaussianSplatExtension;
139
+ };
140
+
83
141
  Object.defineProperties(GaussianSplat3DTileContent.prototype, {
84
142
  /**
85
143
  * Gets the number of features in the tile. Currently this is always zero.
@@ -106,7 +164,7 @@ Object.defineProperties(GaussianSplat3DTileContent.prototype, {
106
164
  */
107
165
  pointsLength: {
108
166
  get: function () {
109
- return this.splatPrimitive.attributes[0].count;
167
+ return this.gltfPrimitive.attributes[0].count;
110
168
  },
111
169
  },
112
170
  /**
@@ -131,7 +189,7 @@ Object.defineProperties(GaussianSplat3DTileContent.prototype, {
131
189
  */
132
190
  geometryByteLength: {
133
191
  get: function () {
134
- return this.splatPrimitive.attributes.reduce((totalLength, attribute) => {
192
+ return this.gltfPrimitive.attributes.reduce((totalLength, attribute) => {
135
193
  return totalLength + attribute.byteLength;
136
194
  }, 0);
137
195
  },
@@ -309,8 +367,188 @@ Object.defineProperties(GaussianSplat3DTileContent.prototype, {
309
367
  this._group = value;
310
368
  },
311
369
  },
370
+
371
+ /**
372
+ * The number of spherical harmonic coefficients used for the Gaussian splats.
373
+ * @type {number}
374
+ * @private
375
+ * @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.
376
+ */
377
+ sphericalHarmonicsCoefficientCount: {
378
+ get: function () {
379
+ return this._sphericalHarmonicsCoefficientCount;
380
+ },
381
+ },
382
+ /**
383
+ * The degree of the spherical harmonics used for the Gaussian splats.
384
+ * @type {number}
385
+ * @private
386
+ * @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.
387
+ */
388
+ sphericalHarmonicsDegree: {
389
+ get: function () {
390
+ return this._sphericalHarmonicsDegree;
391
+ },
392
+ },
393
+
394
+ /**
395
+ * The packed spherical harmonic data for the Gaussian splats for use a shader or texture.
396
+ * @type {number}
397
+ * @private
398
+ * @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.
399
+ */
400
+ packedSphericalHarmonicsData: {
401
+ get: function () {
402
+ return this._packedSphericalHarmonicsData;
403
+ },
404
+ },
312
405
  });
313
406
 
407
+ function getShAttributePrefix(attribute) {
408
+ const prefix = attribute.startsWith("KHR_gaussian_splatting:")
409
+ ? "KHR_gaussian_splatting:"
410
+ : "_";
411
+ return `${prefix}SH_DEGREE_`;
412
+ }
413
+
414
+ /**
415
+ * Determine Spherical Harmonics degree and coefficient count from attributes
416
+ * @param {Attribute[]} attributes - The list of glTF attributes.
417
+ * @returns {object} An object containing the degree (l) and coefficient (n).
418
+ * @private
419
+ */
420
+ function degreeAndCoefFromAttributes(attributes) {
421
+ const shAttributes = attributes.filter((attr) =>
422
+ attr.name.includes("SH_DEGREE_"),
423
+ );
424
+
425
+ switch (shAttributes.length) {
426
+ default:
427
+ case 0:
428
+ return { l: 0, n: 0 };
429
+ case 3:
430
+ return { l: 1, n: 9 };
431
+ case 8:
432
+ return { l: 2, n: 24 };
433
+ case 15:
434
+ return { l: 3, n: 45 };
435
+ }
436
+ }
437
+
438
+ /**
439
+ * Converts a 32-bit floating point number to a 16-bit floating point number.
440
+ * @param {number} float32 input
441
+ * @returns {number} Half precision float
442
+ * @private
443
+ */
444
+ const buffer = new ArrayBuffer(4);
445
+ const floatView = new Float32Array(buffer);
446
+ const intView = new Uint32Array(buffer);
447
+
448
+ function float32ToFloat16(float32) {
449
+ floatView[0] = float32;
450
+ const bits = intView[0];
451
+
452
+ const sign = (bits >> 31) & 0x1;
453
+ const exponent = (bits >> 23) & 0xff;
454
+ const mantissa = bits & 0x7fffff;
455
+
456
+ let half;
457
+
458
+ if (exponent === 0xff) {
459
+ half = (sign << 15) | (0x1f << 10) | (mantissa ? 0x200 : 0);
460
+ } else if (exponent === 0) {
461
+ half = sign << 15;
462
+ } else {
463
+ const newExponent = exponent - 127 + 15;
464
+ if (newExponent >= 31) {
465
+ half = (sign << 15) | (0x1f << 10);
466
+ } else if (newExponent <= 0) {
467
+ half = sign << 15;
468
+ } else {
469
+ half = (sign << 15) | (newExponent << 10) | (mantissa >>> 13);
470
+ }
471
+ }
472
+
473
+ return half;
474
+ }
475
+
476
+ /**
477
+ * Extracts the spherical harmonic degree and coefficient from the attribute name.
478
+ * @param {string} attribute - The attribute name.
479
+ * @returns {object} An object containing the degree (l) and coefficient (n).
480
+ * @private
481
+ */
482
+ function extractSHDegreeAndCoef(attribute) {
483
+ const prefix = getShAttributePrefix(attribute);
484
+ const separator = "_COEF_";
485
+
486
+ const lStart = prefix.length;
487
+ const coefIndex = attribute.indexOf(separator, lStart);
488
+
489
+ const l = parseInt(attribute.slice(lStart, coefIndex), 10);
490
+ const n = parseInt(attribute.slice(coefIndex + separator.length), 10);
491
+
492
+ return { l, n };
493
+ }
494
+
495
+ /**
496
+ * Packs spherical harmonic data into half-precision floats.
497
+ * @param {GaussianSplat3DTileContent} tileContent - The tile content containing the spherical harmonic data.
498
+ * @returns {Uint32Array} - The Float16 packed spherical harmonic data.
499
+ * @private
500
+ */
501
+ function packSphericalHarmonicsData(tileContent) {
502
+ const degree = tileContent.sphericalHarmonicsDegree;
503
+ const coefs = tileContent.sphericalHarmonicsCoefficientCount;
504
+ const totalLength = tileContent.pointsLength * (coefs * (2 / 3)); //3 packs into 2
505
+ const packedData = new Uint32Array(totalLength);
506
+
507
+ const shAttributes = tileContent.gltfPrimitive.attributes.filter((attr) =>
508
+ attr.name.includes("SH_DEGREE_"),
509
+ );
510
+ let stride = 0;
511
+ const base = [0, 9, 24];
512
+ switch (degree) {
513
+ case 1:
514
+ stride = 9;
515
+ break;
516
+ case 2:
517
+ stride = 24;
518
+ break;
519
+ case 3:
520
+ stride = 45;
521
+ break;
522
+ }
523
+ shAttributes.sort((a, b) => {
524
+ if (a.name < b.name) {
525
+ return -1;
526
+ }
527
+ if (a.name > b.name) {
528
+ return 1;
529
+ }
530
+
531
+ return 0;
532
+ });
533
+ const packedStride = stride * (2 / 3);
534
+ for (let i = 0; i < shAttributes.length; i++) {
535
+ const { l, n } = extractSHDegreeAndCoef(shAttributes[i].name);
536
+ for (let j = 0; j < tileContent.pointsLength; j++) {
537
+ //interleave the data
538
+ const packedBase = (base[l - 1] * 2) / 3;
539
+ const idx = j * packedStride + packedBase + n * 2;
540
+ const src = j * 3;
541
+ packedData[idx] =
542
+ float32ToFloat16(shAttributes[i].typedArray[src]) |
543
+ (float32ToFloat16(shAttributes[i].typedArray[src + 1]) << 16);
544
+ packedData[idx + 1] = float32ToFloat16(
545
+ shAttributes[i].typedArray[src + 2],
546
+ );
547
+ }
548
+ }
549
+ return packedData;
550
+ }
551
+
314
552
  /**
315
553
  * Creates a new instance of {@link GaussianSplat3DTileContent} from a glTF or glb resource.
316
554
  *
@@ -387,31 +625,37 @@ GaussianSplat3DTileContent.prototype.update = function (primitive, frameState) {
387
625
  }
388
626
 
389
627
  if (this._resourcesLoaded) {
390
- this.splatPrimitive = loader.components.scene.nodes[0].primitives[0];
628
+ this.gltfPrimitive = loader.components.scene.nodes[0].primitives[0];
391
629
  this.worldTransform = loader.components.scene.nodes[0].matrix;
392
630
  this._ready = true;
393
631
 
394
632
  this._originalPositions = new Float32Array(
395
633
  ModelUtility.getAttributeBySemantic(
396
- this.splatPrimitive,
634
+ this.gltfPrimitive,
397
635
  VertexAttributeSemantic.POSITION,
398
636
  ).typedArray,
399
637
  );
400
638
 
401
639
  this._originalRotations = new Float32Array(
402
640
  ModelUtility.getAttributeBySemantic(
403
- this.splatPrimitive,
641
+ this.gltfPrimitive,
404
642
  VertexAttributeSemantic.ROTATION,
405
643
  ).typedArray,
406
644
  );
407
645
 
408
646
  this._originalScales = new Float32Array(
409
647
  ModelUtility.getAttributeBySemantic(
410
- this.splatPrimitive,
648
+ this.gltfPrimitive,
411
649
  VertexAttributeSemantic.SCALE,
412
650
  ).typedArray,
413
651
  );
414
652
 
653
+ const { l, n } = degreeAndCoefFromAttributes(this.gltfPrimitive.attributes);
654
+ this._sphericalHarmonicsDegree = l;
655
+ this._sphericalHarmonicsCoefficientCount = n;
656
+
657
+ this._packedSphericalHarmonicsData = packSphericalHarmonicsData(this);
658
+
415
659
  return;
416
660
  }
417
661
 
@@ -31,10 +31,12 @@ import Cartesian3 from "../Core/Cartesian3.js";
31
31
  import Quaternion from "../Core/Quaternion.js";
32
32
  import SplitDirection from "./SplitDirection.js";
33
33
  import destroyObject from "../Core/destroyObject.js";
34
+ import ContextLimits from "../Renderer/ContextLimits.js";
34
35
 
35
36
  const scratchMatrix4A = new Matrix4();
36
37
  const scratchMatrix4B = new Matrix4();
37
38
  const scratchMatrix4C = new Matrix4();
39
+ const scratchMatrix4D = new Matrix4();
38
40
 
39
41
  const GaussianSplatSortingState = {
40
42
  IDLE: 0,
@@ -44,6 +46,25 @@ const GaussianSplatSortingState = {
44
46
  ERROR: 4,
45
47
  };
46
48
 
49
+ function createSphericalHarmonicsTexture(context, shData) {
50
+ const texture = new Texture({
51
+ context: context,
52
+ source: {
53
+ width: shData.width,
54
+ height: shData.height,
55
+ arrayBufferView: shData.data,
56
+ },
57
+ preMultiplyAlpha: false,
58
+ skipColorSpaceConversion: true,
59
+ pixelFormat: PixelFormat.RG_INTEGER,
60
+ pixelDatatype: PixelDatatype.UNSIGNED_INT,
61
+ flipY: false,
62
+ sampler: Sampler.NEAREST,
63
+ });
64
+
65
+ return texture;
66
+ }
67
+
47
68
  function createGaussianSplatTexture(context, splatTextureData) {
48
69
  return new Texture({
49
70
  context: context,
@@ -64,7 +85,7 @@ function createGaussianSplatTexture(context, splatTextureData) {
64
85
  /** A primitive that renders Gaussian splats.
65
86
  * <p>
66
87
  * This primitive is used to render Gaussian splats in a 3D Tileset.
67
- * It is designed to work with the KHR_spz_gaussian_splats_compression extension.
88
+ * It is designed to work with the KHR_gaussian_splatting and KHR_gaussian_splatting_compression_spz_2 extensions.
68
89
  * </p>
69
90
  * @alias GaussianSplatPrimitive
70
91
  * @constructor
@@ -148,6 +169,14 @@ function GaussianSplatPrimitive(options) {
148
169
  * @see {@link GaussianSplatTextureGenerator}
149
170
  */
150
171
  this.gaussianSplatTexture = undefined;
172
+
173
+ /**
174
+ * The texture used to store the spherical harmonics coefficients for the Gaussian splats.
175
+ * @type {undefined|Texture}
176
+ * @private
177
+ */
178
+ this.sphericalHarmonicsTexture = undefined;
179
+
151
180
  /**
152
181
  * The last width of the Gaussian splat texture.
153
182
  * This is used to track changes in the texture size and update the primitive accordingly.
@@ -395,7 +424,7 @@ GaussianSplatPrimitive.prototype.onTileVisible = function (tile) {};
395
424
  */
396
425
  GaussianSplatPrimitive.transformTile = function (tile) {
397
426
  const computedTransform = tile.computedTransform;
398
- const splatPrimitive = tile.content.splatPrimitive;
427
+ const gltfPrimitive = tile.content.gltfPrimitive;
399
428
  const gaussianSplatPrimitive = tile.tileset.gaussianSplatPrimitive;
400
429
 
401
430
  const computedModelMatrix = Matrix4.multiplyTransformation(
@@ -425,17 +454,17 @@ GaussianSplatPrimitive.transformTile = function (tile) {
425
454
  const rotations = tile.content._originalRotations;
426
455
  const scales = tile.content._originalScales;
427
456
  const attributePositions = ModelUtility.getAttributeBySemantic(
428
- splatPrimitive,
457
+ gltfPrimitive,
429
458
  VertexAttributeSemantic.POSITION,
430
459
  ).typedArray;
431
460
 
432
461
  const attributeRotations = ModelUtility.getAttributeBySemantic(
433
- splatPrimitive,
462
+ gltfPrimitive,
434
463
  VertexAttributeSemantic.ROTATION,
435
464
  ).typedArray;
436
465
 
437
466
  const attributeScales = ModelUtility.getAttributeBySemantic(
438
- splatPrimitive,
467
+ gltfPrimitive,
439
468
  VertexAttributeSemantic.SCALE,
440
469
  ).typedArray;
441
470
 
@@ -601,12 +630,69 @@ GaussianSplatPrimitive.buildGSplatDrawCommand = function (
601
630
  ShaderDestination.VERTEX,
602
631
  );
603
632
 
633
+ shaderBuilder.addUniform(
634
+ "float",
635
+ "u_sphericalHarmonicsDegree",
636
+ ShaderDestination.VERTEX,
637
+ );
638
+
639
+ shaderBuilder.addUniform("float", "u_splatScale", ShaderDestination.VERTEX);
640
+
641
+ shaderBuilder.addUniform(
642
+ "vec3",
643
+ "u_cameraPositionWC",
644
+ ShaderDestination.VERTEX,
645
+ );
646
+
647
+ shaderBuilder.addUniform(
648
+ "mat3",
649
+ "u_inverseModelRotation",
650
+ ShaderDestination.VERTEX,
651
+ );
652
+
604
653
  const uniformMap = renderResources.uniformMap;
605
654
 
606
655
  uniformMap.u_splatAttributeTexture = function () {
607
656
  return primitive.gaussianSplatTexture;
608
657
  };
609
658
 
659
+ if (primitive._sphericalHarmonicsDegree > 0) {
660
+ shaderBuilder.addDefine(
661
+ "HAS_SPHERICAL_HARMONICS",
662
+ "1",
663
+ ShaderDestination.VERTEX,
664
+ );
665
+ shaderBuilder.addUniform(
666
+ "highp usampler2D",
667
+ "u_sphericalHarmonicsTexture",
668
+ ShaderDestination.VERTEX,
669
+ );
670
+ uniformMap.u_sphericalHarmonicsTexture = function () {
671
+ return primitive.sphericalHarmonicsTexture;
672
+ };
673
+ }
674
+ uniformMap.u_sphericalHarmonicsDegree = function () {
675
+ return primitive._sphericalHarmonicsDegree;
676
+ };
677
+
678
+ uniformMap.u_cameraPositionWC = function () {
679
+ return Cartesian3.clone(frameState.camera.positionWC);
680
+ };
681
+
682
+ uniformMap.u_inverseModelRotation = function () {
683
+ const tileset = primitive._tileset;
684
+ const modelMatrix = Matrix4.multiply(
685
+ tileset.modelMatrix,
686
+ Matrix4.fromArray(tileset.root.transform),
687
+ scratchMatrix4A,
688
+ );
689
+ const inverseModelRotation = Matrix4.getRotation(
690
+ Matrix4.inverse(modelMatrix, scratchMatrix4C),
691
+ scratchMatrix4D,
692
+ );
693
+ return inverseModelRotation;
694
+ };
695
+
610
696
  uniformMap.u_splitDirection = function () {
611
697
  return primitive.splitDirection;
612
698
  };
@@ -720,7 +806,11 @@ GaussianSplatPrimitive.prototype.update = function (frameState) {
720
806
  this._rootTransform = tileset.root.computedTransform;
721
807
  }
722
808
 
723
- if (this._drawCommand && tileset.show) {
809
+ if (!tileset.show || tileset._selectedTiles.length === 0) {
810
+ return;
811
+ }
812
+
813
+ if (this._drawCommand) {
724
814
  frameState.commandList.push(this._drawCommand);
725
815
  }
726
816
 
@@ -756,6 +846,7 @@ GaussianSplatPrimitive.prototype.update = function (frameState) {
756
846
  this._scales = undefined;
757
847
  this._colors = undefined;
758
848
  this._indexes = undefined;
849
+ this._shData = undefined;
759
850
  this._needsGaussianSplatTexture = true;
760
851
  this._gaussianSplatTexturePending = false;
761
852
 
@@ -771,7 +862,7 @@ GaussianSplatPrimitive.prototype.update = function (frameState) {
771
862
  let aggregate;
772
863
  let offset = 0;
773
864
  for (const tile of tiles) {
774
- const primitive = tile.content.splatPrimitive;
865
+ const primitive = tile.content.gltfPrimitive;
775
866
  const attribute = getAttributeCallback(primitive);
776
867
  if (!defined(aggregate)) {
777
868
  aggregate = ComponentDatatype.createTypedArray(
@@ -786,42 +877,71 @@ GaussianSplatPrimitive.prototype.update = function (frameState) {
786
877
  return aggregate;
787
878
  };
788
879
 
880
+ const aggregateShData = () => {
881
+ let offset = 0;
882
+ for (const tile of tiles) {
883
+ const shData = tile.content.packedSphericalHarmonicsData;
884
+ if (tile.content.sphericalHarmonicsDegree > 0) {
885
+ if (!defined(this._shData)) {
886
+ let coefs;
887
+ switch (tile.content.sphericalHarmonicsDegree) {
888
+ case 1:
889
+ coefs = 9;
890
+ break;
891
+ case 2:
892
+ coefs = 24;
893
+ break;
894
+ case 3:
895
+ coefs = 45;
896
+ }
897
+ this._shData = new Uint32Array(totalElements * (coefs * (2 / 3)));
898
+ }
899
+ this._shData.set(shData, offset);
900
+ offset += shData.length;
901
+ }
902
+ }
903
+ };
904
+
789
905
  this._positions = aggregateAttributeValues(
790
906
  ComponentDatatype.FLOAT,
791
- (splatPrimitive) =>
907
+ (gltfPrimitive) =>
792
908
  ModelUtility.getAttributeBySemantic(
793
- splatPrimitive,
909
+ gltfPrimitive,
794
910
  VertexAttributeSemantic.POSITION,
795
911
  ),
796
912
  );
797
913
 
798
914
  this._scales = aggregateAttributeValues(
799
915
  ComponentDatatype.FLOAT,
800
- (splatPrimitive) =>
916
+ (gltfPrimitive) =>
801
917
  ModelUtility.getAttributeBySemantic(
802
- splatPrimitive,
918
+ gltfPrimitive,
803
919
  VertexAttributeSemantic.SCALE,
804
920
  ),
805
921
  );
806
922
 
807
923
  this._rotations = aggregateAttributeValues(
808
924
  ComponentDatatype.FLOAT,
809
- (splatPrimitive) =>
925
+ (gltfPrimitive) =>
810
926
  ModelUtility.getAttributeBySemantic(
811
- splatPrimitive,
927
+ gltfPrimitive,
812
928
  VertexAttributeSemantic.ROTATION,
813
929
  ),
814
930
  );
815
931
 
816
932
  this._colors = aggregateAttributeValues(
817
933
  ComponentDatatype.UNSIGNED_BYTE,
818
- (splatPrimitive) =>
934
+ (gltfPrimitive) =>
819
935
  ModelUtility.getAttributeBySemantic(
820
- splatPrimitive,
936
+ gltfPrimitive,
821
937
  VertexAttributeSemantic.COLOR,
822
938
  ),
823
939
  );
824
940
 
941
+ aggregateShData();
942
+ this._sphericalHarmonicsDegree =
943
+ tiles[0].content.sphericalHarmonicsDegree;
944
+
825
945
  this._numSplats = totalElements;
826
946
  this.selectedTileLength = tileset._selectedTiles.length;
827
947
  }
@@ -833,6 +953,38 @@ GaussianSplatPrimitive.prototype.update = function (frameState) {
833
953
  if (this._needsGaussianSplatTexture) {
834
954
  if (!this._gaussianSplatTexturePending) {
835
955
  GaussianSplatPrimitive.generateSplatTexture(this, frameState);
956
+ if (defined(this._shData)) {
957
+ const oldTex = this.sphericalHarmonicsTexture;
958
+ const width = ContextLimits.maximumTextureSize;
959
+ const dims =
960
+ tileset._selectedTiles[0].content
961
+ .sphericalHarmonicsCoefficientCount / 3;
962
+ const splatsPerRow = Math.floor(width / dims);
963
+ const floatsPerRow = splatsPerRow * (dims * 2);
964
+ const texBuf = new Uint32Array(
965
+ width * Math.ceil(this._numSplats / splatsPerRow) * 2,
966
+ );
967
+
968
+ let dataIndex = 0;
969
+ for (let i = 0; dataIndex < this._shData.length; i += width * 2) {
970
+ texBuf.set(
971
+ this._shData.subarray(dataIndex, dataIndex + floatsPerRow),
972
+ i,
973
+ );
974
+ dataIndex += floatsPerRow;
975
+ }
976
+ this.sphericalHarmonicsTexture = createSphericalHarmonicsTexture(
977
+ frameState.context,
978
+ {
979
+ data: texBuf,
980
+ width: width,
981
+ height: Math.ceil(this._numSplats / splatsPerRow),
982
+ },
983
+ );
984
+ if (defined(oldTex)) {
985
+ oldTex.destroy();
986
+ }
987
+ }
836
988
  }
837
989
  return;
838
990
  }