@cesium/engine 17.0.0 → 18.0.1-splats.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 (188) hide show
  1. package/Build/ThirdParty/Workers/z-worker-pako.js +1 -1
  2. package/Build/Workers/{chunk-UC7KH56Y.js → chunk-2AXKROJA.js} +5 -5
  3. package/Build/Workers/{chunk-IKDQX7DY.js → chunk-2J5ZZ7CY.js} +4 -4
  4. package/Build/Workers/{chunk-4TIR5UPL.js → chunk-2SYY3UBI.js} +1 -1
  5. package/Build/Workers/{chunk-CC2WKHIW.js → chunk-2WKW3BEB.js} +6 -6
  6. package/Build/Workers/{chunk-CBFJVM6I.js → chunk-2ZO6BCHN.js} +11 -11
  7. package/Build/Workers/{chunk-7PHT4JHA.js → chunk-3UKG5X7F.js} +12 -12
  8. package/Build/Workers/{chunk-PM4Q36WX.js → chunk-4GYIDPXP.js} +9 -9
  9. package/Build/Workers/{chunk-QUFN3GEO.js → chunk-6EP7ED36.js} +3 -3
  10. package/Build/Workers/{chunk-QJTIOB2Z.js → chunk-6QOBORNG.js} +6 -6
  11. package/Build/Workers/{chunk-YE6MDFDA.js → chunk-6WWHK2ER.js} +14 -14
  12. package/Build/Workers/{chunk-RX65FA7X.js → chunk-6Y6TVYHS.js} +7 -7
  13. package/Build/Workers/{chunk-P2N5IDWU.js → chunk-744VWE2U.js} +13 -13
  14. package/Build/Workers/{chunk-LVGYWPEX.js → chunk-7PQ52XCW.js} +4 -4
  15. package/Build/Workers/{chunk-PS3OKVOQ.js → chunk-A5UFJW2M.js} +12 -12
  16. package/Build/Workers/{chunk-CAKU6ZPR.js → chunk-AQKVFTWV.js} +8 -8
  17. package/Build/Workers/{chunk-236N6BJN.js → chunk-BKTEHJFD.js} +2 -2
  18. package/Build/Workers/{chunk-5PC577K7.js → chunk-CQXYKPAW.js} +16 -16
  19. package/Build/Workers/{chunk-DRMXU674.js → chunk-DI7PHKC6.js} +5 -5
  20. package/Build/Workers/{chunk-CQMXZF4A.js → chunk-DKKIQS6F.js} +6 -6
  21. package/Build/Workers/{chunk-J2HTPGC7.js → chunk-DTVWE5YL.js} +2 -2
  22. package/Build/Workers/{chunk-SSLK4U3V.js → chunk-ERPS2WZC.js} +4 -4
  23. package/Build/Workers/chunk-EYMZ5FSQ.js +280 -0
  24. package/Build/Workers/{chunk-LPGOAMYH.js → chunk-F43TQW5B.js} +2 -2
  25. package/Build/Workers/{chunk-5RPUEFSA.js → chunk-FOMRN6II.js} +6 -6
  26. package/Build/Workers/{chunk-2BJXFXD7.js → chunk-FOTXJYKS.js} +4 -4
  27. package/Build/Workers/{chunk-VXAKU6EV.js → chunk-G2Y7EA4W.js} +5 -5
  28. package/Build/Workers/{chunk-KE45DUDH.js → chunk-GY4E4ZP6.js} +10 -10
  29. package/Build/Workers/{chunk-NZSBSY5K.js → chunk-HDG3VHYL.js} +2 -2
  30. package/Build/Workers/{chunk-WP3IJYLC.js → chunk-HOEUXPBL.js} +9 -9
  31. package/Build/Workers/{chunk-5YEFZMMM.js → chunk-IWDYVJ56.js} +12 -12
  32. package/Build/Workers/{chunk-SQKTLDSD.js → chunk-JA4KPQJL.js} +12 -12
  33. package/Build/Workers/{chunk-MAIKDIBS.js → chunk-JZZQEZMA.js} +6 -6
  34. package/Build/Workers/{chunk-77MDEA47.js → chunk-KPLU3WDY.js} +5 -5
  35. package/Build/Workers/{chunk-E7SMO47Q.js → chunk-LHM6V4D6.js} +5 -5
  36. package/Build/Workers/{chunk-HBNWBMAM.js → chunk-LMTGCD6P.js} +1 -1
  37. package/Build/Workers/{chunk-XYGBWBD5.js → chunk-LWZOYSSF.js} +1 -1
  38. package/Build/Workers/{chunk-OBHLT34A.js → chunk-M6U7SV4T.js} +7 -7
  39. package/Build/Workers/{chunk-MS5NWDHH.js → chunk-O25M56DO.js} +2 -2
  40. package/Build/Workers/{chunk-UX5JWAC7.js → chunk-OE2WXO2Z.js} +10 -10
  41. package/Build/Workers/{chunk-C5DCX2YQ.js → chunk-PFD462OE.js} +6 -6
  42. package/Build/Workers/{chunk-37PA7GZW.js → chunk-PPI33PXH.js} +7 -7
  43. package/Build/Workers/{chunk-4BGKMM7J.js → chunk-PRQQHLUB.js} +1 -1
  44. package/Build/Workers/{chunk-IFIS4CVK.js → chunk-RTUZ7MJB.js} +2 -2
  45. package/Build/Workers/{chunk-G6JUXZUO.js → chunk-S6QBTP5U.js} +4 -4
  46. package/Build/Workers/{chunk-UFV3YUIN.js → chunk-SMFCIGM3.js} +5 -5
  47. package/Build/Workers/{chunk-P57PR3WM.js → chunk-TC3LEKFJ.js} +5 -5
  48. package/Build/Workers/{chunk-7IIMO7ZZ.js → chunk-UTLYCPFY.js} +16 -16
  49. package/Build/Workers/{chunk-HGEGZ67N.js → chunk-V7LEBY53.js} +6 -6
  50. package/Build/Workers/{chunk-GO3RZX2R.js → chunk-VE3UKRDB.js} +9 -9
  51. package/Build/Workers/{chunk-ZTBZMRQT.js → chunk-W3FBD4FE.js} +8 -8
  52. package/Build/Workers/{chunk-K5JTWJPE.js → chunk-YRR6CJGG.js} +4 -4
  53. package/Build/Workers/{chunk-UZ6KXWCA.js → chunk-ZVTKMLU6.js} +4 -4
  54. package/Build/Workers/combineGeometry.js +21 -21
  55. package/Build/Workers/createBoxGeometry.js +15 -15
  56. package/Build/Workers/createBoxOutlineGeometry.js +13 -13
  57. package/Build/Workers/createCircleGeometry.js +23 -23
  58. package/Build/Workers/createCircleOutlineGeometry.js +16 -16
  59. package/Build/Workers/createCoplanarPolygonGeometry.js +30 -30
  60. package/Build/Workers/createCoplanarPolygonOutlineGeometry.js +28 -28
  61. package/Build/Workers/createCorridorGeometry.js +26 -26
  62. package/Build/Workers/createCorridorOutlineGeometry.js +25 -25
  63. package/Build/Workers/createCylinderGeometry.js +17 -17
  64. package/Build/Workers/createCylinderOutlineGeometry.js +15 -15
  65. package/Build/Workers/createEllipseGeometry.js +23 -23
  66. package/Build/Workers/createEllipseOutlineGeometry.js +16 -16
  67. package/Build/Workers/createEllipsoidGeometry.js +16 -16
  68. package/Build/Workers/createEllipsoidOutlineGeometry.js +15 -15
  69. package/Build/Workers/createFrustumGeometry.js +15 -15
  70. package/Build/Workers/createFrustumOutlineGeometry.js +15 -15
  71. package/Build/Workers/createGeometry.js +23 -21
  72. package/Build/Workers/createGroundPolylineGeometry.js +19 -19
  73. package/Build/Workers/createPlaneGeometry.js +13 -13
  74. package/Build/Workers/createPlaneOutlineGeometry.js +12 -12
  75. package/Build/Workers/createPolygonGeometry.js +29 -29
  76. package/Build/Workers/createPolygonOutlineGeometry.js +27 -27
  77. package/Build/Workers/createPolylineGeometry.js +22 -22
  78. package/Build/Workers/createPolylineVolumeGeometry.js +28 -28
  79. package/Build/Workers/createPolylineVolumeOutlineGeometry.js +24 -24
  80. package/Build/Workers/createRectangleGeometry.js +24 -24
  81. package/Build/Workers/createRectangleOutlineGeometry.js +17 -17
  82. package/Build/Workers/createSimplePolylineGeometry.js +20 -20
  83. package/Build/Workers/createSphereGeometry.js +16 -16
  84. package/Build/Workers/createSphereOutlineGeometry.js +15 -15
  85. package/Build/Workers/createTaskProcessorWorker.js +3 -3
  86. package/Build/Workers/createVectorTileClampedPolylines.js +12 -12
  87. package/Build/Workers/createVectorTileGeometries.js +21 -21
  88. package/Build/Workers/createVectorTilePoints.js +11 -11
  89. package/Build/Workers/createVectorTilePolygons.js +19 -19
  90. package/Build/Workers/createVectorTilePolylines.js +12 -12
  91. package/Build/Workers/createVerticesFromGoogleEarthEnterpriseBuffer.js +19 -19
  92. package/Build/Workers/createVerticesFromHeightmap.js +19 -19
  93. package/Build/Workers/createVerticesFromQuantizedTerrainMesh.js +16 -16
  94. package/Build/Workers/createWallGeometry.js +21 -21
  95. package/Build/Workers/createWallOutlineGeometry.js +20 -20
  96. package/Build/Workers/decodeDraco.js +10 -10
  97. package/Build/Workers/decodeGoogleEarthEnterprisePacket.js +5 -5
  98. package/Build/Workers/decodeI3S.js +9 -9
  99. package/Build/Workers/gaussianSplatSorter.js +62 -0
  100. package/Build/Workers/gaussianSplatTextureGenerator.js +68 -0
  101. package/Build/Workers/transcodeKTX2.js +78 -7
  102. package/Build/Workers/transferTypedArrayTest.js +1 -1
  103. package/Build/Workers/upsampleQuantizedTerrainMesh.js +19 -19
  104. package/Source/Core/Ion.js +1 -1
  105. package/Source/Core/PixelFormat.js +98 -0
  106. package/Source/Renderer/Context.js +2 -0
  107. package/Source/Renderer/Pass.js +3 -2
  108. package/Source/Renderer/Texture.js +1 -0
  109. package/Source/Renderer/Texture3D.js +568 -0
  110. package/Source/Renderer/VertexArray.js +33 -8
  111. package/Source/Renderer/createUniform.js +3 -0
  112. package/Source/Renderer/createUniformArray.js +1 -0
  113. package/Source/Scene/ArcGisMapService.js +1 -1
  114. package/Source/Scene/Cesium3DTileContentFactory.js +23 -0
  115. package/Source/Scene/Cesium3DTileset.js +197 -2
  116. package/Source/Scene/GaussianSplat3DTileContent.js +504 -0
  117. package/Source/Scene/GaussianSplatPrimitive.js +932 -0
  118. package/Source/Scene/GaussianSplatRenderResources.js +81 -0
  119. package/Source/Scene/GaussianSplatSorter.js +73 -0
  120. package/Source/Scene/GaussianSplatTextureGenerator.js +64 -0
  121. package/Source/Scene/GlobeSurfaceShaderSet.js +4 -5
  122. package/Source/Scene/GltfLoader.js +82 -4
  123. package/Source/Scene/GltfSpzLoader.js +222 -0
  124. package/Source/Scene/GltfVertexBufferLoader.js +98 -3
  125. package/Source/Scene/ImageryLayer.js +19 -4
  126. package/Source/Scene/ImageryLayerCollection.js +3 -2
  127. package/Source/Scene/Model/CartesianRectangle.js +108 -0
  128. package/Source/Scene/Model/ImageryConfiguration.js +25 -0
  129. package/Source/Scene/Model/ImageryCoverage.js +488 -0
  130. package/Source/Scene/Model/ImageryFlags.js +31 -0
  131. package/Source/Scene/Model/ImageryInput.js +60 -0
  132. package/Source/Scene/Model/ImageryPipelineStage.js +1040 -0
  133. package/Source/Scene/Model/MappedPositions.js +84 -0
  134. package/Source/Scene/Model/Model.js +38 -0
  135. package/Source/Scene/Model/ModelImagery.js +403 -0
  136. package/Source/Scene/Model/ModelImageryMapping.js +489 -0
  137. package/Source/Scene/Model/ModelPrimitiveImagery.js +972 -0
  138. package/Source/Scene/Model/ModelReader.js +810 -0
  139. package/Source/Scene/Model/ModelRenderResources.js +13 -0
  140. package/Source/Scene/Model/ModelRuntimePrimitive.js +20 -0
  141. package/Source/Scene/Model/ModelSceneGraph.js +133 -27
  142. package/Source/Scene/Model/ModelUtility.js +2 -0
  143. package/Source/Scene/Model/NodeRenderResources.js +10 -0
  144. package/Source/Scene/ModelComponents.js +10 -0
  145. package/Source/Scene/PrimitiveLoadPlan.js +59 -0
  146. package/Source/Scene/ResourceCache.js +60 -3
  147. package/Source/Scene/ResourceCacheKey.js +39 -1
  148. package/Source/Scene/Scene.js +32 -1
  149. package/Source/Scene/VertexAttributeSemantic.js +30 -0
  150. package/Source/Scene/VoxelPrimitive.js +22 -37
  151. package/Source/Scene/VoxelRenderResources.js +1 -1
  152. package/Source/Scene/processVoxelProperties.js +41 -100
  153. package/Source/Shaders/Builtin/Constants/passGaussianSplats.glsl +9 -0
  154. package/Source/Shaders/Builtin/Constants/passGaussianSplats.js +11 -0
  155. package/Source/Shaders/Builtin/Constants/passOverlay.glsl +1 -1
  156. package/Source/Shaders/Builtin/Constants/passOverlay.js +1 -1
  157. package/Source/Shaders/Builtin/CzmBuiltins.js +2 -0
  158. package/Source/Shaders/Builtin/Functions/windowToEyeCoordinates.glsl +0 -1
  159. package/Source/Shaders/Builtin/Functions/windowToEyeCoordinates.js +0 -1
  160. package/Source/Shaders/GlobeFS.glsl +22 -0
  161. package/Source/Shaders/GlobeFS.js +22 -0
  162. package/Source/Shaders/Model/MaterialStageFS.glsl +4 -0
  163. package/Source/Shaders/Model/MaterialStageFS.js +4 -0
  164. package/Source/Shaders/Model/ModelFS.glsl +3 -1
  165. package/Source/Shaders/Model/ModelFS.js +3 -1
  166. package/Source/Shaders/Model/ModelVS.glsl +5 -1
  167. package/Source/Shaders/Model/ModelVS.js +5 -1
  168. package/Source/Shaders/Model/PointCloudStylingStageVS.glsl +1 -1
  169. package/Source/Shaders/Model/PointCloudStylingStageVS.js +2 -1
  170. package/Source/Shaders/PrimitiveGaussianSplatFS.glsl +18 -0
  171. package/Source/Shaders/PrimitiveGaussianSplatFS.js +20 -0
  172. package/Source/Shaders/PrimitiveGaussianSplatVS.glsl +108 -0
  173. package/Source/Shaders/PrimitiveGaussianSplatVS.js +109 -0
  174. package/Source/Shaders/Voxels/IntersectDepth.glsl +10 -3
  175. package/Source/Shaders/Voxels/IntersectDepth.js +10 -3
  176. package/Source/Shaders/Voxels/Intersection.glsl +1 -3
  177. package/Source/Shaders/Voxels/Intersection.js +1 -3
  178. package/Source/Shaders/Voxels/IntersectionUtils.glsl +1 -0
  179. package/Source/Shaders/Voxels/IntersectionUtils.js +1 -0
  180. package/Source/Shaders/Voxels/VoxelFS.glsl +37 -24
  181. package/Source/Shaders/Voxels/VoxelFS.js +37 -24
  182. package/Source/ThirdParty/Workers/z-worker-pako.js +1 -1
  183. package/Source/ThirdParty/wasm_splats_bg.wasm +0 -0
  184. package/Source/Workers/gaussianSplatSorter.js +34 -0
  185. package/Source/Workers/gaussianSplatTextureGenerator.js +39 -0
  186. package/index.d.ts +66 -2
  187. package/index.js +101 -80
  188. package/package.json +6 -4
@@ -101,6 +101,19 @@ function ModelRenderResources(model) {
101
101
  * @private
102
102
  */
103
103
  this.hasSkipLevelOfDetail = false;
104
+
105
+ /**
106
+ * The NodeRenderResources for the nodes of the scene graph.
107
+ *
108
+ * Note that elements of this array may be <code>undefined</code> when
109
+ * there was no runtime node for a certain node.
110
+ *
111
+ * @type {NodeRenderResources[]}
112
+ * @default []
113
+ *
114
+ * @private
115
+ */
116
+ this.nodeRenderResources = [];
104
117
  }
105
118
 
106
119
  export default ModelRenderResources;
@@ -12,6 +12,7 @@ import CustomShaderPipelineStage from "./CustomShaderPipelineStage.js";
12
12
  import DequantizationPipelineStage from "./DequantizationPipelineStage.js";
13
13
  import FeatureIdPipelineStage from "./FeatureIdPipelineStage.js";
14
14
  import GeometryPipelineStage from "./GeometryPipelineStage.js";
15
+ import ImageryPipelineStage from "./ImageryPipelineStage.js";
15
16
  import LightingPipelineStage from "./LightingPipelineStage.js";
16
17
  import MaterialPipelineStage from "./MaterialPipelineStage.js";
17
18
  import MetadataPickingPipelineStage from "./MetadataPickingPipelineStage.js";
@@ -27,6 +28,7 @@ import SelectedFeatureIdPipelineStage from "./SelectedFeatureIdPipelineStage.js"
27
28
  import SkinningPipelineStage from "./SkinningPipelineStage.js";
28
29
  import VerticalExaggerationPipelineStage from "./VerticalExaggerationPipelineStage.js";
29
30
  import WireframePipelineStage from "./WireframePipelineStage.js";
31
+ import oneTimeWarning from "../../Core/oneTimeWarning.js";
30
32
 
31
33
  /**
32
34
  * In memory representation of a single primitive, that is, a primitive
@@ -206,6 +208,12 @@ ModelRuntimePrimitive.prototype.configurePipeline = function (frameState) {
206
208
  const hasMorphTargets =
207
209
  defined(primitive.morphTargets) && primitive.morphTargets.length > 0;
208
210
  const hasSkinning = defined(node.skin);
211
+
212
+ // Check whether the model is part of a `Model3DTileContent` that
213
+ // belongs to a tileset that has imagery layers. If this is the
214
+ // case, then the `ImageryPipelineStage` will be required.
215
+ const hasImageryLayers = defined(model.imageryLayers);
216
+
209
217
  const hasCustomShader = defined(customShader);
210
218
  const hasCustomFragmentShader =
211
219
  hasCustomShader && defined(customShader.fragmentShaderText);
@@ -215,6 +223,7 @@ ModelRuntimePrimitive.prototype.configurePipeline = function (frameState) {
215
223
  const hasQuantization = ModelUtility.hasQuantizedAttributes(
216
224
  primitive.attributes,
217
225
  );
226
+
218
227
  const generateWireframeIndices =
219
228
  model.debugWireframe &&
220
229
  PrimitiveType.isTriangles(primitive.primitiveType) &&
@@ -270,6 +279,17 @@ ModelRuntimePrimitive.prototype.configurePipeline = function (frameState) {
270
279
  pipelineStages.push(DequantizationPipelineStage);
271
280
  }
272
281
 
282
+ if (hasImageryLayers) {
283
+ if (hasOutlines) {
284
+ oneTimeWarning(
285
+ "outlines-and-draping",
286
+ "Primitive outlines disable imagery draping",
287
+ );
288
+ } else {
289
+ pipelineStages.push(ImageryPipelineStage);
290
+ }
291
+ }
292
+
273
293
  if (materialsEnabled) {
274
294
  pipelineStages.push(MaterialPipelineStage);
275
295
  }
@@ -445,6 +445,7 @@ const scratchModelPositionMin = new Cartesian3();
445
445
  const scratchModelPositionMax = new Cartesian3();
446
446
  const scratchPrimitivePositionMin = new Cartesian3();
447
447
  const scratchPrimitivePositionMax = new Cartesian3();
448
+
448
449
  /**
449
450
  * Generates the {@link ModelDrawCommand} for each primitive in the model.
450
451
  * If the model is used for classification, a {@link ClassificationModelDrawCommand}
@@ -456,6 +457,30 @@ const scratchPrimitivePositionMax = new Cartesian3();
456
457
  * @private
457
458
  */
458
459
  ModelSceneGraph.prototype.buildDrawCommands = function (frameState) {
460
+ const modelRenderResources = this.buildRenderResources(frameState);
461
+ this.computeBoundingVolumes(modelRenderResources);
462
+ this.createDrawCommands(modelRenderResources, frameState);
463
+ };
464
+
465
+ /**
466
+ * Generates the {@link ModelRenderResources} for the model.
467
+ *
468
+ * This will traverse the model, nodes and primitives of the scene graph,
469
+ * and perform the following tasks:
470
+ *
471
+ * - configure the pipeline stages by calling `configurePipeline`,
472
+ * `runtimeNode.configurePipeline`, and `runtimePrimitive.configurePipeline`
473
+ * - create the `ModelRenderResources`, `NodeRenderResources`, and
474
+ * `PrimitiveRenderResources`
475
+ * - Process the render resources with the respective pipelines
476
+ *
477
+ * @param {FrameState} frameState The current frame state. This is needed to
478
+ * allocate GPU resources as needed.
479
+ * @returns {ModelRenderResources} The model render resources
480
+ *
481
+ * @private
482
+ */
483
+ ModelSceneGraph.prototype.buildRenderResources = function (frameState) {
459
484
  const model = this._model;
460
485
  const modelRenderResources = new ModelRenderResources(model);
461
486
 
@@ -465,26 +490,12 @@ ModelSceneGraph.prototype.buildDrawCommands = function (frameState) {
465
490
  this.configurePipeline(frameState);
466
491
  const modelPipelineStages = this.modelPipelineStages;
467
492
 
468
- let i, j, k;
469
- for (i = 0; i < modelPipelineStages.length; i++) {
493
+ for (let i = 0; i < modelPipelineStages.length; i++) {
470
494
  const modelPipelineStage = modelPipelineStages[i];
471
495
  modelPipelineStage.process(modelRenderResources, model, frameState);
472
496
  }
473
497
 
474
- const modelPositionMin = Cartesian3.fromElements(
475
- Number.MAX_VALUE,
476
- Number.MAX_VALUE,
477
- Number.MAX_VALUE,
478
- scratchModelPositionMin,
479
- );
480
- const modelPositionMax = Cartesian3.fromElements(
481
- -Number.MAX_VALUE,
482
- -Number.MAX_VALUE,
483
- -Number.MAX_VALUE,
484
- scratchModelPositionMax,
485
- );
486
-
487
- for (i = 0; i < this._runtimeNodes.length; i++) {
498
+ for (let i = 0; i < this._runtimeNodes.length; i++) {
488
499
  const runtimeNode = this._runtimeNodes[i];
489
500
 
490
501
  // If a node in the model was unreachable from the scene graph, there will
@@ -500,8 +511,9 @@ ModelSceneGraph.prototype.buildDrawCommands = function (frameState) {
500
511
  modelRenderResources,
501
512
  runtimeNode,
502
513
  );
514
+ modelRenderResources.nodeRenderResources[i] = nodeRenderResources;
503
515
 
504
- for (j = 0; j < nodePipelineStages.length; j++) {
516
+ for (let j = 0; j < nodePipelineStages.length; j++) {
505
517
  const nodePipelineStage = nodePipelineStages[j];
506
518
 
507
519
  nodePipelineStage.process(
@@ -511,8 +523,7 @@ ModelSceneGraph.prototype.buildDrawCommands = function (frameState) {
511
523
  );
512
524
  }
513
525
 
514
- const nodeTransform = runtimeNode.computedTransform;
515
- for (j = 0; j < runtimeNode.runtimePrimitives.length; j++) {
526
+ for (let j = 0; j < runtimeNode.runtimePrimitives.length; j++) {
516
527
  const runtimePrimitive = runtimeNode.runtimePrimitives[j];
517
528
 
518
529
  runtimePrimitive.configurePipeline(frameState);
@@ -522,16 +533,76 @@ ModelSceneGraph.prototype.buildDrawCommands = function (frameState) {
522
533
  nodeRenderResources,
523
534
  runtimePrimitive,
524
535
  );
536
+ nodeRenderResources.primitiveRenderResources[j] =
537
+ primitiveRenderResources;
525
538
 
526
- for (k = 0; k < primitivePipelineStages.length; k++) {
539
+ for (let k = 0; k < primitivePipelineStages.length; k++) {
527
540
  const primitivePipelineStage = primitivePipelineStages[k];
528
-
529
541
  primitivePipelineStage.process(
530
542
  primitiveRenderResources,
531
543
  runtimePrimitive.primitive,
532
544
  frameState,
533
545
  );
534
546
  }
547
+ }
548
+ }
549
+ return modelRenderResources;
550
+ };
551
+
552
+ /**
553
+ * Computes the bounding volumes for the scene graph and the model.
554
+ *
555
+ * This will traverse the model, nodes and primitives of the scene graph,
556
+ * and compute the bounding volumes. Specifically, it will compute
557
+ *
558
+ * - this._boundingSphere
559
+ * - model._boundingSphere
560
+ *
561
+ * With the latter being modified as of
562
+ *
563
+ * - model._initialRadius = model._boundingSphere.radius;
564
+ * - model._boundingSphere.radius *= model._clampedScale;
565
+ *
566
+ * NOTE: This contains some bugs. See https://github.com/CesiumGS/cesium/issues/12108
567
+ *
568
+ * @param {ModelRenderResources} modelRenderResources The model render resources
569
+ *
570
+ * @private
571
+ */
572
+ ModelSceneGraph.prototype.computeBoundingVolumes = function (
573
+ modelRenderResources,
574
+ ) {
575
+ const model = this._model;
576
+
577
+ const modelPositionMin = Cartesian3.fromElements(
578
+ Number.MAX_VALUE,
579
+ Number.MAX_VALUE,
580
+ Number.MAX_VALUE,
581
+ scratchModelPositionMin,
582
+ );
583
+ const modelPositionMax = Cartesian3.fromElements(
584
+ -Number.MAX_VALUE,
585
+ -Number.MAX_VALUE,
586
+ -Number.MAX_VALUE,
587
+ scratchModelPositionMax,
588
+ );
589
+
590
+ for (let i = 0; i < this._runtimeNodes.length; i++) {
591
+ const runtimeNode = this._runtimeNodes[i];
592
+
593
+ // If a node in the model was unreachable from the scene graph, there will
594
+ // be no corresponding runtime node and therefore should be skipped.
595
+ if (!defined(runtimeNode)) {
596
+ continue;
597
+ }
598
+
599
+ const nodeRenderResources = modelRenderResources.nodeRenderResources[i];
600
+ const nodeTransform = runtimeNode.computedTransform;
601
+ for (let j = 0; j < runtimeNode.runtimePrimitives.length; j++) {
602
+ const runtimePrimitive = runtimeNode.runtimePrimitives[j];
603
+
604
+ const primitiveRenderResources =
605
+ nodeRenderResources.primitiveRenderResources[j];
535
606
 
536
607
  runtimePrimitive.boundingSphere = BoundingSphere.clone(
537
608
  primitiveRenderResources.boundingSphere,
@@ -559,12 +630,6 @@ ModelSceneGraph.prototype.buildDrawCommands = function (frameState) {
559
630
  primitivePositionMax,
560
631
  modelPositionMax,
561
632
  );
562
-
563
- const drawCommand = ModelDrawCommands.buildModelDrawCommand(
564
- primitiveRenderResources,
565
- frameState,
566
- );
567
- runtimePrimitive.drawCommand = drawCommand;
568
633
  }
569
634
  }
570
635
 
@@ -596,6 +661,47 @@ ModelSceneGraph.prototype.buildDrawCommands = function (frameState) {
596
661
  model._boundingSphere.radius *= model._clampedScale;
597
662
  };
598
663
 
664
+ /**
665
+ * Creates the draw commands for the primitives in the scene graph.
666
+ *
667
+ * This will traverse the model, nodes and primitives of the scene graph,
668
+ * and create the respective draw commands for the primitives, storing
669
+ * them as the `runtimePrimitive.drawCommand`, respectively.
670
+ *
671
+ * @param {ModelRenderResources} modelRenderResources The model render resources
672
+ *
673
+ * @private
674
+ */
675
+ ModelSceneGraph.prototype.createDrawCommands = function (
676
+ modelRenderResources,
677
+ frameState,
678
+ ) {
679
+ for (let i = 0; i < this._runtimeNodes.length; i++) {
680
+ const runtimeNode = this._runtimeNodes[i];
681
+
682
+ // If a node in the model was unreachable from the scene graph, there will
683
+ // be no corresponding runtime node and therefore should be skipped.
684
+ if (!defined(runtimeNode)) {
685
+ continue;
686
+ }
687
+
688
+ const nodeRenderResources = modelRenderResources.nodeRenderResources[i];
689
+
690
+ for (let j = 0; j < runtimeNode.runtimePrimitives.length; j++) {
691
+ const runtimePrimitive = runtimeNode.runtimePrimitives[j];
692
+
693
+ const primitiveRenderResources =
694
+ nodeRenderResources.primitiveRenderResources[j];
695
+
696
+ const drawCommand = ModelDrawCommands.buildModelDrawCommand(
697
+ primitiveRenderResources,
698
+ frameState,
699
+ );
700
+ runtimePrimitive.drawCommand = drawCommand;
701
+ }
702
+ }
703
+ };
704
+
599
705
  /**
600
706
  * Configure the model pipeline stages. If the pipeline needs to be re-run, call
601
707
  * this method again to ensure the correct sequence of pipeline stages are
@@ -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
 
@@ -155,6 +155,16 @@ function NodeRenderResources(modelRenderResources, runtimeNode) {
155
155
  * @private
156
156
  */
157
157
  this.instanceCount = 0;
158
+
159
+ /**
160
+ * The PrimitiveRenderResources for the primitives of the node.
161
+ *
162
+ * @type {PrimitiveRenderResources[]}
163
+ * @default []
164
+ *
165
+ * @private
166
+ */
167
+ this.primitiveRenderResources = [];
158
168
  }
159
169
 
160
170
  export default NodeRenderResources;
@@ -620,6 +620,16 @@ function Primitive() {
620
620
  * @private
621
621
  */
622
622
  this.outlineCoordinates = undefined;
623
+
624
+ /**
625
+ * If the model is part of a Model3DTileContent of a Cesium3DTileset that
626
+ * has 'imageryLayers', then this will represent the information that is
627
+ * required for draping the imagery over this primitive.
628
+ *
629
+ * @type {ModelPrimitiveImagery|undefined}
630
+ * @private
631
+ */
632
+ this.modelPrimitiveImagery = undefined;
623
633
  }
624
634
 
625
635
  /**
@@ -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;