@cesium/engine 18.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 (146) hide show
  1. package/Build/Workers/{chunk-WTFZHPUW.js → chunk-2AXKROJA.js} +5 -5
  2. package/Build/Workers/{chunk-UK33ZN4K.js → chunk-2J5ZZ7CY.js} +4 -4
  3. package/Build/Workers/{chunk-2AXPWBJG.js → chunk-2SYY3UBI.js} +1 -1
  4. package/Build/Workers/{chunk-ZIP27IX6.js → chunk-2WKW3BEB.js} +6 -6
  5. package/Build/Workers/{chunk-LIPZUYNR.js → chunk-2ZO6BCHN.js} +11 -11
  6. package/Build/Workers/{chunk-KGXTCGX3.js → chunk-3UKG5X7F.js} +12 -12
  7. package/Build/Workers/{chunk-IWGMVQGG.js → chunk-4GYIDPXP.js} +9 -9
  8. package/Build/Workers/{chunk-NR7KSD56.js → chunk-6EP7ED36.js} +3 -3
  9. package/Build/Workers/{chunk-J4MAVE6J.js → chunk-6QOBORNG.js} +6 -6
  10. package/Build/Workers/{chunk-GM55YFOB.js → chunk-6WWHK2ER.js} +14 -14
  11. package/Build/Workers/{chunk-JF4IYQYC.js → chunk-6Y6TVYHS.js} +7 -7
  12. package/Build/Workers/{chunk-4MIY63FM.js → chunk-744VWE2U.js} +13 -13
  13. package/Build/Workers/{chunk-ZADJ6FRX.js → chunk-7PQ52XCW.js} +4 -4
  14. package/Build/Workers/{chunk-2NKHPWDY.js → chunk-A5UFJW2M.js} +12 -12
  15. package/Build/Workers/{chunk-2CAYUY2B.js → chunk-AQKVFTWV.js} +8 -8
  16. package/Build/Workers/{chunk-F4ZAKN4V.js → chunk-BKTEHJFD.js} +2 -2
  17. package/Build/Workers/{chunk-GAUF4F5A.js → chunk-CQXYKPAW.js} +16 -16
  18. package/Build/Workers/{chunk-QN7JEOQV.js → chunk-DI7PHKC6.js} +5 -5
  19. package/Build/Workers/{chunk-NWSAYFZG.js → chunk-DKKIQS6F.js} +6 -6
  20. package/Build/Workers/{chunk-4DSTDGY3.js → chunk-DTVWE5YL.js} +2 -2
  21. package/Build/Workers/{chunk-EXEZHW3P.js → chunk-ERPS2WZC.js} +4 -4
  22. package/Build/Workers/chunk-EYMZ5FSQ.js +280 -0
  23. package/Build/Workers/{chunk-HQE7KSR4.js → chunk-F43TQW5B.js} +2 -2
  24. package/Build/Workers/{chunk-W6CPO62M.js → chunk-FOMRN6II.js} +6 -6
  25. package/Build/Workers/{chunk-VGJSKEIB.js → chunk-FOTXJYKS.js} +4 -4
  26. package/Build/Workers/{chunk-2QNKQVUT.js → chunk-G2Y7EA4W.js} +5 -5
  27. package/Build/Workers/{chunk-LZFUG3GO.js → chunk-GY4E4ZP6.js} +10 -10
  28. package/Build/Workers/{chunk-WYCR5DWQ.js → chunk-HDG3VHYL.js} +2 -2
  29. package/Build/Workers/{chunk-YV37YFUM.js → chunk-HOEUXPBL.js} +9 -9
  30. package/Build/Workers/{chunk-OATG6PKE.js → chunk-IWDYVJ56.js} +12 -12
  31. package/Build/Workers/{chunk-AEGAQ6FD.js → chunk-JA4KPQJL.js} +12 -12
  32. package/Build/Workers/{chunk-DINSLSJD.js → chunk-JZZQEZMA.js} +6 -6
  33. package/Build/Workers/{chunk-QUSP3NWA.js → chunk-KPLU3WDY.js} +5 -5
  34. package/Build/Workers/{chunk-5WVF4BK7.js → chunk-LHM6V4D6.js} +5 -5
  35. package/Build/Workers/{chunk-FPYBD2P5.js → chunk-LMTGCD6P.js} +1 -1
  36. package/Build/Workers/{chunk-5OL6XFNS.js → chunk-LWZOYSSF.js} +1 -1
  37. package/Build/Workers/{chunk-T6B6H3GR.js → chunk-M6U7SV4T.js} +7 -7
  38. package/Build/Workers/{chunk-NVJ5JRIM.js → chunk-O25M56DO.js} +2 -2
  39. package/Build/Workers/{chunk-OIHAAHBK.js → chunk-OE2WXO2Z.js} +10 -10
  40. package/Build/Workers/{chunk-LWJWWCZ4.js → chunk-PFD462OE.js} +6 -6
  41. package/Build/Workers/{chunk-WGHUCZMX.js → chunk-PPI33PXH.js} +7 -7
  42. package/Build/Workers/{chunk-CES6DHHV.js → chunk-PRQQHLUB.js} +1 -1
  43. package/Build/Workers/{chunk-HS76VTVY.js → chunk-RTUZ7MJB.js} +2 -2
  44. package/Build/Workers/{chunk-EHB2OCQX.js → chunk-S6QBTP5U.js} +4 -4
  45. package/Build/Workers/{chunk-IWZK2AIH.js → chunk-SMFCIGM3.js} +5 -5
  46. package/Build/Workers/{chunk-MFGVMUN3.js → chunk-TC3LEKFJ.js} +5 -5
  47. package/Build/Workers/{chunk-I3BAKR4S.js → chunk-UTLYCPFY.js} +16 -16
  48. package/Build/Workers/{chunk-GS55WTRX.js → chunk-V7LEBY53.js} +6 -6
  49. package/Build/Workers/{chunk-RWFYLWSF.js → chunk-VE3UKRDB.js} +9 -9
  50. package/Build/Workers/{chunk-3RKVDGRF.js → chunk-W3FBD4FE.js} +8 -8
  51. package/Build/Workers/{chunk-KNA65INJ.js → chunk-YRR6CJGG.js} +4 -4
  52. package/Build/Workers/{chunk-SIOVJ4L5.js → chunk-ZVTKMLU6.js} +4 -4
  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 +70 -61
  146. package/package.json +4 -2
@@ -0,0 +1,81 @@
1
+ import ShaderBuilder from "../Renderer/ShaderBuilder.js";
2
+ import RenderState from "../Renderer/RenderState.js";
3
+ import DepthFunction from "../Scene/DepthFunction.js";
4
+ import ModelAlphaOptions from "./Model/ModelAlphaOptions.js";
5
+ import ShaderDestination from "../Renderer/ShaderDestination.js";
6
+
7
+ function GaussianSplatRenderResources(primitive) {
8
+ const shaderBuilder = new ShaderBuilder();
9
+ /**
10
+ * An object used to build a shader incrementally. Each pipeline stage
11
+ * may add lines of shader code to this object.
12
+ *
13
+ * @type {ShaderBuilder}
14
+ * @readonly
15
+ *
16
+ * @private
17
+ */
18
+ this.shaderBuilder = shaderBuilder;
19
+
20
+ /**
21
+ * A dictionary mapping uniform name to functions that return the uniform
22
+ * values.
23
+ *
24
+ * @type {Object<string, Function>}
25
+ * @readonly
26
+ *
27
+ * @private
28
+ */
29
+ this.uniformMap = {};
30
+
31
+ /**
32
+ * An object storing options for creating a {@link RenderState}.
33
+ * The pipeline stages simply set the options, the render state is created
34
+ * when the {@link DrawCommand} is constructed.
35
+ *
36
+ * @type {object}
37
+ * @readonly
38
+ *
39
+ * @private
40
+ */
41
+ this.renderStateOptions = RenderState.getState(
42
+ RenderState.fromCache({
43
+ depthTest: {
44
+ enabled: true,
45
+ func: DepthFunction.LESS_OR_EQUAL,
46
+ },
47
+ }),
48
+ );
49
+
50
+ /**
51
+ * Options for configuring the alpha stage such as pass and alpha cutoff.
52
+ *
53
+ * @type {ModelAlphaOptions}
54
+ * @readonly
55
+ *
56
+ * @private
57
+ */
58
+ this.alphaOptions = new ModelAlphaOptions();
59
+
60
+ /**
61
+ * Whether the model is part of a tileset that uses the skipLevelOfDetail
62
+ * optimization. This value indicates what draw commands are needed and
63
+ * is set by TilesetPipelineStage.
64
+ *
65
+ * @type {boolean}
66
+ * @default false
67
+ *
68
+ * @private
69
+ */
70
+ this.hasSkipLevelOfDetail = false;
71
+
72
+ if (primitive._useLogDepth) {
73
+ shaderBuilder.addDefine(
74
+ "LOG_DEPTH_READ_ONLY",
75
+ undefined,
76
+ ShaderDestination.FRAGMENT,
77
+ );
78
+ }
79
+ }
80
+
81
+ export default GaussianSplatRenderResources;
@@ -0,0 +1,73 @@
1
+ import defined from "../Core/defined.js";
2
+ import FeatureDetection from "../Core/FeatureDetection.js";
3
+ import RuntimeError from "../Core/RuntimeError.js";
4
+ import TaskProcessor from "../Core/TaskProcessor.js";
5
+
6
+ /** * A sorter for Gaussian splats that uses a task processor to handle sorting in parallel.
7
+ * This class is responsible for initializing the task processor and scheduling sorting tasks.
8
+ * * @constructor
9
+ * @private
10
+ */
11
+ function GaussianSplatSorter() {}
12
+
13
+ GaussianSplatSorter._maxSortingConcurrency = Math.max(
14
+ FeatureDetection.hardwareConcurrency - 1,
15
+ 1,
16
+ );
17
+
18
+ GaussianSplatSorter._sorterTaskProcessor = undefined;
19
+ GaussianSplatSorter._taskProcessorReady = false;
20
+ GaussianSplatSorter._error = undefined;
21
+ GaussianSplatSorter._getSorterTaskProcessor = function () {
22
+ if (!defined(GaussianSplatSorter._sorterTaskProcessor)) {
23
+ const processor = new TaskProcessor(
24
+ "gaussianSplatSorter",
25
+ GaussianSplatSorter._maxSortingConcurrency,
26
+ );
27
+ processor
28
+ .initWebAssemblyModule({
29
+ wasmBinaryFile: "ThirdParty/wasm_splats_bg.wasm",
30
+ })
31
+ .then(function (result) {
32
+ if (result) {
33
+ GaussianSplatSorter._taskProcessorReady = true;
34
+ } else {
35
+ GaussianSplatSorter._error = new RuntimeError(
36
+ "Gaussian splat sorter could not be initialized.",
37
+ );
38
+ }
39
+ })
40
+ .catch((error) => {
41
+ GaussianSplatSorter._error = error;
42
+ });
43
+ GaussianSplatSorter._sorterTaskProcessor = processor;
44
+ }
45
+
46
+ return GaussianSplatSorter._sorterTaskProcessor;
47
+ };
48
+ /**
49
+ * Sorts Gaussian splats using a radix sort algorithm. Sorted by distance from the camera.
50
+ * A new list of indexes is returned, which can be used to render the splats in the correct order.
51
+ *
52
+ * @param {Object} parameters - The parameters for sorting Gaussian splat indexes.
53
+ * @param {Object} parameters.primitive - The primitive containing positions and modelView matrices.
54
+ * @returns {Promise|undefined} A promise that resolves to the sorted indexes or undefined if the task cannot be scheduled.
55
+ * @exception {RuntimeError} Sorter could not be initialized.
56
+ * @private
57
+ */
58
+ GaussianSplatSorter.radixSortIndexes = function (parameters) {
59
+ const sorterTaskProcessor = GaussianSplatSorter._getSorterTaskProcessor();
60
+ if (defined(GaussianSplatSorter._error)) {
61
+ throw GaussianSplatSorter._error;
62
+ }
63
+
64
+ if (!GaussianSplatSorter._taskProcessorReady) {
65
+ return;
66
+ }
67
+
68
+ return sorterTaskProcessor.scheduleTask(parameters, [
69
+ parameters.primitive.positions.buffer,
70
+ ]);
71
+ };
72
+
73
+ export default GaussianSplatSorter;
@@ -0,0 +1,64 @@
1
+ import defined from "../Core/defined.js";
2
+ import FeatureDetection from "../Core/FeatureDetection.js";
3
+ import RuntimeError from "../Core/RuntimeError.js";
4
+ import TaskProcessor from "../Core/TaskProcessor.js";
5
+
6
+ function GaussianSplatTextureGenerator() {}
7
+
8
+ GaussianSplatTextureGenerator._maxSortingConcurrency = Math.max(
9
+ FeatureDetection.hardwareConcurrency - 1,
10
+ 1,
11
+ );
12
+
13
+ GaussianSplatTextureGenerator._textureTaskProcessor = undefined;
14
+ GaussianSplatTextureGenerator._taskProcessorReady = false;
15
+ GaussianSplatTextureGenerator._error = undefined;
16
+ GaussianSplatTextureGenerator._getTextureTaskProcessor = function () {
17
+ if (!defined(GaussianSplatTextureGenerator._textureTaskProcessor)) {
18
+ const processor = new TaskProcessor(
19
+ "gaussianSplatTextureGenerator",
20
+ GaussianSplatTextureGenerator._maxSortingConcurrency,
21
+ );
22
+ processor
23
+ .initWebAssemblyModule({
24
+ wasmBinaryFile: "ThirdParty/wasm_splats_bg.wasm",
25
+ })
26
+ .then(function (result) {
27
+ if (result) {
28
+ GaussianSplatTextureGenerator._taskProcessorReady = true;
29
+ } else {
30
+ GaussianSplatTextureGenerator._error = new RuntimeError(
31
+ "Gaussian splat sorter could not be initialized.",
32
+ );
33
+ }
34
+ })
35
+ .catch((error) => {
36
+ GaussianSplatTextureGenerator._error = error;
37
+ });
38
+ GaussianSplatTextureGenerator._textureTaskProcessor = processor;
39
+ }
40
+
41
+ return GaussianSplatTextureGenerator._textureTaskProcessor;
42
+ };
43
+
44
+ GaussianSplatTextureGenerator.generateFromAttributes = function (parameters) {
45
+ const textureTaskProcessor =
46
+ GaussianSplatTextureGenerator._getTextureTaskProcessor();
47
+ if (defined(GaussianSplatTextureGenerator._error)) {
48
+ throw GaussianSplatTextureGenerator._error;
49
+ }
50
+
51
+ if (!GaussianSplatTextureGenerator._taskProcessorReady) {
52
+ return;
53
+ }
54
+
55
+ const { attributes } = parameters;
56
+ return textureTaskProcessor.scheduleTask(parameters, [
57
+ attributes.positions.buffer,
58
+ attributes.scales.buffer,
59
+ attributes.rotations.buffer,
60
+ attributes.colors.buffer,
61
+ ]);
62
+ };
63
+
64
+ export default GaussianSplatTextureGenerator;
@@ -507,8 +507,7 @@ function postProcessGeometry(loader, context) {
507
507
  for (let i = 0; i < loadPlans.length; i++) {
508
508
  const loadPlan = loadPlans[i];
509
509
  loadPlan.postProcess(context);
510
-
511
- if (loadPlan.needsOutlines) {
510
+ if (loadPlan.needsOutlines || loadPlan.needsGaussianSplats) {
512
511
  // The glTF loader takes ownership of any buffers generated in the
513
512
  // post-process stage since they were created after the geometry loaders
514
513
  // finished. This way they can be destroyed when the loader is destroyed.
@@ -687,6 +686,7 @@ function getVertexBufferLoader(
687
686
  semantic,
688
687
  primitive,
689
688
  draco,
689
+ spzExtension,
690
690
  loadBuffer,
691
691
  loadTypedArray,
692
692
  frameState,
@@ -703,6 +703,7 @@ function getVertexBufferLoader(
703
703
  bufferViewId: bufferViewId,
704
704
  primitive: primitive,
705
705
  draco: draco,
706
+ spz: spzExtension,
706
707
  attributeSemantic: semantic,
707
708
  accessorId: accessorId,
708
709
  asynchronous: loader._asynchronous,
@@ -1032,7 +1033,10 @@ function createAttribute(gltf, accessorId, name, semantic, setIndex) {
1032
1033
  attribute.semantic === VertexAttributeSemantic.POSITION ||
1033
1034
  attribute.semantic === VertexAttributeSemantic.NORMAL ||
1034
1035
  attribute.semantic === VertexAttributeSemantic.TANGENT ||
1035
- attribute.semantic === VertexAttributeSemantic.TEXCOORD;
1036
+ attribute.semantic === VertexAttributeSemantic.TEXCOORD ||
1037
+ attribute.semantic === VertexAttributeSemantic.FEATURE_ID ||
1038
+ attribute.semantic === VertexAttributeSemantic.SCALE ||
1039
+ attribute.semantic === VertexAttributeSemantic.ROTATION;
1036
1040
 
1037
1041
  // In the glTF 2.0 spec, min and max are not affected by the normalized flag.
1038
1042
  // However, for KHR_mesh_quantization, min and max must be dequantized for
@@ -1124,6 +1128,58 @@ function finalizeDracoAttribute(
1124
1128
  }
1125
1129
  }
1126
1130
 
1131
+ function finalizeSpzAttribute(
1132
+ attribute,
1133
+ vertexBufferLoader,
1134
+ loadBuffer,
1135
+ loadTypedArray,
1136
+ ) {
1137
+ attribute.byteOffset = 0;
1138
+ attribute.byteStride = undefined;
1139
+
1140
+ if (loadBuffer) {
1141
+ attribute.buffer = vertexBufferLoader.buffer;
1142
+ }
1143
+
1144
+ if (loadTypedArray && defined(vertexBufferLoader.typedArray)) {
1145
+ attribute.typedArray = ComponentDatatype.createArrayBufferView(
1146
+ attribute.componentDatatype,
1147
+ vertexBufferLoader.typedArray.buffer,
1148
+ );
1149
+ }
1150
+
1151
+ if (attribute.semantic === VertexAttributeSemantic.POSITION) {
1152
+ const findMinMaxXY = (flatArray) => {
1153
+ let minX = Infinity;
1154
+ let maxX = -Infinity;
1155
+ let minY = Infinity;
1156
+ let maxY = -Infinity;
1157
+ let minZ = Infinity;
1158
+ let maxZ = -Infinity;
1159
+
1160
+ for (let i = 0; i < flatArray.length; i += 3) {
1161
+ const x = flatArray[i];
1162
+ const y = flatArray[i + 1];
1163
+ const z = flatArray[i + 2];
1164
+
1165
+ minX = Math.min(minX, x);
1166
+ maxX = Math.max(maxX, x);
1167
+ minY = Math.min(minY, y);
1168
+ maxY = Math.max(maxY, y);
1169
+ minZ = Math.min(minZ, z);
1170
+ maxZ = Math.max(maxZ, z);
1171
+ }
1172
+
1173
+ return [
1174
+ new Cartesian3(minX, minY, minZ),
1175
+ new Cartesian3(maxX, maxY, maxZ),
1176
+ ];
1177
+ };
1178
+ const buffer = attribute.typedArray;
1179
+ [attribute.min, attribute.max] = findMinMaxXY(buffer);
1180
+ }
1181
+ }
1182
+
1127
1183
  function finalizeAttribute(
1128
1184
  gltf,
1129
1185
  accessor,
@@ -1160,6 +1216,7 @@ function loadAttribute(
1160
1216
  semanticInfo,
1161
1217
  primitive,
1162
1218
  draco,
1219
+ spz,
1163
1220
  loadBuffer,
1164
1221
  loadTypedArray,
1165
1222
  frameState,
@@ -1185,7 +1242,7 @@ function loadAttribute(
1185
1242
  setIndex,
1186
1243
  );
1187
1244
 
1188
- if (!defined(draco) && !defined(bufferViewId)) {
1245
+ if (!defined(draco) && !defined(bufferViewId) && !defined(spz)) {
1189
1246
  return attribute;
1190
1247
  }
1191
1248
 
@@ -1195,6 +1252,7 @@ function loadAttribute(
1195
1252
  gltfSemantic,
1196
1253
  primitive,
1197
1254
  draco,
1255
+ spz,
1198
1256
  loadBuffer,
1199
1257
  loadTypedArray,
1200
1258
  frameState,
@@ -1204,6 +1262,7 @@ function loadAttribute(
1204
1262
  loader._geometryLoaders.push(vertexBufferLoader);
1205
1263
  const promise = vertexBufferLoader.load();
1206
1264
  loader._loaderPromises.push(promise);
1265
+
1207
1266
  // This can only execute once vertexBufferLoader.process() has run and returns true
1208
1267
  // Save this finish callback by the loader index so it can be called
1209
1268
  // in process().
@@ -1219,6 +1278,13 @@ function loadAttribute(
1219
1278
  loadBuffer,
1220
1279
  loadTypedArray,
1221
1280
  );
1281
+ } else if (defined(spz)) {
1282
+ finalizeSpzAttribute(
1283
+ attribute,
1284
+ vertexBufferLoader,
1285
+ loadBuffer,
1286
+ loadTypedArray,
1287
+ );
1222
1288
  } else {
1223
1289
  finalizeAttribute(
1224
1290
  gltf,
@@ -1240,6 +1306,7 @@ function loadVertexAttribute(
1240
1306
  semanticInfo,
1241
1307
  primitive,
1242
1308
  draco,
1309
+ spz,
1243
1310
  hasInstances,
1244
1311
  needsPostProcessing,
1245
1312
  frameState,
@@ -1287,6 +1354,7 @@ function loadVertexAttribute(
1287
1354
  semanticInfo,
1288
1355
  primitive,
1289
1356
  draco,
1357
+ spz,
1290
1358
  loadBuffer,
1291
1359
  loadTypedArray,
1292
1360
  frameState,
@@ -1360,6 +1428,7 @@ function loadInstancedAttribute(
1360
1428
  semanticInfo,
1361
1429
  undefined,
1362
1430
  undefined,
1431
+ undefined,
1363
1432
  loadBuffer,
1364
1433
  loadTypedArray,
1365
1434
  frameState,
@@ -1876,6 +1945,7 @@ function loadMorphTarget(
1876
1945
  // Don't pass in primitive or draco object since morph targets can't be draco compressed
1877
1946
  const primitive = undefined;
1878
1947
  const draco = undefined;
1948
+ const spz = undefined;
1879
1949
  const hasInstances = false;
1880
1950
 
1881
1951
  for (const semantic in target) {
@@ -1896,6 +1966,7 @@ function loadMorphTarget(
1896
1966
  semanticInfo,
1897
1967
  primitive,
1898
1968
  draco,
1969
+ spz,
1899
1970
  hasInstances,
1900
1971
  needsPostProcessing,
1901
1972
  frameState,
@@ -1947,6 +2018,12 @@ function loadPrimitive(loader, gltfPrimitive, hasInstances, frameState) {
1947
2018
  );
1948
2019
  }
1949
2020
 
2021
+ const spzExtension = extensions.KHR_spz_gaussian_splats_compression;
2022
+ if (defined(spzExtension)) {
2023
+ needsPostProcessing = true;
2024
+ primitivePlan.needsGaussianSplats = true;
2025
+ }
2026
+
1950
2027
  const loadForClassification = loader._loadForClassification;
1951
2028
  const draco = extensions.KHR_draco_mesh_compression;
1952
2029
 
@@ -1979,6 +2056,7 @@ function loadPrimitive(loader, gltfPrimitive, hasInstances, frameState) {
1979
2056
  semanticInfo,
1980
2057
  gltfPrimitive,
1981
2058
  draco,
2059
+ spzExtension,
1982
2060
  hasInstances,
1983
2061
  needsPostProcessing,
1984
2062
  frameState,
@@ -0,0 +1,222 @@
1
+ import Check from "../Core/Check.js";
2
+ import Frozen from "../Core/Frozen.js";
3
+ import defined from "../Core/defined.js";
4
+ import ResourceLoader from "./ResourceLoader.js";
5
+ import ResourceLoaderState from "./ResourceLoaderState.js";
6
+ import { loadSpz } from "@spz-loader/core";
7
+
8
+ /**
9
+ * Load a SPZ buffer from a glTF.
10
+ * <p>
11
+ * Implements the {@link ResourceLoader} interface.
12
+ * </p>
13
+ * @alias GltfSpzLoader
14
+ * @constructor
15
+ * @augments ResourceLoader
16
+ * @param {object} options Object with the following properties:
17
+ * @param {ResourceCache} options.resourceCache The {@link ResourceCache} (to avoid circular dependencies).
18
+ * @param {object} options.gltf The glTF JSON.
19
+ * @param {object} options.primitive The primitive containing the SPZ extension.
20
+ * @param {object} options.spz The SPZ extension object.
21
+ * @param {Resource} options.gltfResource The {@link Resource} containing the glTF.
22
+ * @param {Resource} options.baseResource The {@link Resource} that paths in the glTF JSON are relative to.
23
+ * @param {string} [options.cacheKey] The cache key of the resource.
24
+ *
25
+ * @private
26
+ */
27
+ function GltfSpzLoader(options) {
28
+ options = options ?? Frozen.EMPTY_OBJECT;
29
+ const resourceCache = options.resourceCache;
30
+ const gltf = options.gltf;
31
+ const primitive = options.primitive;
32
+ const spz = options.spz;
33
+ const gltfResource = options.gltfResource;
34
+ const baseResource = options.baseResource;
35
+ const cacheKey = options.cacheKey;
36
+
37
+ //>>includeStart('debug', pragmas.debug);
38
+ Check.typeOf.func("options.resourceCache", resourceCache);
39
+ Check.typeOf.object("options.gltf", gltf);
40
+ Check.typeOf.object("options.primitive", primitive);
41
+ Check.typeOf.object("options.spz", spz);
42
+ Check.typeOf.object("options.gltfResource", gltfResource);
43
+ Check.typeOf.object("options.baseResource", baseResource);
44
+ //>>includeEnd('debug');
45
+
46
+ this._resourceCache = resourceCache;
47
+ this._gltfResource = gltfResource;
48
+ this._baseResource = baseResource;
49
+ this._gltf = gltf;
50
+ this._primitive = primitive;
51
+ this._spz = spz;
52
+ this._cacheKey = cacheKey;
53
+ this._bufferViewLoader = undefined;
54
+ this._bufferViewTypedArray = undefined;
55
+ this._decodePromise = undefined;
56
+ this._decodedData = undefined;
57
+ this._state = ResourceLoaderState.UNLOADED;
58
+ this._promise = undefined;
59
+ this._spzError = undefined;
60
+ }
61
+
62
+ if (defined(Object.create)) {
63
+ GltfSpzLoader.prototype = Object.create(ResourceLoader.prototype);
64
+ GltfSpzLoader.prototype.constructor = GltfSpzLoader;
65
+ }
66
+
67
+ Object.defineProperties(GltfSpzLoader.prototype, {
68
+ /**
69
+ * The cache key of the resource.
70
+ * @memberof GltfSpzLoader.prototype
71
+ * @type {string}
72
+ * @readonly
73
+ * @private
74
+ */
75
+ cacheKey: {
76
+ get: function () {
77
+ return this._cacheKey;
78
+ },
79
+ },
80
+ /**
81
+ * The decoded SPZ data.
82
+ * @memberof GltfSpzLoader.prototype
83
+ * @type {object}
84
+ * @readonly
85
+ * @private
86
+ */
87
+ decodedData: {
88
+ get: function () {
89
+ return this._decodedData;
90
+ },
91
+ },
92
+ });
93
+
94
+ async function loadResources(loader) {
95
+ const resourceCache = loader._resourceCache;
96
+ try {
97
+ const bufferViewLoader = resourceCache.getBufferViewLoader({
98
+ gltf: loader._gltf,
99
+ bufferViewId: 0,
100
+ gltfResource: loader._gltfResource,
101
+ baseResource: loader._baseResource,
102
+ });
103
+ loader._bufferViewLoader = bufferViewLoader;
104
+ await bufferViewLoader.load();
105
+
106
+ if (loader.isDestroyed()) {
107
+ return;
108
+ }
109
+
110
+ loader._bufferViewTypedArray = bufferViewLoader.typedArray;
111
+ loader._state = ResourceLoaderState.PROCESSING;
112
+ return loader;
113
+ } catch (error) {
114
+ if (loader.isDestroyed()) {
115
+ return;
116
+ }
117
+
118
+ handleError(loader, error);
119
+ }
120
+ }
121
+
122
+ /**
123
+ * Loads the SPZ resource.
124
+ * @returns {Promise<Resource>} A promise that resolves to the resource when the SPZ is loaded.
125
+ * @private
126
+ */
127
+ GltfSpzLoader.prototype.load = async function () {
128
+ if (defined(this._promise)) {
129
+ return this._promise;
130
+ }
131
+
132
+ this._state = ResourceLoaderState.LOADING;
133
+ this._promise = loadResources(this);
134
+ return this._promise;
135
+ };
136
+
137
+ function handleError(spzLoader, error) {
138
+ spzLoader.unload();
139
+ spzLoader._state = ResourceLoaderState.FAILED;
140
+ const errorMessage = "Failed to load SPZ";
141
+ throw spzLoader.getError(errorMessage, error);
142
+ }
143
+
144
+ async function processDecode(loader, decodePromise) {
145
+ try {
146
+ const gcloud = await decodePromise;
147
+ if (loader.isDestroyed()) {
148
+ return;
149
+ }
150
+
151
+ loader.unload();
152
+
153
+ loader._decodedData = {
154
+ gcloud: gcloud,
155
+ };
156
+ loader._state = ResourceLoaderState.READY;
157
+ return loader._baseResource;
158
+ } catch (error) {
159
+ if (loader.isDestroyed()) {
160
+ return;
161
+ }
162
+
163
+ loader._spzError = error;
164
+ }
165
+ }
166
+
167
+ /**
168
+ * Processes the SPZ resource.
169
+ * @param {FrameState} frameState The frame state.
170
+ * @private
171
+ */
172
+ GltfSpzLoader.prototype.process = function (frameState) {
173
+ //>>includeStart('debug', pragmas.debug);
174
+ Check.typeOf.object("frameState", frameState);
175
+ //>>includeEnd('debug');
176
+
177
+ if (this._state === ResourceLoaderState.READY) {
178
+ return true;
179
+ }
180
+
181
+ if (this._state !== ResourceLoaderState.PROCESSING) {
182
+ return false;
183
+ }
184
+
185
+ if (defined(this._spzError)) {
186
+ handleError(this, this._spzError);
187
+ }
188
+
189
+ if (!defined(this._bufferViewTypedArray)) {
190
+ return false;
191
+ }
192
+
193
+ if (defined(this._decodePromise)) {
194
+ return false;
195
+ }
196
+
197
+ const decodePromise = loadSpz(this._bufferViewTypedArray);
198
+
199
+ if (!defined(decodePromise)) {
200
+ return false;
201
+ }
202
+
203
+ this._decodePromise = processDecode(this, decodePromise);
204
+ };
205
+
206
+ /**
207
+ * Unloads the SPZ resource and frees associated resources.
208
+ * @private
209
+ */
210
+ GltfSpzLoader.prototype.unload = function () {
211
+ if (defined(this._bufferViewLoader)) {
212
+ this._resourceCache.unload(this._bufferViewLoader);
213
+ }
214
+
215
+ this._bufferViewLoader = undefined;
216
+ this._bufferViewTypedArray = undefined;
217
+ this._decodedData = undefined;
218
+ this._gltf = undefined;
219
+ this._primitive = undefined;
220
+ };
221
+
222
+ export default GltfSpzLoader;