@cesium/engine 18.0.0 → 18.2.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 (146) hide show
  1. package/Build/Workers/{chunk-QN7JEOQV.js → chunk-2QPO2E4E.js} +5 -5
  2. package/Build/Workers/{chunk-HS76VTVY.js → chunk-3JKMJ2DT.js} +2 -2
  3. package/Build/Workers/{chunk-3RKVDGRF.js → chunk-3RZFU3BO.js} +8 -8
  4. package/Build/Workers/{chunk-4MIY63FM.js → chunk-3X2BQHN6.js} +13 -13
  5. package/Build/Workers/{chunk-I3BAKR4S.js → chunk-4TGW7D6G.js} +16 -16
  6. package/Build/Workers/{chunk-LWJWWCZ4.js → chunk-5J3B5IYT.js} +6 -6
  7. package/Build/Workers/{chunk-WYCR5DWQ.js → chunk-5N52XJIS.js} +2 -2
  8. package/Build/Workers/{chunk-KGXTCGX3.js → chunk-5WXKC7TN.js} +12 -12
  9. package/Build/Workers/{chunk-5OL6XFNS.js → chunk-7252BLXK.js} +1 -1
  10. package/Build/Workers/{chunk-WGHUCZMX.js → chunk-7DRP5IKA.js} +7 -7
  11. package/Build/Workers/{chunk-AEGAQ6FD.js → chunk-AGEQBE2G.js} +12 -12
  12. package/Build/Workers/{chunk-EXEZHW3P.js → chunk-AJWIQQTX.js} +4 -4
  13. package/Build/Workers/{chunk-4DSTDGY3.js → chunk-DBPLDHPT.js} +2 -2
  14. package/Build/Workers/{chunk-J4MAVE6J.js → chunk-EG3P66JO.js} +6 -6
  15. package/Build/Workers/{chunk-OATG6PKE.js → chunk-EJGJUZST.js} +12 -12
  16. package/Build/Workers/{chunk-ZIP27IX6.js → chunk-ER7SSBHR.js} +6 -6
  17. package/Build/Workers/{chunk-5WVF4BK7.js → chunk-F3ZH4MQG.js} +5 -5
  18. package/Build/Workers/{chunk-RWFYLWSF.js → chunk-FC2YDGY6.js} +9 -9
  19. package/Build/Workers/{chunk-NR7KSD56.js → chunk-FPJWHB5J.js} +3 -3
  20. package/Build/Workers/{chunk-YV37YFUM.js → chunk-HMYDBCCY.js} +9 -9
  21. package/Build/Workers/{chunk-EHB2OCQX.js → chunk-JVHONLHD.js} +4 -4
  22. package/Build/Workers/{chunk-ZADJ6FRX.js → chunk-K65RSNI5.js} +4 -4
  23. package/Build/Workers/{chunk-MFGVMUN3.js → chunk-KZ752MAA.js} +5 -5
  24. package/Build/Workers/{chunk-CES6DHHV.js → chunk-LMDJ23I7.js} +1 -1
  25. package/Build/Workers/{chunk-KNA65INJ.js → chunk-LQQDQHA5.js} +4 -4
  26. package/Build/Workers/{chunk-LZFUG3GO.js → chunk-MATVBVGM.js} +10 -10
  27. package/Build/Workers/chunk-MIMOEYBO.js +280 -0
  28. package/Build/Workers/{chunk-NWSAYFZG.js → chunk-MPNN7PNO.js} +6 -6
  29. package/Build/Workers/{chunk-2AXPWBJG.js → chunk-MV5UVSOZ.js} +1 -1
  30. package/Build/Workers/{chunk-NVJ5JRIM.js → chunk-NCW6XN5X.js} +2 -2
  31. package/Build/Workers/{chunk-T6B6H3GR.js → chunk-PFZ45265.js} +7 -7
  32. package/Build/Workers/{chunk-F4ZAKN4V.js → chunk-PHIB2ITA.js} +2 -2
  33. package/Build/Workers/{chunk-UK33ZN4K.js → chunk-PLM7GGHT.js} +4 -4
  34. package/Build/Workers/{chunk-GS55WTRX.js → chunk-PMNYUVMK.js} +6 -6
  35. package/Build/Workers/{chunk-SIOVJ4L5.js → chunk-R3VU4BBN.js} +4 -4
  36. package/Build/Workers/{chunk-JF4IYQYC.js → chunk-R7LO2ZW7.js} +7 -7
  37. package/Build/Workers/{chunk-LIPZUYNR.js → chunk-R7VDSCQM.js} +11 -11
  38. package/Build/Workers/{chunk-2CAYUY2B.js → chunk-RRSRPDQN.js} +8 -8
  39. package/Build/Workers/{chunk-IWGMVQGG.js → chunk-SOLM3ZIV.js} +9 -9
  40. package/Build/Workers/{chunk-W6CPO62M.js → chunk-UGKOGDMZ.js} +6 -6
  41. package/Build/Workers/{chunk-2QNKQVUT.js → chunk-UGWI4JAZ.js} +5 -5
  42. package/Build/Workers/{chunk-FPYBD2P5.js → chunk-UOU6BW5C.js} +1 -1
  43. package/Build/Workers/{chunk-DINSLSJD.js → chunk-USCHXXVF.js} +6 -6
  44. package/Build/Workers/{chunk-GM55YFOB.js → chunk-VB7MVZDU.js} +14 -14
  45. package/Build/Workers/{chunk-OIHAAHBK.js → chunk-VC5NTCLG.js} +10 -10
  46. package/Build/Workers/{chunk-2NKHPWDY.js → chunk-VGOLRLK7.js} +12 -12
  47. package/Build/Workers/{chunk-QUSP3NWA.js → chunk-VKMJSSOD.js} +5 -5
  48. package/Build/Workers/{chunk-WTFZHPUW.js → chunk-XAP7YXEJ.js} +5 -5
  49. package/Build/Workers/{chunk-IWZK2AIH.js → chunk-XH4DQCNS.js} +5 -5
  50. package/Build/Workers/{chunk-GAUF4F5A.js → chunk-YTIUL27M.js} +16 -16
  51. package/Build/Workers/{chunk-VGJSKEIB.js → chunk-Z43MDFLH.js} +4 -4
  52. package/Build/Workers/{chunk-HQE7KSR4.js → chunk-ZT5GZ75Z.js} +2 -2
  53. package/Build/Workers/combineGeometry.js +21 -21
  54. package/Build/Workers/createBoxGeometry.js +15 -15
  55. package/Build/Workers/createBoxOutlineGeometry.js +13 -13
  56. package/Build/Workers/createCircleGeometry.js +23 -23
  57. package/Build/Workers/createCircleOutlineGeometry.js +16 -16
  58. package/Build/Workers/createCoplanarPolygonGeometry.js +30 -30
  59. package/Build/Workers/createCoplanarPolygonOutlineGeometry.js +28 -28
  60. package/Build/Workers/createCorridorGeometry.js +26 -26
  61. package/Build/Workers/createCorridorOutlineGeometry.js +25 -25
  62. package/Build/Workers/createCylinderGeometry.js +17 -17
  63. package/Build/Workers/createCylinderOutlineGeometry.js +15 -15
  64. package/Build/Workers/createEllipseGeometry.js +23 -23
  65. package/Build/Workers/createEllipseOutlineGeometry.js +16 -16
  66. package/Build/Workers/createEllipsoidGeometry.js +16 -16
  67. package/Build/Workers/createEllipsoidOutlineGeometry.js +15 -15
  68. package/Build/Workers/createFrustumGeometry.js +15 -15
  69. package/Build/Workers/createFrustumOutlineGeometry.js +15 -15
  70. package/Build/Workers/createGeometry.js +23 -21
  71. package/Build/Workers/createGroundPolylineGeometry.js +19 -19
  72. package/Build/Workers/createPlaneGeometry.js +13 -13
  73. package/Build/Workers/createPlaneOutlineGeometry.js +12 -12
  74. package/Build/Workers/createPolygonGeometry.js +29 -29
  75. package/Build/Workers/createPolygonOutlineGeometry.js +27 -27
  76. package/Build/Workers/createPolylineGeometry.js +22 -22
  77. package/Build/Workers/createPolylineVolumeGeometry.js +28 -28
  78. package/Build/Workers/createPolylineVolumeOutlineGeometry.js +24 -24
  79. package/Build/Workers/createRectangleGeometry.js +24 -24
  80. package/Build/Workers/createRectangleOutlineGeometry.js +17 -17
  81. package/Build/Workers/createSimplePolylineGeometry.js +20 -20
  82. package/Build/Workers/createSphereGeometry.js +16 -16
  83. package/Build/Workers/createSphereOutlineGeometry.js +15 -15
  84. package/Build/Workers/createTaskProcessorWorker.js +3 -3
  85. package/Build/Workers/createVectorTileClampedPolylines.js +12 -12
  86. package/Build/Workers/createVectorTileGeometries.js +21 -21
  87. package/Build/Workers/createVectorTilePoints.js +11 -11
  88. package/Build/Workers/createVectorTilePolygons.js +19 -19
  89. package/Build/Workers/createVectorTilePolylines.js +12 -12
  90. package/Build/Workers/createVerticesFromGoogleEarthEnterpriseBuffer.js +19 -19
  91. package/Build/Workers/createVerticesFromHeightmap.js +19 -19
  92. package/Build/Workers/createVerticesFromQuantizedTerrainMesh.js +16 -16
  93. package/Build/Workers/createWallGeometry.js +21 -21
  94. package/Build/Workers/createWallOutlineGeometry.js +20 -20
  95. package/Build/Workers/decodeDraco.js +10 -10
  96. package/Build/Workers/decodeGoogleEarthEnterprisePacket.js +5 -5
  97. package/Build/Workers/decodeI3S.js +9 -9
  98. package/Build/Workers/gaussianSplatSorter.js +62 -0
  99. package/Build/Workers/gaussianSplatTextureGenerator.js +68 -0
  100. package/Build/Workers/transcodeKTX2.js +59 -7
  101. package/Build/Workers/transferTypedArrayTest.js +1 -1
  102. package/Build/Workers/upsampleQuantizedTerrainMesh.js +19 -19
  103. package/Source/Core/PixelFormat.js +62 -0
  104. package/Source/Renderer/Context.js +2 -0
  105. package/Source/Renderer/Pass.js +3 -2
  106. package/Source/Renderer/Texture.js +1 -0
  107. package/Source/Renderer/VertexArray.js +33 -8
  108. package/Source/Renderer/createUniform.js +2 -0
  109. package/Source/Scene/Cesium3DTileContentFactory.js +23 -0
  110. package/Source/Scene/Cesium3DTileset.js +59 -2
  111. package/Source/Scene/GaussianSplat3DTileContent.js +504 -0
  112. package/Source/Scene/GaussianSplatPrimitive.js +932 -0
  113. package/Source/Scene/GaussianSplatRenderResources.js +81 -0
  114. package/Source/Scene/GaussianSplatSorter.js +73 -0
  115. package/Source/Scene/GaussianSplatTextureGenerator.js +64 -0
  116. package/Source/Scene/GltfLoader.js +82 -4
  117. package/Source/Scene/GltfSpzLoader.js +222 -0
  118. package/Source/Scene/GltfVertexBufferLoader.js +98 -3
  119. package/Source/Scene/Model/ModelRuntimePrimitive.js +1 -0
  120. package/Source/Scene/Model/ModelUtility.js +2 -0
  121. package/Source/Scene/PrimitiveLoadPlan.js +59 -0
  122. package/Source/Scene/ResourceCache.js +60 -3
  123. package/Source/Scene/ResourceCacheKey.js +39 -1
  124. package/Source/Scene/Scene.js +32 -1
  125. package/Source/Scene/VertexAttributeSemantic.js +30 -0
  126. package/Source/Shaders/Builtin/Constants/passGaussianSplats.glsl +9 -0
  127. package/Source/Shaders/Builtin/Constants/passGaussianSplats.js +11 -0
  128. package/Source/Shaders/Builtin/Constants/passOverlay.glsl +1 -1
  129. package/Source/Shaders/Builtin/Constants/passOverlay.js +1 -1
  130. package/Source/Shaders/Builtin/CzmBuiltins.js +2 -0
  131. package/Source/Shaders/Model/ModelFS.glsl +3 -1
  132. package/Source/Shaders/Model/ModelFS.js +3 -1
  133. package/Source/Shaders/Model/ModelVS.glsl +1 -1
  134. package/Source/Shaders/Model/ModelVS.js +1 -1
  135. package/Source/Shaders/Model/PointCloudStylingStageVS.glsl +1 -1
  136. package/Source/Shaders/Model/PointCloudStylingStageVS.js +2 -1
  137. package/Source/Shaders/PrimitiveGaussianSplatFS.glsl +18 -0
  138. package/Source/Shaders/PrimitiveGaussianSplatFS.js +20 -0
  139. package/Source/Shaders/PrimitiveGaussianSplatVS.glsl +108 -0
  140. package/Source/Shaders/PrimitiveGaussianSplatVS.js +109 -0
  141. package/Source/ThirdParty/wasm_splats_bg.wasm +0 -0
  142. package/Source/Workers/gaussianSplatSorter.js +34 -0
  143. package/Source/Workers/gaussianSplatTextureGenerator.js +39 -0
  144. package/index.d.ts +16 -0
  145. package/index.js +71 -62
  146. package/package.json +4 -2
@@ -9,6 +9,7 @@ import JobType from "./JobType.js";
9
9
  import ModelComponents from "./ModelComponents.js";
10
10
  import ResourceLoader from "./ResourceLoader.js";
11
11
  import ResourceLoaderState from "./ResourceLoaderState.js";
12
+ import CesiumMath from "../Core/Math.js";
12
13
 
13
14
  /**
14
15
  * Loads a vertex buffer from a glTF buffer view.
@@ -53,6 +54,7 @@ function GltfVertexBufferLoader(options) {
53
54
  const attributeSemantic = options.attributeSemantic;
54
55
  const accessorId = options.accessorId;
55
56
  const cacheKey = options.cacheKey;
57
+ const spz = options.spz;
56
58
  const asynchronous = options.asynchronous ?? true;
57
59
  const loadBuffer = options.loadBuffer ?? false;
58
60
  const loadTypedArray = options.loadTypedArray ?? false;
@@ -73,10 +75,10 @@ function GltfVertexBufferLoader(options) {
73
75
  const hasDraco = hasDracoCompression(draco, attributeSemantic);
74
76
  const hasAttributeSemantic = defined(attributeSemantic);
75
77
  const hasAccessorId = defined(accessorId);
76
-
77
- if (hasBufferViewId === hasDraco) {
78
+ const hasSpz = defined(spz);
79
+ if (hasBufferViewId === (hasDraco !== hasSpz)) {
78
80
  throw new DeveloperError(
79
- "One of options.bufferViewId and options.draco must be defined.",
81
+ "One of options.bufferViewId, options.draco, or options.spz must be defined.",
80
82
  );
81
83
  }
82
84
 
@@ -104,6 +106,7 @@ function GltfVertexBufferLoader(options) {
104
106
  Check.typeOf.string("options.attributeSemantic", attributeSemantic);
105
107
  Check.typeOf.number("options.accessorId", accessorId);
106
108
  }
109
+
107
110
  //>>includeEnd('debug');
108
111
 
109
112
  this._resourceCache = resourceCache;
@@ -113,6 +116,7 @@ function GltfVertexBufferLoader(options) {
113
116
  this._bufferViewId = bufferViewId;
114
117
  this._primitive = primitive;
115
118
  this._draco = draco;
119
+ this._spz = spz;
116
120
  this._attributeSemantic = attributeSemantic;
117
121
  this._accessorId = accessorId;
118
122
  this._cacheKey = cacheKey;
@@ -210,6 +214,11 @@ GltfVertexBufferLoader.prototype.load = async function () {
210
214
  return this._promise;
211
215
  }
212
216
 
217
+ if (defined(this._spz)) {
218
+ this._promise = loadFromSpz(this);
219
+ return this._promise;
220
+ }
221
+
213
222
  if (hasDracoCompression(this._draco, this._attributeSemantic)) {
214
223
  this._promise = loadFromDraco(this);
215
224
  return this._promise;
@@ -270,6 +279,74 @@ function getQuantizationInformation(
270
279
  return quantization;
271
280
  }
272
281
 
282
+ async function loadFromSpz(vertexBufferLoader) {
283
+ vertexBufferLoader._state = ResourceLoaderState.LOADING;
284
+ const resourceCache = vertexBufferLoader._resourceCache;
285
+ try {
286
+ const spzLoader = resourceCache.getSpzLoader({
287
+ gltf: vertexBufferLoader._gltf,
288
+ primitive: vertexBufferLoader._primitive,
289
+ spz: vertexBufferLoader._spz,
290
+ gltfResource: vertexBufferLoader._gltfResource,
291
+ baseResource: vertexBufferLoader._baseResource,
292
+ });
293
+ vertexBufferLoader._spzLoader = spzLoader;
294
+ await spzLoader.load();
295
+
296
+ if (vertexBufferLoader.isDestroyed()) {
297
+ return;
298
+ }
299
+
300
+ vertexBufferLoader._state = ResourceLoaderState.LOADED;
301
+ return vertexBufferLoader;
302
+ } catch {
303
+ if (vertexBufferLoader.isDestroyed()) {
304
+ return;
305
+ }
306
+ }
307
+ }
308
+
309
+ function processSpz(vertexBufferLoader) {
310
+ vertexBufferLoader._state = ResourceLoaderState.PROCESSING;
311
+ const spzLoader = vertexBufferLoader._spzLoader;
312
+
313
+ const gcloudData = spzLoader.decodedData.gcloud;
314
+
315
+ if (vertexBufferLoader._attributeSemantic === "POSITION") {
316
+ vertexBufferLoader._typedArray = gcloudData.positions;
317
+ } else if (vertexBufferLoader._attributeSemantic === "_SCALE") {
318
+ vertexBufferLoader._typedArray = gcloudData.scales;
319
+ } else if (vertexBufferLoader._attributeSemantic === "_ROTATION") {
320
+ vertexBufferLoader._typedArray = gcloudData.rotations;
321
+ } else if (vertexBufferLoader._attributeSemantic === "COLOR_0") {
322
+ const colors = gcloudData.colors;
323
+ const alphas = gcloudData.alphas;
324
+ vertexBufferLoader._typedArray = new Uint8Array((colors.length / 3) * 4);
325
+ for (let i = 0; i < colors.length / 3; i++) {
326
+ vertexBufferLoader._typedArray[i * 4] = CesiumMath.clamp(
327
+ colors[i * 3] * 255.0,
328
+ 0.0,
329
+ 255.0,
330
+ );
331
+ vertexBufferLoader._typedArray[i * 4 + 1] = CesiumMath.clamp(
332
+ colors[i * 3 + 1] * 255.0,
333
+ 0.0,
334
+ 255.0,
335
+ );
336
+ vertexBufferLoader._typedArray[i * 4 + 2] = CesiumMath.clamp(
337
+ colors[i * 3 + 2] * 255.0,
338
+ 0.0,
339
+ 255.0,
340
+ );
341
+ vertexBufferLoader._typedArray[i * 4 + 3] = CesiumMath.clamp(
342
+ alphas[i] * 255.0,
343
+ 0.0,
344
+ 255.0,
345
+ );
346
+ }
347
+ }
348
+ }
349
+
273
350
  async function loadFromDraco(vertexBufferLoader) {
274
351
  vertexBufferLoader._state = ResourceLoaderState.LOADING;
275
352
  const resourceCache = vertexBufferLoader._resourceCache;
@@ -427,6 +504,19 @@ GltfVertexBufferLoader.prototype.process = function (frameState) {
427
504
  processDraco(this);
428
505
  }
429
506
 
507
+ if (defined(this._spzLoader)) {
508
+ try {
509
+ const ready = this._spzLoader.process(frameState);
510
+ if (!ready) {
511
+ return false;
512
+ }
513
+ } catch (error) {
514
+ handleError(this, error);
515
+ }
516
+
517
+ processSpz(this);
518
+ }
519
+
430
520
  let buffer;
431
521
  const typedArray = this._typedArray;
432
522
  if (this._loadBuffer && this._asynchronous) {
@@ -474,8 +564,13 @@ GltfVertexBufferLoader.prototype.unload = function () {
474
564
  resourceCache.unload(this._dracoLoader);
475
565
  }
476
566
 
567
+ if (defined(this._spzLoader)) {
568
+ resourceCache.unload(this._spzLoader);
569
+ }
570
+
477
571
  this._bufferViewLoader = undefined;
478
572
  this._dracoLoader = undefined;
573
+ this._spzLoader = undefined;
479
574
  this._typedArray = undefined;
480
575
  this._buffer = undefined;
481
576
  this._gltf = undefined;
@@ -223,6 +223,7 @@ ModelRuntimePrimitive.prototype.configurePipeline = function (frameState) {
223
223
  const hasQuantization = ModelUtility.hasQuantizedAttributes(
224
224
  primitive.attributes,
225
225
  );
226
+
226
227
  const generateWireframeIndices =
227
228
  model.debugWireframe &&
228
229
  PrimitiveType.isTriangles(primitive.primitiveType) &&
@@ -368,6 +368,8 @@ ModelUtility.supportedExtensions = {
368
368
  KHR_techniques_webgl: true,
369
369
  KHR_texture_basisu: true,
370
370
  KHR_texture_transform: true,
371
+ KHR_gaussian_splatting: true,
372
+ KHR_spz_gaussian_splats_compression: true,
371
373
  WEB3D_quantized_attributes: true,
372
374
  };
373
375
 
@@ -7,6 +7,8 @@ import BufferUsage from "../Renderer/BufferUsage.js";
7
7
  import AttributeType from "./AttributeType.js";
8
8
  import ModelComponents from "./ModelComponents.js";
9
9
  import PrimitiveOutlineGenerator from "./Model/PrimitiveOutlineGenerator.js";
10
+ import VertexAttributeSemantic from "./VertexAttributeSemantic.js";
11
+ import ModelUtility from "./Model/ModelUtility.js";
10
12
 
11
13
  /**
12
14
  * Simple struct for tracking whether an attribute will be loaded as a buffer
@@ -157,6 +159,15 @@ function PrimitiveLoadPlan(primitive) {
157
159
  * @private
158
160
  */
159
161
  this.outlineIndices = undefined;
162
+
163
+ /**
164
+ * Set this true to indicate that the primitive has the
165
+ * KHR_gaussian_splatting extension and needs to be post-processed
166
+ *
167
+ * @type {boolean}
168
+ * @private
169
+ */
170
+ this.needsGaussianSplats = false;
160
171
  }
161
172
 
162
173
  /**
@@ -174,6 +185,11 @@ PrimitiveLoadPlan.prototype.postProcess = function (context) {
174
185
  generateOutlines(this);
175
186
  generateBuffers(this, context);
176
187
  }
188
+
189
+ if (this.needsGaussianSplats) {
190
+ prepareSpzData(this, context);
191
+ setupGaussianSplatBuffers(this, context);
192
+ }
177
193
  };
178
194
 
179
195
  function generateOutlines(loadPlan) {
@@ -226,6 +242,49 @@ function makeOutlineCoordinatesAttribute(outlineCoordinatesTypedArray) {
226
242
  return attribute;
227
243
  }
228
244
 
245
+ function prepareSpzData(loadPlan, context) {
246
+ const position = ModelUtility.getAttributeBySemantic(
247
+ loadPlan.primitive,
248
+ VertexAttributeSemantic.POSITION,
249
+ );
250
+
251
+ for (let i = 0; i < position.typedArray.length; i += 3) {
252
+ position.typedArray[i + 1] = -position.typedArray[i + 1];
253
+ position.typedArray[i + 2] = -position.typedArray[i + 2];
254
+ }
255
+
256
+ const rotations = ModelUtility.getAttributeBySemantic(
257
+ loadPlan.primitive,
258
+ VertexAttributeSemantic.ROTATION,
259
+ );
260
+
261
+ //180* rotation around X.
262
+ //Temporary until we can get SPZ supporting Z-up assets natively
263
+ const rots = rotations.typedArray;
264
+ for (let q = 0; q < rots.length; q += 4) {
265
+ const w = rots[q];
266
+ const x = -rots[q + 3];
267
+ const y = rots[q + 2];
268
+ const z = -rots[q + 1];
269
+
270
+ rots[q] = y;
271
+ rots[q + 1] = -x;
272
+ rots[q + 2] = w;
273
+ rots[q + 3] = -z;
274
+ }
275
+ rotations.typedArray = rots;
276
+ }
277
+
278
+ function setupGaussianSplatBuffers(loadPlan, context) {
279
+ const attributePlans = loadPlan.attributePlans;
280
+ const attrLen = attributePlans.length;
281
+ for (let i = 0; i < attrLen; i++) {
282
+ const attributePlan = attributePlans[i];
283
+ attributePlan.loadBuffer = false;
284
+ attributePlan.loadTypedArray = true;
285
+ }
286
+ }
287
+
229
288
  function generateBuffers(loadPlan, context) {
230
289
  generateAttributeBuffers(loadPlan.attributePlans, context);
231
290
 
@@ -10,6 +10,7 @@ import GltfIndexBufferLoader from "./GltfIndexBufferLoader.js";
10
10
  import GltfJsonLoader from "./GltfJsonLoader.js";
11
11
  import GltfTextureLoader from "./GltfTextureLoader.js";
12
12
  import GltfVertexBufferLoader from "./GltfVertexBufferLoader.js";
13
+ import GltfSpzLoader from "./GltfSpzLoader.js";
13
14
  import MetadataSchemaLoader from "./MetadataSchemaLoader.js";
14
15
  import ResourceCacheKey from "./ResourceCacheKey.js";
15
16
  import ResourceCacheStatistics from "./ResourceCacheStatistics.js";
@@ -390,6 +391,57 @@ ResourceCache.getDracoLoader = function (options) {
390
391
  return ResourceCache.add(dracoLoader);
391
392
  };
392
393
 
394
+ /**
395
+ * Gets an existing SPZ loader from the cache, or creates a new loader if one does not already exist.
396
+ * This loader is used to decode SPZ (Splat Point Cloud) data in glTF.
397
+ *
398
+ * @param {object} options Object with the following properties:
399
+ * @param {object} options.gltf The glTF JSON.
400
+ * @param {object} options.primitive The primitive containing the SPZ extension.
401
+ * @param {object} options.spz The SPZ extension object.
402
+ * @param {Resource} options.gltfResource The {@link Resource} containing the glTF.
403
+ * @param {Resource} options.baseResource The {@link Resource} that paths in the glTF JSON are relative to.
404
+ *
405
+ * @return {GltfSpzLoader} The cached SPZ loader.
406
+ @private
407
+ * */
408
+ ResourceCache.getSpzLoader = function (options) {
409
+ options = options ?? Frozen.EMPTY_OBJECT;
410
+ const { gltf, primitive, spz, gltfResource, baseResource } = options;
411
+
412
+ //>>includeStart('debug', pragmas.debug);
413
+ Check.typeOf.object("options.gltf", gltf);
414
+ Check.typeOf.object("options.primitive", primitive);
415
+ Check.typeOf.object("options.spz", spz);
416
+ Check.typeOf.object("options.gltfResource", gltfResource);
417
+ Check.typeOf.object("options.baseResource", baseResource);
418
+ //>>includeEnd('debug');
419
+
420
+ const cacheKey = ResourceCacheKey.getSpzCacheKey({
421
+ gltf: gltf,
422
+ primitive: primitive,
423
+ gltfResource: gltfResource,
424
+ baseResource: baseResource,
425
+ });
426
+
427
+ let spzLoader = ResourceCache.get(cacheKey);
428
+ if (defined(spzLoader)) {
429
+ return spzLoader;
430
+ }
431
+
432
+ spzLoader = new GltfSpzLoader({
433
+ resourceCache: ResourceCache,
434
+ gltf: gltf,
435
+ primitive: primitive,
436
+ spz: spz,
437
+ gltfResource: gltfResource,
438
+ baseResource: baseResource,
439
+ cacheKey: cacheKey,
440
+ });
441
+
442
+ return ResourceCache.add(spzLoader);
443
+ };
444
+
393
445
  /**
394
446
  * Gets an existing glTF vertex buffer from the cache, or creates a new loader if one does not already exist.
395
447
  *
@@ -424,6 +476,7 @@ ResourceCache.getVertexBufferLoader = function (options) {
424
476
  bufferViewId,
425
477
  primitive,
426
478
  draco,
479
+ spz,
427
480
  attributeSemantic,
428
481
  accessorId,
429
482
  asynchronous = true,
@@ -448,10 +501,11 @@ ResourceCache.getVertexBufferLoader = function (options) {
448
501
  const hasDraco = hasDracoCompression(draco, attributeSemantic);
449
502
  const hasAttributeSemantic = defined(attributeSemantic);
450
503
  const hasAccessorId = defined(accessorId);
504
+ const hasSpz = defined(spz);
451
505
 
452
- if (hasBufferViewId === hasDraco) {
506
+ if (hasBufferViewId === (hasDraco !== hasSpz)) {
453
507
  throw new DeveloperError(
454
- "One of options.bufferViewId and options.draco must be defined.",
508
+ "One of options.bufferViewId, options.draco, or options.spz must be defined.",
455
509
  );
456
510
  }
457
511
 
@@ -463,7 +517,7 @@ ResourceCache.getVertexBufferLoader = function (options) {
463
517
 
464
518
  if (hasDraco && !hasAccessorId) {
465
519
  throw new DeveloperError(
466
- "When options.draco is defined options.haAccessorId must also be defined.",
520
+ "When options.draco is defined options.hasAccessorId must also be defined.",
467
521
  );
468
522
  }
469
523
 
@@ -478,6 +532,7 @@ ResourceCache.getVertexBufferLoader = function (options) {
478
532
  Check.typeOf.string("options.attributeSemantic", attributeSemantic);
479
533
  Check.typeOf.number("options.accessorId", accessorId);
480
534
  }
535
+
481
536
  //>>includeEnd('debug');
482
537
 
483
538
  const cacheKey = ResourceCacheKey.getVertexBufferCacheKey({
@@ -487,6 +542,7 @@ ResourceCache.getVertexBufferLoader = function (options) {
487
542
  frameState: frameState,
488
543
  bufferViewId: bufferViewId,
489
544
  draco: draco,
545
+ spz: spz,
490
546
  attributeSemantic: attributeSemantic,
491
547
  dequantize: dequantize,
492
548
  loadBuffer: loadBuffer,
@@ -506,6 +562,7 @@ ResourceCache.getVertexBufferLoader = function (options) {
506
562
  bufferViewId: bufferViewId,
507
563
  primitive: primitive,
508
564
  draco: draco,
565
+ spz: spz,
509
566
  attributeSemantic: attributeSemantic,
510
567
  accessorId: accessorId,
511
568
  cacheKey: cacheKey,
@@ -71,6 +71,24 @@ function getDracoCacheKey(gltf, draco, gltfResource, baseResource) {
71
71
  return `${bufferCacheKey}-range-${bufferViewCacheKey}`;
72
72
  }
73
73
 
74
+ function getSpzCacheKey(gltf, primitive, gltfResource, baseResource) {
75
+ const bufferViewId = 0;
76
+ const bufferView = gltf.bufferViews[bufferViewId];
77
+ const bufferId = bufferView.buffer;
78
+ const buffer = gltf.buffers[bufferId];
79
+
80
+ const bufferCacheKey = getBufferCacheKey(
81
+ buffer,
82
+ bufferId,
83
+ gltfResource,
84
+ baseResource,
85
+ );
86
+
87
+ const bufferViewCacheKey = getBufferViewCacheKey(bufferView);
88
+
89
+ return `${bufferCacheKey}-range-${bufferViewCacheKey}`;
90
+ }
91
+
74
92
  function getImageCacheKey(gltf, imageId, gltfResource, baseResource) {
75
93
  const image = gltf.images[imageId];
76
94
  const bufferViewId = image.bufferView;
@@ -272,6 +290,19 @@ ResourceCacheKey.getDracoCacheKey = function (options) {
272
290
  return `draco:${getDracoCacheKey(gltf, draco, gltfResource, baseResource)}`;
273
291
  };
274
292
 
293
+ ResourceCacheKey.getSpzCacheKey = function (options) {
294
+ options = options ?? Frozen.EMPTY_OBJECT;
295
+ const { gltf, primitive, gltfResource, baseResource } = options;
296
+
297
+ //>>includeStart('debug', pragmas.debug);
298
+ Check.typeOf.object("options.gltf", gltf);
299
+ Check.typeOf.object("options.primitive", primitive);
300
+ Check.typeOf.object("options.gltfResource", gltfResource);
301
+ Check.typeOf.object("options.baseResource", baseResource);
302
+ //>>includeEnd('debug');
303
+
304
+ return `spz:${getSpzCacheKey(gltf, primitive, gltfResource, baseResource)}`;
305
+ };
275
306
  /**
276
307
  * Gets the vertex buffer cache key.
277
308
  *
@@ -301,6 +332,7 @@ ResourceCacheKey.getVertexBufferCacheKey = function (options) {
301
332
  frameState,
302
333
  bufferViewId,
303
334
  draco,
335
+ spz,
304
336
  attributeSemantic,
305
337
  dequantize = false,
306
338
  loadBuffer = false,
@@ -316,8 +348,9 @@ ResourceCacheKey.getVertexBufferCacheKey = function (options) {
316
348
  const hasBufferViewId = defined(bufferViewId);
317
349
  const hasDraco = hasDracoCompression(draco, attributeSemantic);
318
350
  const hasAttributeSemantic = defined(attributeSemantic);
351
+ const hasSpz = defined(spz);
319
352
 
320
- if (hasBufferViewId === hasDraco) {
353
+ if (hasBufferViewId === (hasDraco !== hasSpz)) {
321
354
  throw new DeveloperError(
322
355
  "One of options.bufferViewId and options.draco must be defined.",
323
356
  );
@@ -365,6 +398,11 @@ ResourceCacheKey.getVertexBufferCacheKey = function (options) {
365
398
  return `vertex-buffer:${dracoCacheKey}-draco-${attributeSemantic}${cacheKeySuffix}`;
366
399
  }
367
400
 
401
+ if (spz) {
402
+ const spzCacheKey = getSpzCacheKey(gltf, spz, gltfResource, baseResource);
403
+ return `vertex-buffer:${spzCacheKey}-spz-${attributeSemantic}${cacheKeySuffix}`;
404
+ }
405
+
368
406
  const bufferView = gltf.bufferViews[bufferViewId];
369
407
  const bufferId = bufferView.buffer;
370
408
  const buffer = gltf.buffers[bufferId];
@@ -2318,6 +2318,23 @@ function backToFront(a, b, position) {
2318
2318
  );
2319
2319
  }
2320
2320
 
2321
+ const scratchCart3 = new Cartesian3();
2322
+ function distanceSquaredToCenter(center, position) {
2323
+ const diff = Cartesian3.subtract(center, position, scratchCart3);
2324
+ const distance = Math.max(0.0, Cartesian3.magnitude(diff));
2325
+ return distance * distance;
2326
+ }
2327
+
2328
+ function backToFrontSplats(a, b, position) {
2329
+ const boxA = a.boundingVolume;
2330
+ const boxB = b.boundingVolume;
2331
+
2332
+ return (
2333
+ distanceSquaredToCenter(boxB.center, position) -
2334
+ distanceSquaredToCenter(boxA.center, position)
2335
+ );
2336
+ }
2337
+
2321
2338
  function frontToBack(a, b, position) {
2322
2339
  // When distances are equal equal favor sorting b before a. This gives render priority to commands later in the list.
2323
2340
  return (
@@ -2362,7 +2379,6 @@ function executeTranslucentCommandsFrontToBack(
2362
2379
  executeFunction(commands[i], scene, passState);
2363
2380
  }
2364
2381
  }
2365
-
2366
2382
  /**
2367
2383
  * Execute commands to render voxels in the scene.
2368
2384
  *
@@ -2385,6 +2401,19 @@ function performVoxelsPass(scene, passState, frustumCommands) {
2385
2401
  }
2386
2402
  }
2387
2403
 
2404
+ function performGaussianSplatPass(scene, passState, frustumCommands) {
2405
+ scene.context.uniformState.updatePass(Pass.GAUSSIAN_SPLATS);
2406
+
2407
+ const commands = frustumCommands.commands[Pass.GAUSSIAN_SPLATS];
2408
+ commands.length = frustumCommands.indices[Pass.GAUSSIAN_SPLATS];
2409
+
2410
+ mergeSort(commands, backToFrontSplats, scene.camera.positionWC);
2411
+
2412
+ for (let i = 0; i < commands.length; ++i) {
2413
+ executeCommand(commands[i], scene, passState);
2414
+ }
2415
+ }
2416
+
2388
2417
  const scratchPerspectiveFrustum = new PerspectiveFrustum();
2389
2418
  const scratchPerspectiveOffCenterFrustum = new PerspectiveOffCenterFrustum();
2390
2419
  const scratchOrthographicFrustum = new OrthographicFrustum();
@@ -2782,6 +2811,8 @@ function executeCommands(scene, passState) {
2782
2811
 
2783
2812
  performPass(frustumCommands, Pass.OPAQUE);
2784
2813
 
2814
+ performGaussianSplatPass(scene, passState, frustumCommands);
2815
+
2785
2816
  if (index !== 0 && scene.mode !== SceneMode.SCENE2D) {
2786
2817
  // Do not overlap frustums in the translucent pass to avoid blending artifacts
2787
2818
  frustum.near = frustumCommands.near;
@@ -73,6 +73,20 @@ const VertexAttributeSemantic = {
73
73
  * @constant
74
74
  */
75
75
  FEATURE_ID: "_FEATURE_ID",
76
+ /**
77
+ * Gaussian Splat Scale
78
+ *
79
+ * @type {string}
80
+ * @constant
81
+ */
82
+ SCALE: "_SCALE",
83
+ /**
84
+ * Gaussian Splat Rotation
85
+ *
86
+ * @type {string}
87
+ * @constant
88
+ */
89
+ ROTATION: "_ROTATION",
76
90
  };
77
91
 
78
92
  function semanticToVariableName(semantic) {
@@ -93,6 +107,10 @@ function semanticToVariableName(semantic) {
93
107
  return "weights";
94
108
  case VertexAttributeSemantic.FEATURE_ID:
95
109
  return "featureId";
110
+ case VertexAttributeSemantic.SCALE:
111
+ return "scale";
112
+ case VertexAttributeSemantic.ROTATION:
113
+ return "rotation";
96
114
  //>>includeStart('debug', pragmas.debug);
97
115
  default:
98
116
  throw new DeveloperError("semantic is not a valid value.");
@@ -124,6 +142,8 @@ VertexAttributeSemantic.hasSetIndex = function (semantic) {
124
142
  case VertexAttributeSemantic.JOINTS:
125
143
  case VertexAttributeSemantic.WEIGHTS:
126
144
  case VertexAttributeSemantic.FEATURE_ID:
145
+ case VertexAttributeSemantic.SCALE:
146
+ case VertexAttributeSemantic.ROTATION:
127
147
  return true;
128
148
  //>>includeStart('debug', pragmas.debug);
129
149
  default:
@@ -172,6 +192,10 @@ VertexAttributeSemantic.fromGltfSemantic = function (gltfSemantic) {
172
192
  return VertexAttributeSemantic.WEIGHTS;
173
193
  case "_FEATURE_ID":
174
194
  return VertexAttributeSemantic.FEATURE_ID;
195
+ case "_SCALE":
196
+ return VertexAttributeSemantic.SCALE;
197
+ case "_ROTATION":
198
+ return VertexAttributeSemantic.ROTATION;
175
199
  }
176
200
 
177
201
  return undefined;
@@ -241,6 +265,12 @@ VertexAttributeSemantic.getGlslType = function (semantic) {
241
265
  return "vec4";
242
266
  case VertexAttributeSemantic.FEATURE_ID:
243
267
  return "int";
268
+ case VertexAttributeSemantic.SCALE:
269
+ return "vec3";
270
+ case VertexAttributeSemantic.ROTATION:
271
+ return "vec4";
272
+ case VertexAttributeSemantic.OPACITY:
273
+ return "float";
244
274
  //>>includeStart('debug', pragmas.debug);
245
275
  default:
246
276
  throw new DeveloperError("semantic is not a valid value.");
@@ -0,0 +1,9 @@
1
+ /**
2
+ * The automatic GLSL constant for {@link Pass#GAUSSIAN_SPLATS}
3
+ *
4
+ * @name czm_passGaussianSplats
5
+ * @glslConstant
6
+ *
7
+ * @see czm_pass
8
+ */
9
+ const float czm_passGaussianSplats = 10.0;
@@ -0,0 +1,11 @@
1
+ //This file is automatically rebuilt by the Cesium build process.
2
+ export default "/**\n\
3
+ * The automatic GLSL constant for {@link Pass#GAUSSIAN_SPLATS}\n\
4
+ *\n\
5
+ * @name czm_passGaussianSplats\n\
6
+ * @glslConstant\n\
7
+ *\n\
8
+ * @see czm_pass\n\
9
+ */\n\
10
+ const float czm_passGaussianSplats = 10.0;\n\
11
+ ";
@@ -6,4 +6,4 @@
6
6
  *
7
7
  * @see czm_pass
8
8
  */
9
- const float czm_passOverlay = 10.0;
9
+ const float czm_passOverlay = 11.0;
@@ -7,5 +7,5 @@ export default "/**\n\
7
7
  *\n\
8
8
  * @see czm_pass\n\
9
9
  */\n\
10
- const float czm_passOverlay = 10.0;\n\
10
+ const float czm_passOverlay = 11.0;\n\
11
11
  ";
@@ -17,6 +17,7 @@ import czm_passCesium3DTileClassificationIgnoreShow from './Constants/passCesium
17
17
  import czm_passClassification from './Constants/passClassification.js'
18
18
  import czm_passCompute from './Constants/passCompute.js'
19
19
  import czm_passEnvironment from './Constants/passEnvironment.js'
20
+ import czm_passGaussianSplats from './Constants/passGaussianSplats.js'
20
21
  import czm_passGlobe from './Constants/passGlobe.js'
21
22
  import czm_passOpaque from './Constants/passOpaque.js'
22
23
  import czm_passOverlay from './Constants/passOverlay.js'
@@ -155,6 +156,7 @@ export default {
155
156
  czm_passClassification : czm_passClassification,
156
157
  czm_passCompute : czm_passCompute,
157
158
  czm_passEnvironment : czm_passEnvironment,
159
+ czm_passGaussianSplats : czm_passGaussianSplats,
158
160
  czm_passGlobe : czm_passGlobe,
159
161
  czm_passOpaque : czm_passOpaque,
160
162
  czm_passOverlay : czm_passOverlay,
@@ -1,5 +1,6 @@
1
1
 
2
2
  precision highp float;
3
+
3
4
  czm_modelMaterial defaultModelMaterial()
4
5
  {
5
6
  czm_modelMaterial material;
@@ -86,7 +87,7 @@ void main()
86
87
 
87
88
  // When not picking metadata END
88
89
  //========================================================================
89
- #else
90
+ #else
90
91
  //========================================================================
91
92
  // When picking metadata START
92
93
 
@@ -124,3 +125,4 @@ void main()
124
125
 
125
126
  out_FragColor = color;
126
127
  }
128
+
@@ -1,6 +1,7 @@
1
1
  //This file is automatically rebuilt by the Cesium build process.
2
2
  export default "\n\
3
3
  precision highp float;\n\
4
+ \n\
4
5
  czm_modelMaterial defaultModelMaterial()\n\
5
6
  {\n\
6
7
  czm_modelMaterial material;\n\
@@ -87,7 +88,7 @@ void main()\n\
87
88
  \n\
88
89
  // When not picking metadata END\n\
89
90
  //========================================================================\n\
90
- #else \n\
91
+ #else\n\
91
92
  //========================================================================\n\
92
93
  // When picking metadata START\n\
93
94
  \n\
@@ -125,4 +126,5 @@ void main()\n\
125
126
  \n\
126
127
  out_FragColor = color;\n\
127
128
  }\n\
129
+ \n\
128
130
  ";