@cesium/engine 19.0.0 → 20.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. package/Build/ThirdParty/Workers/pako_deflate.min.js +3 -3
  2. package/Build/ThirdParty/Workers/pako_inflate.min.js +3 -3
  3. package/Build/ThirdParty/Workers/z-worker-pako.js +49 -42
  4. package/Build/Workers/{chunk-ECWQXDZY.js → chunk-2K5PKWLP.js} +16 -16
  5. package/Build/Workers/{chunk-T7C73J6H.js → chunk-2MEON5V4.js} +4 -4
  6. package/Build/Workers/{chunk-AZPKFL5X.js → chunk-4MCKK5XE.js} +5 -5
  7. package/Build/Workers/{chunk-Q2QXUN33.js → chunk-4Z7AGRTU.js} +2 -2
  8. package/Build/Workers/{chunk-SOYVF5RC.js → chunk-7FEVXX5D.js} +2 -2
  9. package/Build/Workers/{chunk-RIQM3XY5.js → chunk-7MCEUVPM.js} +4 -4
  10. package/Build/Workers/{chunk-25USKS4R.js → chunk-7P7R7ERW.js} +6 -6
  11. package/Build/Workers/{chunk-MUL374P3.js → chunk-CTU7LCVZ.js} +4 -4
  12. package/Build/Workers/{chunk-DPFAUGBE.js → chunk-CZGSJ6ZG.js} +2 -2
  13. package/Build/Workers/{chunk-ESDVZ4QL.js → chunk-D4VFVSGU.js} +10 -10
  14. package/Build/Workers/{chunk-JZVUMRYA.js → chunk-DAGWF5MM.js} +13 -13
  15. package/Build/Workers/{chunk-VCCR35R6.js → chunk-DAZVD3AH.js} +11 -11
  16. package/Build/Workers/{chunk-GVO3YIU2.js → chunk-DJCPJJSP.js} +4 -4
  17. package/Build/Workers/{chunk-DXYAD4ED.js → chunk-DNMSVJ4S.js} +1 -1
  18. package/Build/Workers/{chunk-Y3PM6G2V.js → chunk-E2533KCN.js} +3 -3
  19. package/Build/Workers/{chunk-RZJA77TX.js → chunk-ECGKCTPM.js} +6 -6
  20. package/Build/Workers/{chunk-PAH73ETP.js → chunk-HKHD5FDM.js} +5 -5
  21. package/Build/Workers/{chunk-6T2PQKYP.js → chunk-HSVZWLJD.js} +4 -4
  22. package/Build/Workers/{chunk-IE2BEHLE.js → chunk-HZ22ZI3Q.js} +12 -12
  23. package/Build/Workers/{chunk-SO2Z6H6F.js → chunk-IQKHPQNT.js} +2 -2
  24. package/Build/Workers/{chunk-SVGHDIZG.js → chunk-JHTZDMN6.js} +5 -5
  25. package/Build/Workers/{chunk-ETCPCGKC.js → chunk-JIXKGUWR.js} +2 -2
  26. package/Build/Workers/{chunk-DNCRKMCI.js → chunk-JVNWWKXF.js} +6 -6
  27. package/Build/Workers/{chunk-AABNX23Q.js → chunk-L7PWWHKM.js} +5 -5
  28. package/Build/Workers/{chunk-SXMHGVZ7.js → chunk-LF74EILW.js} +12 -12
  29. package/Build/Workers/{chunk-23FRF5ZP.js → chunk-LHZKPI55.js} +9 -9
  30. package/Build/Workers/{chunk-E6NMEKSS.js → chunk-LSYTMSIQ.js} +5 -4
  31. package/Build/Workers/{chunk-GO3IRH6U.js → chunk-LYKXQPGW.js} +6 -6
  32. package/Build/Workers/{chunk-MBDKO456.js → chunk-LZZA3PAR.js} +5 -5
  33. package/Build/Workers/{chunk-34DFERFC.js → chunk-M4FSVD3C.js} +12 -12
  34. package/Build/Workers/{chunk-NMAT4IJ6.js → chunk-O4DA3KRB.js} +7 -7
  35. package/Build/Workers/{chunk-HHHBRTSW.js → chunk-O7KDJVRH.js} +9 -9
  36. package/Build/Workers/{chunk-XUYCCEG6.js → chunk-OWV4L2GH.js} +5 -5
  37. package/Build/Workers/{chunk-ZNEIUXBK.js → chunk-OYFINQQA.js} +7 -7
  38. package/Build/Workers/{chunk-4QWLEG4L.js → chunk-PFUF2QIK.js} +14 -14
  39. package/Build/Workers/{chunk-37IYBZDZ.js → chunk-QFMJIXCL.js} +9 -9
  40. package/Build/Workers/{chunk-5VPO47LB.js → chunk-QWHUQ4B7.js} +8 -8
  41. package/Build/Workers/{chunk-KTDHOEXR.js → chunk-RB3XS7EZ.js} +1 -1
  42. package/Build/Workers/{chunk-HJ6KFRM7.js → chunk-RP4KKY2E.js} +16 -16
  43. package/Build/Workers/{chunk-Y6LLFNXN.js → chunk-SLPWFCXZ.js} +10 -10
  44. package/Build/Workers/{chunk-WUMTX3FI.js → chunk-UUXKGCBU.js} +8 -8
  45. package/Build/Workers/{chunk-EV4PBU7O.js → chunk-UXIZVXIR.js} +1 -1
  46. package/Build/Workers/{chunk-YPNIIVIF.js → chunk-V65LOTF3.js} +6 -6
  47. package/Build/Workers/{chunk-K5VGMGFM.js → chunk-VQLQAENU.js} +7 -7
  48. package/Build/Workers/{chunk-W32QSECR.js → chunk-WJ5THCIZ.js} +6 -6
  49. package/Build/Workers/{chunk-4NRFVAG2.js → chunk-WNEY4A5P.js} +5 -5
  50. package/Build/Workers/{chunk-UPU755HO.js → chunk-XMIVNU5H.js} +12 -12
  51. package/Build/Workers/{chunk-5YCDPN3O.js → chunk-YNRRVRHO.js} +1 -1
  52. package/Build/Workers/{chunk-NKM2EV46.js → chunk-YVAOKOKX.js} +1 -1
  53. package/Build/Workers/{chunk-FQNSMOZT.js → chunk-YW2UXIBU.js} +4 -4
  54. package/Build/Workers/{chunk-DAHXCIOX.js → chunk-ZBLPNAYB.js} +8 -8
  55. package/Build/Workers/{chunk-C36VNKTH.js → chunk-ZJGO7T2S.js} +4 -4
  56. package/Build/Workers/combineGeometry.js +21 -21
  57. package/Build/Workers/createBoxGeometry.js +15 -15
  58. package/Build/Workers/createBoxOutlineGeometry.js +13 -13
  59. package/Build/Workers/createCircleGeometry.js +23 -23
  60. package/Build/Workers/createCircleOutlineGeometry.js +16 -16
  61. package/Build/Workers/createCoplanarPolygonGeometry.js +30 -30
  62. package/Build/Workers/createCoplanarPolygonOutlineGeometry.js +28 -28
  63. package/Build/Workers/createCorridorGeometry.js +26 -26
  64. package/Build/Workers/createCorridorOutlineGeometry.js +25 -25
  65. package/Build/Workers/createCylinderGeometry.js +17 -17
  66. package/Build/Workers/createCylinderOutlineGeometry.js +15 -15
  67. package/Build/Workers/createEllipseGeometry.js +23 -23
  68. package/Build/Workers/createEllipseOutlineGeometry.js +16 -16
  69. package/Build/Workers/createEllipsoidGeometry.js +16 -16
  70. package/Build/Workers/createEllipsoidOutlineGeometry.js +15 -15
  71. package/Build/Workers/createFrustumGeometry.js +15 -15
  72. package/Build/Workers/createFrustumOutlineGeometry.js +15 -15
  73. package/Build/Workers/createGeometry.js +21 -21
  74. package/Build/Workers/createGroundPolylineGeometry.js +19 -19
  75. package/Build/Workers/createPlaneGeometry.js +13 -13
  76. package/Build/Workers/createPlaneOutlineGeometry.js +12 -12
  77. package/Build/Workers/createPolygonGeometry.js +29 -29
  78. package/Build/Workers/createPolygonOutlineGeometry.js +27 -27
  79. package/Build/Workers/createPolylineGeometry.js +22 -22
  80. package/Build/Workers/createPolylineVolumeGeometry.js +28 -28
  81. package/Build/Workers/createPolylineVolumeOutlineGeometry.js +24 -24
  82. package/Build/Workers/createRectangleGeometry.js +24 -24
  83. package/Build/Workers/createRectangleOutlineGeometry.js +17 -17
  84. package/Build/Workers/createSimplePolylineGeometry.js +20 -20
  85. package/Build/Workers/createSphereGeometry.js +16 -16
  86. package/Build/Workers/createSphereOutlineGeometry.js +15 -15
  87. package/Build/Workers/createTaskProcessorWorker.js +3 -3
  88. package/Build/Workers/createVectorTileClampedPolylines.js +12 -12
  89. package/Build/Workers/createVectorTileGeometries.js +21 -21
  90. package/Build/Workers/createVectorTilePoints.js +11 -11
  91. package/Build/Workers/createVectorTilePolygons.js +19 -19
  92. package/Build/Workers/createVectorTilePolylines.js +12 -12
  93. package/Build/Workers/createVerticesFromGoogleEarthEnterpriseBuffer.js +19 -19
  94. package/Build/Workers/createVerticesFromHeightmap.js +25 -25
  95. package/Build/Workers/createVerticesFromQuantizedTerrainMesh.js +16 -16
  96. package/Build/Workers/createWallGeometry.js +21 -21
  97. package/Build/Workers/createWallOutlineGeometry.js +20 -20
  98. package/Build/Workers/decodeDraco.js +10 -10
  99. package/Build/Workers/decodeGoogleEarthEnterprisePacket.js +5 -5
  100. package/Build/Workers/decodeI3S.js +9 -9
  101. package/Build/Workers/gaussianSplatSorter.js +4 -4
  102. package/Build/Workers/gaussianSplatTextureGenerator.js +4 -4
  103. package/Build/Workers/transcodeKTX2.js +17 -16
  104. package/Build/Workers/transferTypedArrayTest.js +1 -1
  105. package/Build/Workers/upsampleQuantizedTerrainMesh.js +19 -19
  106. package/Source/Core/Ellipsoid.js +9 -0
  107. package/Source/Core/Ion.js +1 -1
  108. package/Source/Core/IonResource.js +14 -8
  109. package/Source/Scene/ArcGisMapService.js +1 -1
  110. package/Source/Scene/BingMapsImageryProvider.js +1 -1
  111. package/Source/Scene/Cesium3DTileContentFactory.js +7 -16
  112. package/Source/Scene/Cesium3DTileset.js +1 -1
  113. package/Source/Scene/GaussianSplat3DTileContent.js +253 -9
  114. package/Source/Scene/GaussianSplatPrimitive.js +167 -15
  115. package/Source/Scene/GltfLoader.js +20 -2
  116. package/Source/Scene/GltfVertexBufferLoader.js +56 -2
  117. package/Source/Scene/ITwinData.js +37 -76
  118. package/Source/Scene/Model/Model.js +3 -0
  119. package/Source/Scene/Model/ModelClippingPolygonsPipelineStage.js +8 -2
  120. package/Source/Scene/Model/ModelUtility.js +1 -0
  121. package/Source/Scene/Model/PntsLoader.js +7 -3
  122. package/Source/Scene/PntsParser.js +6 -3
  123. package/Source/Scene/PrimitiveLoadPlan.js +1 -1
  124. package/Source/Scene/VertexAttributeSemantic.js +4 -2
  125. package/Source/Scene/WebMapServiceImageryProvider.js +3 -2
  126. package/Source/Scene/WebMapTileServiceImageryProvider.js +0 -22
  127. package/Source/Scene/getMeshPrimitives.js +72 -0
  128. package/Source/Shaders/PrimitiveGaussianSplatFS.glsl +5 -5
  129. package/Source/Shaders/PrimitiveGaussianSplatFS.js +5 -5
  130. package/Source/Shaders/PrimitiveGaussianSplatVS.glsl +102 -5
  131. package/Source/Shaders/PrimitiveGaussianSplatVS.js +102 -5
  132. package/Source/ThirdParty/Workers/z-worker-pako.js +1 -1
  133. package/index.d.ts +109 -1
  134. package/index.js +245 -244
  135. package/package.json +3 -3
@@ -31,10 +31,12 @@ import Cartesian3 from "../Core/Cartesian3.js";
31
31
  import Quaternion from "../Core/Quaternion.js";
32
32
  import SplitDirection from "./SplitDirection.js";
33
33
  import destroyObject from "../Core/destroyObject.js";
34
+ import ContextLimits from "../Renderer/ContextLimits.js";
34
35
 
35
36
  const scratchMatrix4A = new Matrix4();
36
37
  const scratchMatrix4B = new Matrix4();
37
38
  const scratchMatrix4C = new Matrix4();
39
+ const scratchMatrix4D = new Matrix4();
38
40
 
39
41
  const GaussianSplatSortingState = {
40
42
  IDLE: 0,
@@ -44,6 +46,25 @@ const GaussianSplatSortingState = {
44
46
  ERROR: 4,
45
47
  };
46
48
 
49
+ function createSphericalHarmonicsTexture(context, shData) {
50
+ const texture = new Texture({
51
+ context: context,
52
+ source: {
53
+ width: shData.width,
54
+ height: shData.height,
55
+ arrayBufferView: shData.data,
56
+ },
57
+ preMultiplyAlpha: false,
58
+ skipColorSpaceConversion: true,
59
+ pixelFormat: PixelFormat.RG_INTEGER,
60
+ pixelDatatype: PixelDatatype.UNSIGNED_INT,
61
+ flipY: false,
62
+ sampler: Sampler.NEAREST,
63
+ });
64
+
65
+ return texture;
66
+ }
67
+
47
68
  function createGaussianSplatTexture(context, splatTextureData) {
48
69
  return new Texture({
49
70
  context: context,
@@ -64,7 +85,7 @@ function createGaussianSplatTexture(context, splatTextureData) {
64
85
  /** A primitive that renders Gaussian splats.
65
86
  * <p>
66
87
  * This primitive is used to render Gaussian splats in a 3D Tileset.
67
- * It is designed to work with the KHR_spz_gaussian_splats_compression extension.
88
+ * It is designed to work with the KHR_gaussian_splatting and KHR_gaussian_splatting_compression_spz_2 extensions.
68
89
  * </p>
69
90
  * @alias GaussianSplatPrimitive
70
91
  * @constructor
@@ -148,6 +169,14 @@ function GaussianSplatPrimitive(options) {
148
169
  * @see {@link GaussianSplatTextureGenerator}
149
170
  */
150
171
  this.gaussianSplatTexture = undefined;
172
+
173
+ /**
174
+ * The texture used to store the spherical harmonics coefficients for the Gaussian splats.
175
+ * @type {undefined|Texture}
176
+ * @private
177
+ */
178
+ this.sphericalHarmonicsTexture = undefined;
179
+
151
180
  /**
152
181
  * The last width of the Gaussian splat texture.
153
182
  * This is used to track changes in the texture size and update the primitive accordingly.
@@ -395,7 +424,7 @@ GaussianSplatPrimitive.prototype.onTileVisible = function (tile) {};
395
424
  */
396
425
  GaussianSplatPrimitive.transformTile = function (tile) {
397
426
  const computedTransform = tile.computedTransform;
398
- const splatPrimitive = tile.content.splatPrimitive;
427
+ const gltfPrimitive = tile.content.gltfPrimitive;
399
428
  const gaussianSplatPrimitive = tile.tileset.gaussianSplatPrimitive;
400
429
 
401
430
  const computedModelMatrix = Matrix4.multiplyTransformation(
@@ -425,17 +454,17 @@ GaussianSplatPrimitive.transformTile = function (tile) {
425
454
  const rotations = tile.content._originalRotations;
426
455
  const scales = tile.content._originalScales;
427
456
  const attributePositions = ModelUtility.getAttributeBySemantic(
428
- splatPrimitive,
457
+ gltfPrimitive,
429
458
  VertexAttributeSemantic.POSITION,
430
459
  ).typedArray;
431
460
 
432
461
  const attributeRotations = ModelUtility.getAttributeBySemantic(
433
- splatPrimitive,
462
+ gltfPrimitive,
434
463
  VertexAttributeSemantic.ROTATION,
435
464
  ).typedArray;
436
465
 
437
466
  const attributeScales = ModelUtility.getAttributeBySemantic(
438
- splatPrimitive,
467
+ gltfPrimitive,
439
468
  VertexAttributeSemantic.SCALE,
440
469
  ).typedArray;
441
470
 
@@ -601,12 +630,69 @@ GaussianSplatPrimitive.buildGSplatDrawCommand = function (
601
630
  ShaderDestination.VERTEX,
602
631
  );
603
632
 
633
+ shaderBuilder.addUniform(
634
+ "float",
635
+ "u_sphericalHarmonicsDegree",
636
+ ShaderDestination.VERTEX,
637
+ );
638
+
639
+ shaderBuilder.addUniform("float", "u_splatScale", ShaderDestination.VERTEX);
640
+
641
+ shaderBuilder.addUniform(
642
+ "vec3",
643
+ "u_cameraPositionWC",
644
+ ShaderDestination.VERTEX,
645
+ );
646
+
647
+ shaderBuilder.addUniform(
648
+ "mat3",
649
+ "u_inverseModelRotation",
650
+ ShaderDestination.VERTEX,
651
+ );
652
+
604
653
  const uniformMap = renderResources.uniformMap;
605
654
 
606
655
  uniformMap.u_splatAttributeTexture = function () {
607
656
  return primitive.gaussianSplatTexture;
608
657
  };
609
658
 
659
+ if (primitive._sphericalHarmonicsDegree > 0) {
660
+ shaderBuilder.addDefine(
661
+ "HAS_SPHERICAL_HARMONICS",
662
+ "1",
663
+ ShaderDestination.VERTEX,
664
+ );
665
+ shaderBuilder.addUniform(
666
+ "highp usampler2D",
667
+ "u_sphericalHarmonicsTexture",
668
+ ShaderDestination.VERTEX,
669
+ );
670
+ uniformMap.u_sphericalHarmonicsTexture = function () {
671
+ return primitive.sphericalHarmonicsTexture;
672
+ };
673
+ }
674
+ uniformMap.u_sphericalHarmonicsDegree = function () {
675
+ return primitive._sphericalHarmonicsDegree;
676
+ };
677
+
678
+ uniformMap.u_cameraPositionWC = function () {
679
+ return Cartesian3.clone(frameState.camera.positionWC);
680
+ };
681
+
682
+ uniformMap.u_inverseModelRotation = function () {
683
+ const tileset = primitive._tileset;
684
+ const modelMatrix = Matrix4.multiply(
685
+ tileset.modelMatrix,
686
+ Matrix4.fromArray(tileset.root.transform),
687
+ scratchMatrix4A,
688
+ );
689
+ const inverseModelRotation = Matrix4.getRotation(
690
+ Matrix4.inverse(modelMatrix, scratchMatrix4C),
691
+ scratchMatrix4D,
692
+ );
693
+ return inverseModelRotation;
694
+ };
695
+
610
696
  uniformMap.u_splitDirection = function () {
611
697
  return primitive.splitDirection;
612
698
  };
@@ -720,7 +806,11 @@ GaussianSplatPrimitive.prototype.update = function (frameState) {
720
806
  this._rootTransform = tileset.root.computedTransform;
721
807
  }
722
808
 
723
- if (this._drawCommand && tileset.show) {
809
+ if (!tileset.show || tileset._selectedTiles.length === 0) {
810
+ return;
811
+ }
812
+
813
+ if (this._drawCommand) {
724
814
  frameState.commandList.push(this._drawCommand);
725
815
  }
726
816
 
@@ -756,6 +846,7 @@ GaussianSplatPrimitive.prototype.update = function (frameState) {
756
846
  this._scales = undefined;
757
847
  this._colors = undefined;
758
848
  this._indexes = undefined;
849
+ this._shData = undefined;
759
850
  this._needsGaussianSplatTexture = true;
760
851
  this._gaussianSplatTexturePending = false;
761
852
 
@@ -771,7 +862,7 @@ GaussianSplatPrimitive.prototype.update = function (frameState) {
771
862
  let aggregate;
772
863
  let offset = 0;
773
864
  for (const tile of tiles) {
774
- const primitive = tile.content.splatPrimitive;
865
+ const primitive = tile.content.gltfPrimitive;
775
866
  const attribute = getAttributeCallback(primitive);
776
867
  if (!defined(aggregate)) {
777
868
  aggregate = ComponentDatatype.createTypedArray(
@@ -786,42 +877,71 @@ GaussianSplatPrimitive.prototype.update = function (frameState) {
786
877
  return aggregate;
787
878
  };
788
879
 
880
+ const aggregateShData = () => {
881
+ let offset = 0;
882
+ for (const tile of tiles) {
883
+ const shData = tile.content.packedSphericalHarmonicsData;
884
+ if (tile.content.sphericalHarmonicsDegree > 0) {
885
+ if (!defined(this._shData)) {
886
+ let coefs;
887
+ switch (tile.content.sphericalHarmonicsDegree) {
888
+ case 1:
889
+ coefs = 9;
890
+ break;
891
+ case 2:
892
+ coefs = 24;
893
+ break;
894
+ case 3:
895
+ coefs = 45;
896
+ }
897
+ this._shData = new Uint32Array(totalElements * (coefs * (2 / 3)));
898
+ }
899
+ this._shData.set(shData, offset);
900
+ offset += shData.length;
901
+ }
902
+ }
903
+ };
904
+
789
905
  this._positions = aggregateAttributeValues(
790
906
  ComponentDatatype.FLOAT,
791
- (splatPrimitive) =>
907
+ (gltfPrimitive) =>
792
908
  ModelUtility.getAttributeBySemantic(
793
- splatPrimitive,
909
+ gltfPrimitive,
794
910
  VertexAttributeSemantic.POSITION,
795
911
  ),
796
912
  );
797
913
 
798
914
  this._scales = aggregateAttributeValues(
799
915
  ComponentDatatype.FLOAT,
800
- (splatPrimitive) =>
916
+ (gltfPrimitive) =>
801
917
  ModelUtility.getAttributeBySemantic(
802
- splatPrimitive,
918
+ gltfPrimitive,
803
919
  VertexAttributeSemantic.SCALE,
804
920
  ),
805
921
  );
806
922
 
807
923
  this._rotations = aggregateAttributeValues(
808
924
  ComponentDatatype.FLOAT,
809
- (splatPrimitive) =>
925
+ (gltfPrimitive) =>
810
926
  ModelUtility.getAttributeBySemantic(
811
- splatPrimitive,
927
+ gltfPrimitive,
812
928
  VertexAttributeSemantic.ROTATION,
813
929
  ),
814
930
  );
815
931
 
816
932
  this._colors = aggregateAttributeValues(
817
933
  ComponentDatatype.UNSIGNED_BYTE,
818
- (splatPrimitive) =>
934
+ (gltfPrimitive) =>
819
935
  ModelUtility.getAttributeBySemantic(
820
- splatPrimitive,
936
+ gltfPrimitive,
821
937
  VertexAttributeSemantic.COLOR,
822
938
  ),
823
939
  );
824
940
 
941
+ aggregateShData();
942
+ this._sphericalHarmonicsDegree =
943
+ tiles[0].content.sphericalHarmonicsDegree;
944
+
825
945
  this._numSplats = totalElements;
826
946
  this.selectedTileLength = tileset._selectedTiles.length;
827
947
  }
@@ -833,6 +953,38 @@ GaussianSplatPrimitive.prototype.update = function (frameState) {
833
953
  if (this._needsGaussianSplatTexture) {
834
954
  if (!this._gaussianSplatTexturePending) {
835
955
  GaussianSplatPrimitive.generateSplatTexture(this, frameState);
956
+ if (defined(this._shData)) {
957
+ const oldTex = this.sphericalHarmonicsTexture;
958
+ const width = ContextLimits.maximumTextureSize;
959
+ const dims =
960
+ tileset._selectedTiles[0].content
961
+ .sphericalHarmonicsCoefficientCount / 3;
962
+ const splatsPerRow = Math.floor(width / dims);
963
+ const floatsPerRow = splatsPerRow * (dims * 2);
964
+ const texBuf = new Uint32Array(
965
+ width * Math.ceil(this._numSplats / splatsPerRow) * 2,
966
+ );
967
+
968
+ let dataIndex = 0;
969
+ for (let i = 0; dataIndex < this._shData.length; i += width * 2) {
970
+ texBuf.set(
971
+ this._shData.subarray(dataIndex, dataIndex + floatsPerRow),
972
+ i,
973
+ );
974
+ dataIndex += floatsPerRow;
975
+ }
976
+ this.sphericalHarmonicsTexture = createSphericalHarmonicsTexture(
977
+ frameState.context,
978
+ {
979
+ data: texBuf,
980
+ width: width,
981
+ height: Math.ceil(this._numSplats / splatsPerRow),
982
+ },
983
+ );
984
+ if (defined(oldTex)) {
985
+ oldTex.destroy();
986
+ }
987
+ }
836
988
  }
837
989
  return;
838
990
  }
@@ -33,6 +33,7 @@ import GltfGpmLoader from "./Model/Extensions/Gpm/GltfGpmLoader.js";
33
33
  import GltfMeshPrimitiveGpmLoader from "./Model/Extensions/Gpm/GltfMeshPrimitiveGpmLoader.js";
34
34
  import oneTimeWarning from "../Core/oneTimeWarning.js";
35
35
  import addAllToArray from "../Core/addAllToArray.js";
36
+ import getMeshPrimitives from "./getMeshPrimitives.js";
36
37
 
37
38
  const {
38
39
  Attribute,
@@ -1982,6 +1983,22 @@ function loadMorphTarget(
1982
1983
  return morphTarget;
1983
1984
  }
1984
1985
 
1986
+ function fetchSpzExtensionFrom(extensions) {
1987
+ const gaussianSplatting = extensions?.KHR_gaussian_splatting;
1988
+ const gsExtensions = gaussianSplatting?.extensions;
1989
+ const spz = gsExtensions?.KHR_gaussian_splatting_compression_spz_2;
1990
+ if (defined(spz)) {
1991
+ return spz;
1992
+ }
1993
+
1994
+ const legacySpz = extensions?.KHR_spz_gaussian_splats_compression;
1995
+ if (defined(legacySpz)) {
1996
+ return legacySpz;
1997
+ }
1998
+
1999
+ return undefined;
2000
+ }
2001
+
1985
2002
  /**
1986
2003
  * Load resources associated with a mesh primitive for a glTF node
1987
2004
  * @param {GltfLoader} loader
@@ -2019,7 +2036,8 @@ function loadPrimitive(loader, gltfPrimitive, hasInstances, frameState) {
2019
2036
  );
2020
2037
  }
2021
2038
 
2022
- const spzExtension = extensions.KHR_spz_gaussian_splats_compression;
2039
+ //support the latest glTF spec and the legacy extension
2040
+ const spzExtension = fetchSpzExtensionFrom(extensions);
2023
2041
  if (defined(spzExtension)) {
2024
2042
  needsPostProcessing = true;
2025
2043
  primitivePlan.needsGaussianSplats = true;
@@ -2432,7 +2450,7 @@ function loadNode(loader, gltfNode, frameState) {
2432
2450
  const meshId = gltfNode.mesh;
2433
2451
  if (defined(meshId)) {
2434
2452
  const mesh = loader.gltfJson.meshes[meshId];
2435
- const primitives = mesh.primitives;
2453
+ const primitives = getMeshPrimitives(mesh);
2436
2454
  for (let i = 0; i < primitives.length; ++i) {
2437
2455
  node.primitives.push(
2438
2456
  loadPrimitive(
@@ -306,6 +306,26 @@ async function loadFromSpz(vertexBufferLoader) {
306
306
  }
307
307
  }
308
308
 
309
+ function getShAttributePrefix(attribute) {
310
+ const prefix = attribute.startsWith("KHR_gaussian_splatting:")
311
+ ? "KHR_gaussian_splatting:"
312
+ : "_";
313
+ return `${prefix}SH_DEGREE_`;
314
+ }
315
+
316
+ function extractSHDegreeAndCoef(attribute) {
317
+ const prefix = getShAttributePrefix(attribute);
318
+ const separator = "_COEF_";
319
+
320
+ const lStart = prefix.length;
321
+ const coefIndex = attribute.indexOf(separator, lStart);
322
+
323
+ const l = parseInt(attribute.slice(lStart, coefIndex), 10);
324
+ const n = parseInt(attribute.slice(coefIndex + separator.length), 10);
325
+
326
+ return { l, n };
327
+ }
328
+
309
329
  function processSpz(vertexBufferLoader) {
310
330
  vertexBufferLoader._state = ResourceLoaderState.PROCESSING;
311
331
  const spzLoader = vertexBufferLoader._spzLoader;
@@ -314,9 +334,16 @@ function processSpz(vertexBufferLoader) {
314
334
 
315
335
  if (vertexBufferLoader._attributeSemantic === "POSITION") {
316
336
  vertexBufferLoader._typedArray = gcloudData.positions;
317
- } else if (vertexBufferLoader._attributeSemantic === "_SCALE") {
337
+ } else if (
338
+ vertexBufferLoader._attributeSemantic === "KHR_gaussian_splatting:SCALE" ||
339
+ vertexBufferLoader._attributeSemantic === "_SCALE"
340
+ ) {
318
341
  vertexBufferLoader._typedArray = gcloudData.scales;
319
- } else if (vertexBufferLoader._attributeSemantic === "_ROTATION") {
342
+ } else if (
343
+ vertexBufferLoader._attributeSemantic ===
344
+ "KHR_gaussian_splatting:ROTATION" ||
345
+ vertexBufferLoader._attributeSemantic === "_ROTATION"
346
+ ) {
320
347
  vertexBufferLoader._typedArray = gcloudData.rotations;
321
348
  } else if (vertexBufferLoader._attributeSemantic === "COLOR_0") {
322
349
  const colors = gcloudData.colors;
@@ -344,6 +371,33 @@ function processSpz(vertexBufferLoader) {
344
371
  255.0,
345
372
  );
346
373
  }
374
+ } else if (vertexBufferLoader._attributeSemantic.includes("SH_DEGREE_")) {
375
+ const { l, n } = extractSHDegreeAndCoef(
376
+ vertexBufferLoader._attributeSemantic,
377
+ );
378
+ const sphericalHarmonicDegree = gcloudData.shDegree;
379
+ let stride = 0;
380
+ const base = [0, 9, 24];
381
+ switch (sphericalHarmonicDegree) {
382
+ case 1:
383
+ stride = 9;
384
+ break;
385
+ case 2:
386
+ stride = 24;
387
+ break;
388
+ case 3:
389
+ stride = 45;
390
+ break;
391
+ }
392
+ const count = gcloudData.numPoints;
393
+ const sh = gcloudData.sh;
394
+ vertexBufferLoader._typedArray = new Float32Array(count * 3);
395
+ for (let i = 0; i < count; i++) {
396
+ const idx = i * stride + base[l - 1] + n * 3;
397
+ vertexBufferLoader._typedArray[i * 3] = sh[idx];
398
+ vertexBufferLoader._typedArray[i * 3 + 1] = sh[idx + 1];
399
+ vertexBufferLoader._typedArray[i * 3 + 2] = sh[idx + 2];
400
+ }
347
401
  }
348
402
  }
349
403
 
@@ -7,7 +7,6 @@ import Check from "../Core/Check.js";
7
7
  import KmlDataSource from "../DataSources/KmlDataSource.js";
8
8
  import GeoJsonDataSource from "../DataSources/GeoJsonDataSource.js";
9
9
  import DeveloperError from "../Core/DeveloperError.js";
10
- import deprecationWarning from "../Core/deprecationWarning.js";
11
10
 
12
11
  /**
13
12
  * Methods for loading iTwin platform data into CesiumJS
@@ -45,20 +44,11 @@ const ITwinData = {};
45
44
  * @throws {RuntimeError} If all exports for the given iModel are Invalid
46
45
  * @throws {RuntimeError} If the iTwin API request is not successful
47
46
  */
48
- ITwinData.createTilesetFromIModelId = async function (options) {
49
- let internalOptions = options;
50
-
51
- if (typeof options === "string") {
52
- // the old signature was (iModelId: string, options?: Cesium3DTileset.ConstructorOptions)
53
- // grab the later arguments directly instead of in the params only for this special case
54
- internalOptions = { iModelId: options, tilesetOptions: arguments[1] };
55
- deprecationWarning(
56
- "ITwinData.createTilesetFromIModelId",
57
- "The arguments signature for ITwinData functions has changed in 1.132 in favor of a single options object. Please update your code. This fallback will be removed in 1.133",
58
- );
59
- }
60
-
61
- const { iModelId, changesetId, tilesetOptions } = internalOptions;
47
+ ITwinData.createTilesetFromIModelId = async function ({
48
+ iModelId,
49
+ changesetId,
50
+ tilesetOptions,
51
+ }) {
62
52
  const { exports } = await ITwinPlatform.getExports(iModelId, changesetId);
63
53
 
64
54
  if (
@@ -100,6 +90,9 @@ ITwinData.createTilesetFromIModelId = async function (options) {
100
90
  * If the <code>type</code> or <code>rootDocument</code> are not provided this function
101
91
  * will first request the full metadata for the specified reality data to fill these values.
102
92
  *
93
+ * The <code>maximumScreenSpaceError</code> of the resulting tileset will default to 4,
94
+ * unless it is explicitly overridden with the given tileset options.
95
+ *
103
96
  * @experimental This feature is not final and is subject to change without Cesium's standard deprecation policy.
104
97
  *
105
98
  * @param {Object} options
@@ -107,30 +100,19 @@ ITwinData.createTilesetFromIModelId = async function (options) {
107
100
  * @param {string} options.realityDataId The id of the reality data to load
108
101
  * @param {ITwinPlatform.RealityDataType} [options.type] The type of this reality data
109
102
  * @param {string} [options.rootDocument] The path of the root document for this reality data
103
+ * @param {Cesium3DTileset.ConstructorOptions} [options.tilesetOptions] Object containing
104
+ * options to pass to the internally created {@link Cesium3DTileset}.
110
105
  * @returns {Promise<Cesium3DTileset>}
111
106
  *
112
107
  * @throws {RuntimeError} if the type of reality data is not supported by this function
113
108
  */
114
- ITwinData.createTilesetForRealityDataId = async function (options) {
115
- let internalOptions = options;
116
-
117
- if (typeof options === "string") {
118
- // the old signature was (iTwinId: string, realityDataId: string, type: RealityDataType, rootDocument: string)
119
- // grab the later arguments directly instead of in the params only for this special case
120
- internalOptions = {
121
- iTwinId: options,
122
- realityDataId: arguments[1],
123
- type: arguments[2],
124
- rootDocument: arguments[3],
125
- };
126
- deprecationWarning(
127
- "ITwinData.createTilesetFromIModelId",
128
- "The arguments signature for ITwinData functions has changed in 1.132 in favor of a single options object. Please update your code. This fallback will be removed in 1.133",
129
- );
130
- }
131
- const { iTwinId, realityDataId } = internalOptions;
132
- let { type, rootDocument } = internalOptions;
133
-
109
+ ITwinData.createTilesetForRealityDataId = async function ({
110
+ iTwinId,
111
+ realityDataId,
112
+ type,
113
+ rootDocument,
114
+ tilesetOptions,
115
+ }) {
134
116
  //>>includeStart('debug', pragmas.debug);
135
117
  Check.typeOf.string("iTwinId", iTwinId);
136
118
  Check.typeOf.string("realityDataId", realityDataId);
@@ -168,9 +150,16 @@ ITwinData.createTilesetForRealityDataId = async function (options) {
168
150
  rootDocument,
169
151
  );
170
152
 
171
- return Cesium3DTileset.fromUrl(tilesetAccessUrl, {
153
+ // The maximum screen space error was defined to default to 4 for
154
+ // reality data tilesets, because they did not show the expected
155
+ // amount of detail with the default value of 16. Values that are
156
+ // given in the tilesetOptions should still override that default.
157
+ const internalTilesetOptions = {
172
158
  maximumScreenSpaceError: 4,
173
- });
159
+ ...tilesetOptions,
160
+ };
161
+
162
+ return Cesium3DTileset.fromUrl(tilesetAccessUrl, internalTilesetOptions);
174
163
  };
175
164
 
176
165
  /**
@@ -189,26 +178,12 @@ ITwinData.createTilesetForRealityDataId = async function (options) {
189
178
  *
190
179
  * @throws {RuntimeError} if the type of reality data is not supported by this function
191
180
  */
192
- ITwinData.createDataSourceForRealityDataId = async function (options) {
193
- let internalOptions = options;
194
-
195
- if (typeof options === "string") {
196
- // the old signature was (iTwinId: string, realityDataId: string, type: RealityDataType, rootDocument: string)
197
- // grab the later arguments directly instead of in the params only for this special case
198
- internalOptions = {
199
- iTwinId: options,
200
- realityDataId: arguments[1],
201
- type: arguments[2],
202
- rootDocument: arguments[3],
203
- };
204
- deprecationWarning(
205
- "ITwinData.createTilesetFromIModelId",
206
- "The arguments signature for ITwinData functions has changed in 1.132 in favor of a single options object. Please update your code. This fallback will be removed in 1.133",
207
- );
208
- }
209
- const { iTwinId, realityDataId } = internalOptions;
210
- let { type, rootDocument } = internalOptions;
211
-
181
+ ITwinData.createDataSourceForRealityDataId = async function ({
182
+ iTwinId,
183
+ realityDataId,
184
+ type,
185
+ rootDocument,
186
+ }) {
212
187
  //>>includeStart('debug', pragmas.debug);
213
188
  Check.typeOf.string("iTwinId", iTwinId);
214
189
  Check.typeOf.string("realityDataId", realityDataId);
@@ -263,25 +238,11 @@ ITwinData.createDataSourceForRealityDataId = async function (options) {
263
238
  * @param {number} [options.limit=10000] number of items per page, must be between 1 and 10,000 inclusive
264
239
  * @returns {Promise<GeoJsonDataSource>}
265
240
  */
266
- ITwinData.loadGeospatialFeatures = async function (options) {
267
- let internalOptions = options;
268
-
269
- if (typeof options === "string") {
270
- // the old signature was (iTwinId: string, collectionId: string, limit: number)
271
- // grab the later arguments directly instead of in the params only for this special case
272
- internalOptions = {
273
- iTwinId: options,
274
- collectionId: arguments[1],
275
- limit: arguments[2],
276
- };
277
- deprecationWarning(
278
- "ITwinData.createTilesetFromIModelId",
279
- "The arguments signature for ITwinData functions has changed in 1.132 in favor of a single options object. Please update your code. This fallback will be removed in 1.133",
280
- );
281
- }
282
-
283
- const { iTwinId, collectionId, limit } = internalOptions;
284
-
241
+ ITwinData.loadGeospatialFeatures = async function ({
242
+ iTwinId,
243
+ collectionId,
244
+ limit,
245
+ }) {
285
246
  //>>includeStart('debug', pragmas.debug);
286
247
  Check.typeOf.string("iTwinId", iTwinId);
287
248
  Check.typeOf.string("collectionId", collectionId);
@@ -72,6 +72,9 @@ import ModelImagery from "./ModelImagery.js";
72
72
  * {@link https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Vendor/EXT_mesh_gpu_instancing|EXT_mesh_gpu_instancing}
73
73
  * </li>
74
74
  * <li>
75
+ * {@link https://github.com/KhronosGroup/glTF/pull/2514|EXT_mesh_primitive_restart}
76
+ * </li>
77
+ * <li>
75
78
  * {@link https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Vendor/EXT_meshopt_compression|EXT_meshopt_compression}
76
79
  * </li>
77
80
  * <li>
@@ -79,10 +79,16 @@ ModelClippingPolygonsPipelineStage.process = function (
79
79
 
80
80
  const uniformMap = {
81
81
  model_clippingDistance: function () {
82
- return clippingPolygons.clippingTexture;
82
+ return (
83
+ // The later should never happen during a render pass, see https://github.com/CesiumGS/cesium/issues/12725
84
+ clippingPolygons.clippingTexture ?? frameState.context.defaultTexture
85
+ );
83
86
  },
84
87
  model_clippingExtents: function () {
85
- return clippingPolygons.extentsTexture;
88
+ return (
89
+ // The later should never happen during a render pass, see https://github.com/CesiumGS/cesium/issues/12725
90
+ clippingPolygons.extentsTexture ?? frameState.context.defaultTexture
91
+ );
86
92
  },
87
93
  };
88
94
 
@@ -369,6 +369,7 @@ ModelUtility.supportedExtensions = {
369
369
  KHR_texture_basisu: true,
370
370
  KHR_texture_transform: true,
371
371
  KHR_gaussian_splatting: true,
372
+ KHR_gaussian_splatting_compression_spz_2: true,
372
373
  KHR_spz_gaussian_splats_compression: true,
373
374
  WEB3D_quantized_attributes: true,
374
375
  };
@@ -549,17 +549,21 @@ function makeAttributes(loader, parsedContent, context) {
549
549
  function makeStructuralMetadata(parsedContent, customAttributeOutput) {
550
550
  const batchLength = parsedContent.batchLength;
551
551
  const pointsLength = parsedContent.pointsLength;
552
+ const batchTableJson = parsedContent.batchTableJson;
552
553
  const batchTableBinary = parsedContent.batchTableBinary;
553
554
 
554
555
  // If there are batch IDs, parse as a property table. Otherwise, parse
555
556
  // as property attributes.
556
557
  const parseAsPropertyAttributes = !defined(parsedContent.batchIds);
557
-
558
- if (defined(batchTableBinary) || parsedContent.hasDracoBatchTable) {
558
+ if (
559
+ defined(batchTableBinary) ||
560
+ defined(batchTableJson) ||
561
+ parsedContent.hasDracoBatchTable
562
+ ) {
559
563
  const count = batchLength ?? pointsLength;
560
564
  return parseBatchTable({
561
565
  count: count,
562
- batchTable: parsedContent.batchTableJson,
566
+ batchTable: batchTableJson,
563
567
  binaryBody: batchTableBinary,
564
568
  parseAsPropertyAttributes: parseAsPropertyAttributes,
565
569
  customAttributeOutput: customAttributeOutput,