@cesium/engine 19.0.0 → 20.0.1

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 (135) 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 +49 -42
  4. package/Build/Workers/{chunk-ECWQXDZY.js → chunk-2K5PKWLP.js} +16 -16
  5. package/Build/Workers/{chunk-T7C73J6H.js → chunk-2MEON5V4.js} +4 -4
  6. package/Build/Workers/{chunk-AZPKFL5X.js → chunk-4MCKK5XE.js} +5 -5
  7. package/Build/Workers/{chunk-Q2QXUN33.js → chunk-4Z7AGRTU.js} +2 -2
  8. package/Build/Workers/{chunk-SOYVF5RC.js → chunk-7FEVXX5D.js} +2 -2
  9. package/Build/Workers/{chunk-RIQM3XY5.js → chunk-7MCEUVPM.js} +4 -4
  10. package/Build/Workers/{chunk-25USKS4R.js → chunk-7P7R7ERW.js} +6 -6
  11. package/Build/Workers/{chunk-MUL374P3.js → chunk-CTU7LCVZ.js} +4 -4
  12. package/Build/Workers/{chunk-DPFAUGBE.js → chunk-CZGSJ6ZG.js} +2 -2
  13. package/Build/Workers/{chunk-ESDVZ4QL.js → chunk-D4VFVSGU.js} +10 -10
  14. package/Build/Workers/{chunk-JZVUMRYA.js → chunk-DAGWF5MM.js} +13 -13
  15. package/Build/Workers/{chunk-VCCR35R6.js → chunk-DAZVD3AH.js} +11 -11
  16. package/Build/Workers/{chunk-GVO3YIU2.js → chunk-DJCPJJSP.js} +4 -4
  17. package/Build/Workers/{chunk-DXYAD4ED.js → chunk-DNMSVJ4S.js} +1 -1
  18. package/Build/Workers/{chunk-Y3PM6G2V.js → chunk-E2533KCN.js} +3 -3
  19. package/Build/Workers/{chunk-RZJA77TX.js → chunk-ECGKCTPM.js} +6 -6
  20. package/Build/Workers/{chunk-PAH73ETP.js → chunk-HKHD5FDM.js} +5 -5
  21. package/Build/Workers/{chunk-6T2PQKYP.js → chunk-HSVZWLJD.js} +4 -4
  22. package/Build/Workers/{chunk-IE2BEHLE.js → chunk-HZ22ZI3Q.js} +12 -12
  23. package/Build/Workers/{chunk-SO2Z6H6F.js → chunk-IQKHPQNT.js} +2 -2
  24. package/Build/Workers/{chunk-SVGHDIZG.js → chunk-JHTZDMN6.js} +5 -5
  25. package/Build/Workers/{chunk-ETCPCGKC.js → chunk-JIXKGUWR.js} +2 -2
  26. package/Build/Workers/{chunk-DNCRKMCI.js → chunk-JVNWWKXF.js} +6 -6
  27. package/Build/Workers/{chunk-AABNX23Q.js → chunk-L7PWWHKM.js} +5 -5
  28. package/Build/Workers/{chunk-SXMHGVZ7.js → chunk-LF74EILW.js} +12 -12
  29. package/Build/Workers/{chunk-23FRF5ZP.js → chunk-LHZKPI55.js} +9 -9
  30. package/Build/Workers/{chunk-E6NMEKSS.js → chunk-LSYTMSIQ.js} +5 -4
  31. package/Build/Workers/{chunk-GO3IRH6U.js → chunk-LYKXQPGW.js} +6 -6
  32. package/Build/Workers/{chunk-MBDKO456.js → chunk-LZZA3PAR.js} +5 -5
  33. package/Build/Workers/{chunk-34DFERFC.js → chunk-M4FSVD3C.js} +12 -12
  34. package/Build/Workers/{chunk-NMAT4IJ6.js → chunk-O4DA3KRB.js} +7 -7
  35. package/Build/Workers/{chunk-HHHBRTSW.js → chunk-O7KDJVRH.js} +9 -9
  36. package/Build/Workers/{chunk-XUYCCEG6.js → chunk-OWV4L2GH.js} +5 -5
  37. package/Build/Workers/{chunk-ZNEIUXBK.js → chunk-OYFINQQA.js} +7 -7
  38. package/Build/Workers/{chunk-4QWLEG4L.js → chunk-PFUF2QIK.js} +14 -14
  39. package/Build/Workers/{chunk-37IYBZDZ.js → chunk-QFMJIXCL.js} +9 -9
  40. package/Build/Workers/{chunk-5VPO47LB.js → chunk-QWHUQ4B7.js} +8 -8
  41. package/Build/Workers/{chunk-KTDHOEXR.js → chunk-RB3XS7EZ.js} +1 -1
  42. package/Build/Workers/{chunk-HJ6KFRM7.js → chunk-RP4KKY2E.js} +16 -16
  43. package/Build/Workers/{chunk-Y6LLFNXN.js → chunk-SLPWFCXZ.js} +10 -10
  44. package/Build/Workers/{chunk-WUMTX3FI.js → chunk-UUXKGCBU.js} +8 -8
  45. package/Build/Workers/{chunk-EV4PBU7O.js → chunk-UXIZVXIR.js} +1 -1
  46. package/Build/Workers/{chunk-YPNIIVIF.js → chunk-V65LOTF3.js} +6 -6
  47. package/Build/Workers/{chunk-K5VGMGFM.js → chunk-VQLQAENU.js} +7 -7
  48. package/Build/Workers/{chunk-W32QSECR.js → chunk-WJ5THCIZ.js} +6 -6
  49. package/Build/Workers/{chunk-4NRFVAG2.js → chunk-WNEY4A5P.js} +5 -5
  50. package/Build/Workers/{chunk-UPU755HO.js → chunk-XMIVNU5H.js} +12 -12
  51. package/Build/Workers/{chunk-5YCDPN3O.js → chunk-YNRRVRHO.js} +1 -1
  52. package/Build/Workers/{chunk-NKM2EV46.js → chunk-YVAOKOKX.js} +1 -1
  53. package/Build/Workers/{chunk-FQNSMOZT.js → chunk-YW2UXIBU.js} +4 -4
  54. package/Build/Workers/{chunk-DAHXCIOX.js → chunk-ZBLPNAYB.js} +8 -8
  55. package/Build/Workers/{chunk-C36VNKTH.js → chunk-ZJGO7T2S.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/Source/Core/Ellipsoid.js +9 -0
  107. package/Source/Core/Ion.js +1 -1
  108. package/Source/Core/IonResource.js +14 -8
  109. package/Source/Scene/ArcGisMapService.js +1 -1
  110. package/Source/Scene/BingMapsImageryProvider.js +1 -1
  111. package/Source/Scene/Cesium3DTileContentFactory.js +7 -16
  112. package/Source/Scene/Cesium3DTileset.js +1 -1
  113. package/Source/Scene/GaussianSplat3DTileContent.js +253 -9
  114. package/Source/Scene/GaussianSplatPrimitive.js +167 -15
  115. package/Source/Scene/GltfLoader.js +20 -2
  116. package/Source/Scene/GltfVertexBufferLoader.js +56 -2
  117. package/Source/Scene/ITwinData.js +37 -76
  118. package/Source/Scene/Model/Model.js +3 -0
  119. package/Source/Scene/Model/ModelClippingPolygonsPipelineStage.js +8 -2
  120. package/Source/Scene/Model/ModelUtility.js +1 -0
  121. package/Source/Scene/Model/PntsLoader.js +7 -3
  122. package/Source/Scene/PntsParser.js +6 -3
  123. package/Source/Scene/PrimitiveLoadPlan.js +1 -1
  124. package/Source/Scene/VertexAttributeSemantic.js +4 -2
  125. package/Source/Scene/WebMapServiceImageryProvider.js +3 -2
  126. package/Source/Scene/WebMapTileServiceImageryProvider.js +0 -22
  127. package/Source/Scene/getMeshPrimitives.js +72 -0
  128. package/Source/Shaders/PrimitiveGaussianSplatFS.glsl +5 -5
  129. package/Source/Shaders/PrimitiveGaussianSplatFS.js +5 -5
  130. package/Source/Shaders/PrimitiveGaussianSplatVS.glsl +102 -5
  131. package/Source/Shaders/PrimitiveGaussianSplatVS.js +102 -5
  132. package/Source/ThirdParty/Workers/z-worker-pako.js +1 -1
  133. package/index.d.ts +109 -1
  134. package/index.js +245 -244
  135. package/package.json +3 -3
@@ -4,7 +4,7 @@ import Resource from "../Core/Resource.js";
4
4
 
5
5
  let defaultTokenCredit;
6
6
  const defaultAccessToken =
7
- "AAPTxy8BH1VEsoebNVZXo8HurEOF051kAEKlhkOhBEc9BmRpOZfBt2Ic5blmnx9xwwyG_Mt0EmBxpEa6xCqXn5V_qFEgJ0edE9ixiefKjMiv986NGSn2HB8y6x0GtSOCBkg19K6rBgZ7Upl7ABEnaFh4dD73GW0gUAJ9hHWhqd1qgHkBuctWiFEJUmQjs_52tdx6l5bDGoeXVvmelklmEJOshCRV_s3kLPC19ENRNLc18eA.AT1_EXUMUBsi";
7
+ "AAPTxy8BH1VEsoebNVZXo8HurEOF051kAEKlhkOhBEc9BmRXcPUeuOd6ZTh-Z86vRv6teqZdBYLUWIxB6HTYajPhFtAlXhMdqTg07UwlBQ59KbiReC5wCeOF4LzLTW4oaSPp-t4pEcJHnFePlnFcIPXM7R565gTy6f6fMuZAXPvUEuZSMf8dvTqHyV9-Zd9eZGWokDzKC4uEtHME7OeAk3oyZ7vzkjEo8fpuIfFw0sH8vQU.AT1_PLgWE6Lc";
8
8
  /**
9
9
  * Default options for accessing the ArcGIS image tile service.
10
10
  *
@@ -160,7 +160,7 @@ async function requestMetadata(
160
160
  const cacheKey = metadataResource.url;
161
161
  let promise = BingMapsImageryProvider._metadataCache[cacheKey];
162
162
  if (!defined(promise)) {
163
- promise = metadataResource.fetchJsonp("jsonp");
163
+ promise = metadataResource.fetchJson();
164
164
  BingMapsImageryProvider._metadataCache[cacheKey] = promise;
165
165
  }
166
166
 
@@ -93,28 +93,19 @@ const Cesium3DTileContentFactory = {
93
93
  const dataView = new DataView(arrayBuffer, byteOffset);
94
94
  const byteLength = dataView.getUint32(8, true);
95
95
  const glb = new Uint8Array(arrayBuffer, byteOffset, byteLength);
96
- let hasGaussianSplatExtension = false;
97
- if (tileset.isGltfExtensionRequired instanceof Function) {
98
- hasGaussianSplatExtension = tileset.isGltfExtensionRequired(
99
- "KHR_spz_gaussian_splats_compression",
100
- );
101
- }
102
- if (hasGaussianSplatExtension) {
96
+
97
+ if (
98
+ GaussianSplat3DTileContent.tilesetRequiresGaussianSplattingExt(tileset)
99
+ ) {
103
100
  return GaussianSplat3DTileContent.fromGltf(tileset, tile, resource, glb);
104
101
  }
105
102
 
106
103
  return Model3DTileContent.fromGltf(tileset, tile, resource, glb);
107
104
  },
108
105
  gltf: function (tileset, tile, resource, json) {
109
- const forceGaussianSplats =
110
- tileset.debugTreatTilesetAsGaussianSplats ?? false;
111
- let hasGaussianSplatExtension = false;
112
- if (tileset.isGltfExtensionRequired instanceof Function) {
113
- hasGaussianSplatExtension = tileset.isGltfExtensionRequired(
114
- "KHR_spz_gaussian_splats_compression",
115
- );
116
- }
117
- if (forceGaussianSplats || hasGaussianSplatExtension) {
106
+ if (
107
+ GaussianSplat3DTileContent.tilesetRequiresGaussianSplattingExt(tileset)
108
+ ) {
118
109
  return GaussianSplat3DTileContent.fromGltf(tileset, tile, resource, json);
119
110
  }
120
111
 
@@ -147,7 +147,7 @@ import ImageryLayerCollection from "./ImageryLayerCollection.js";
147
147
  *
148
148
  * @alias Cesium3DTileset
149
149
  * @constructor
150
- * @experimental Support for loading Gaussian splats content encoded with SPZ compression using the draft glTF extension {@link https://github.com/KhronosGroup/glTF/pull/2490 | KHR_spz_gaussian_splats_compression} is experimental and is subject change without Cesium's standard deprecation policy.
150
+ * @experimental Support for loading Gaussian splats content encoded with SPZ compression using the draft glTF extensions {@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} is experimental and is subject change without Cesium's standard deprecation policy.
151
151
  * @param {Cesium3DTileset.ConstructorOptions} options An object describing initialization options
152
152
  *
153
153
  * @exception {DeveloperError} The tileset must be 3D Tiles version 0.0 or 1.0.
@@ -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