@cesium/engine 19.0.0 → 20.0.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.
- package/Build/ThirdParty/Workers/pako_deflate.min.js +3 -3
- package/Build/ThirdParty/Workers/pako_inflate.min.js +3 -3
- package/Build/ThirdParty/Workers/z-worker-pako.js +49 -42
- package/Build/Workers/{chunk-ETCPCGKC.js → chunk-22LUVCO3.js} +2 -2
- package/Build/Workers/{chunk-34DFERFC.js → chunk-3BO4XBWM.js} +12 -12
- package/Build/Workers/{chunk-DXYAD4ED.js → chunk-3SQPZVG4.js} +1 -1
- package/Build/Workers/{chunk-Y3PM6G2V.js → chunk-4O5SZ2RE.js} +3 -3
- package/Build/Workers/{chunk-37IYBZDZ.js → chunk-4UIKSIEZ.js} +9 -9
- package/Build/Workers/{chunk-UPU755HO.js → chunk-5FZEM66Y.js} +12 -12
- package/Build/Workers/{chunk-ESDVZ4QL.js → chunk-5G56VVL3.js} +10 -10
- package/Build/Workers/{chunk-SXMHGVZ7.js → chunk-5GKRDXYJ.js} +12 -12
- package/Build/Workers/{chunk-4QWLEG4L.js → chunk-5W4EBNO3.js} +14 -14
- package/Build/Workers/{chunk-ZNEIUXBK.js → chunk-67RLCIDP.js} +7 -7
- package/Build/Workers/{chunk-GVO3YIU2.js → chunk-74VODBWB.js} +4 -4
- package/Build/Workers/{chunk-Y6LLFNXN.js → chunk-7HOD2LGH.js} +10 -10
- package/Build/Workers/{chunk-5YCDPN3O.js → chunk-D25QOWHR.js} +1 -1
- package/Build/Workers/{chunk-NMAT4IJ6.js → chunk-D63DK275.js} +7 -7
- package/Build/Workers/{chunk-XUYCCEG6.js → chunk-EHOOC4HJ.js} +5 -5
- package/Build/Workers/{chunk-MBDKO456.js → chunk-ELI5ZYDR.js} +5 -5
- package/Build/Workers/{chunk-HHHBRTSW.js → chunk-FGF4ETPY.js} +9 -9
- package/Build/Workers/{chunk-PAH73ETP.js → chunk-FKWL63D4.js} +5 -5
- package/Build/Workers/{chunk-MUL374P3.js → chunk-FLH3ZH2X.js} +4 -4
- package/Build/Workers/{chunk-HJ6KFRM7.js → chunk-HDOFAYEE.js} +16 -16
- package/Build/Workers/{chunk-SVGHDIZG.js → chunk-HHUHFFYN.js} +5 -5
- package/Build/Workers/{chunk-E6NMEKSS.js → chunk-IHUXLSNT.js} +5 -4
- package/Build/Workers/{chunk-KTDHOEXR.js → chunk-IJM2HVTV.js} +1 -1
- package/Build/Workers/{chunk-DNCRKMCI.js → chunk-IPXMWP5Z.js} +6 -6
- package/Build/Workers/{chunk-RZJA77TX.js → chunk-IWKYS6RV.js} +6 -6
- package/Build/Workers/{chunk-WUMTX3FI.js → chunk-JMX3P7DE.js} +8 -8
- package/Build/Workers/{chunk-23FRF5ZP.js → chunk-JQSMAZAT.js} +9 -9
- package/Build/Workers/{chunk-5VPO47LB.js → chunk-JRLT2FQV.js} +8 -8
- package/Build/Workers/{chunk-JZVUMRYA.js → chunk-KRXL3KZL.js} +13 -13
- package/Build/Workers/{chunk-Q2QXUN33.js → chunk-KWB7PPVO.js} +2 -2
- package/Build/Workers/{chunk-ECWQXDZY.js → chunk-M62PWLGC.js} +16 -16
- package/Build/Workers/{chunk-4NRFVAG2.js → chunk-MSLO3MQF.js} +5 -5
- package/Build/Workers/{chunk-W32QSECR.js → chunk-MZZK44UI.js} +6 -6
- package/Build/Workers/{chunk-25USKS4R.js → chunk-NB2NKFJL.js} +6 -6
- package/Build/Workers/{chunk-EV4PBU7O.js → chunk-NJYFQE5B.js} +1 -1
- package/Build/Workers/{chunk-SOYVF5RC.js → chunk-O2O4FYNI.js} +2 -2
- package/Build/Workers/{chunk-SO2Z6H6F.js → chunk-PZEPLREA.js} +2 -2
- package/Build/Workers/{chunk-C36VNKTH.js → chunk-S2RSJJQI.js} +4 -4
- package/Build/Workers/{chunk-DAHXCIOX.js → chunk-S3UYLP3X.js} +8 -8
- package/Build/Workers/{chunk-AZPKFL5X.js → chunk-TH3P77KJ.js} +5 -5
- package/Build/Workers/{chunk-GO3IRH6U.js → chunk-UGSQJYGE.js} +6 -6
- package/Build/Workers/{chunk-IE2BEHLE.js → chunk-UUXOFY6G.js} +12 -12
- package/Build/Workers/{chunk-VCCR35R6.js → chunk-V36BVRDX.js} +11 -11
- package/Build/Workers/{chunk-T7C73J6H.js → chunk-VJ2DNCFT.js} +4 -4
- package/Build/Workers/{chunk-RIQM3XY5.js → chunk-VQUVJWBK.js} +4 -4
- package/Build/Workers/{chunk-AABNX23Q.js → chunk-VWQWZ7OL.js} +5 -5
- package/Build/Workers/{chunk-K5VGMGFM.js → chunk-VXBNLAG4.js} +7 -7
- package/Build/Workers/{chunk-YPNIIVIF.js → chunk-W3KNMQT2.js} +6 -6
- package/Build/Workers/{chunk-DPFAUGBE.js → chunk-WIGH3CPD.js} +2 -2
- package/Build/Workers/{chunk-NKM2EV46.js → chunk-XVHLXVN3.js} +1 -1
- package/Build/Workers/{chunk-6T2PQKYP.js → chunk-YHB3RNF2.js} +4 -4
- package/Build/Workers/{chunk-FQNSMOZT.js → chunk-ZSHDRKLT.js} +4 -4
- package/Build/Workers/combineGeometry.js +21 -21
- package/Build/Workers/createBoxGeometry.js +15 -15
- package/Build/Workers/createBoxOutlineGeometry.js +13 -13
- package/Build/Workers/createCircleGeometry.js +23 -23
- package/Build/Workers/createCircleOutlineGeometry.js +16 -16
- package/Build/Workers/createCoplanarPolygonGeometry.js +30 -30
- package/Build/Workers/createCoplanarPolygonOutlineGeometry.js +28 -28
- package/Build/Workers/createCorridorGeometry.js +26 -26
- package/Build/Workers/createCorridorOutlineGeometry.js +25 -25
- package/Build/Workers/createCylinderGeometry.js +17 -17
- package/Build/Workers/createCylinderOutlineGeometry.js +15 -15
- package/Build/Workers/createEllipseGeometry.js +23 -23
- package/Build/Workers/createEllipseOutlineGeometry.js +16 -16
- package/Build/Workers/createEllipsoidGeometry.js +16 -16
- package/Build/Workers/createEllipsoidOutlineGeometry.js +15 -15
- package/Build/Workers/createFrustumGeometry.js +15 -15
- package/Build/Workers/createFrustumOutlineGeometry.js +15 -15
- package/Build/Workers/createGeometry.js +21 -21
- package/Build/Workers/createGroundPolylineGeometry.js +19 -19
- package/Build/Workers/createPlaneGeometry.js +13 -13
- package/Build/Workers/createPlaneOutlineGeometry.js +12 -12
- package/Build/Workers/createPolygonGeometry.js +29 -29
- package/Build/Workers/createPolygonOutlineGeometry.js +27 -27
- package/Build/Workers/createPolylineGeometry.js +22 -22
- package/Build/Workers/createPolylineVolumeGeometry.js +28 -28
- package/Build/Workers/createPolylineVolumeOutlineGeometry.js +24 -24
- package/Build/Workers/createRectangleGeometry.js +24 -24
- package/Build/Workers/createRectangleOutlineGeometry.js +17 -17
- package/Build/Workers/createSimplePolylineGeometry.js +20 -20
- package/Build/Workers/createSphereGeometry.js +16 -16
- package/Build/Workers/createSphereOutlineGeometry.js +15 -15
- package/Build/Workers/createTaskProcessorWorker.js +3 -3
- package/Build/Workers/createVectorTileClampedPolylines.js +12 -12
- package/Build/Workers/createVectorTileGeometries.js +21 -21
- package/Build/Workers/createVectorTilePoints.js +11 -11
- package/Build/Workers/createVectorTilePolygons.js +19 -19
- package/Build/Workers/createVectorTilePolylines.js +12 -12
- package/Build/Workers/createVerticesFromGoogleEarthEnterpriseBuffer.js +19 -19
- package/Build/Workers/createVerticesFromHeightmap.js +25 -25
- package/Build/Workers/createVerticesFromQuantizedTerrainMesh.js +16 -16
- package/Build/Workers/createWallGeometry.js +21 -21
- package/Build/Workers/createWallOutlineGeometry.js +20 -20
- package/Build/Workers/decodeDraco.js +10 -10
- package/Build/Workers/decodeGoogleEarthEnterprisePacket.js +5 -5
- package/Build/Workers/decodeI3S.js +9 -9
- package/Build/Workers/gaussianSplatSorter.js +4 -4
- package/Build/Workers/gaussianSplatTextureGenerator.js +4 -4
- package/Build/Workers/transcodeKTX2.js +17 -16
- package/Build/Workers/transferTypedArrayTest.js +1 -1
- package/Build/Workers/upsampleQuantizedTerrainMesh.js +19 -19
- package/Source/Core/Ellipsoid.js +9 -0
- package/Source/Core/Ion.js +1 -1
- package/Source/Core/IonResource.js +14 -8
- package/Source/Scene/ArcGisMapService.js +1 -1
- package/Source/Scene/BingMapsImageryProvider.js +1 -1
- package/Source/Scene/Cesium3DTileContentFactory.js +7 -16
- package/Source/Scene/Cesium3DTileset.js +1 -1
- package/Source/Scene/GaussianSplat3DTileContent.js +253 -9
- package/Source/Scene/GaussianSplatPrimitive.js +167 -15
- package/Source/Scene/GltfLoader.js +20 -2
- package/Source/Scene/GltfVertexBufferLoader.js +56 -2
- package/Source/Scene/ITwinData.js +37 -76
- package/Source/Scene/Model/Model.js +3 -0
- package/Source/Scene/Model/ModelClippingPolygonsPipelineStage.js +8 -2
- package/Source/Scene/Model/ModelUtility.js +1 -0
- package/Source/Scene/Model/PntsLoader.js +7 -3
- package/Source/Scene/PntsParser.js +6 -3
- package/Source/Scene/PrimitiveLoadPlan.js +1 -1
- package/Source/Scene/VertexAttributeSemantic.js +4 -2
- package/Source/Scene/WebMapServiceImageryProvider.js +3 -2
- package/Source/Scene/WebMapTileServiceImageryProvider.js +0 -22
- package/Source/Scene/getMeshPrimitives.js +72 -0
- package/Source/Shaders/PrimitiveGaussianSplatFS.glsl +5 -5
- package/Source/Shaders/PrimitiveGaussianSplatFS.js +5 -5
- package/Source/Shaders/PrimitiveGaussianSplatVS.glsl +102 -5
- package/Source/Shaders/PrimitiveGaussianSplatVS.js +102 -5
- package/Source/ThirdParty/Workers/z-worker-pako.js +1 -1
- package/index.d.ts +109 -1
- package/index.js +376 -375
- package/package.json +2 -2
|
@@ -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
|
|
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
|
|
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
|
-
|
|
457
|
+
gltfPrimitive,
|
|
429
458
|
VertexAttributeSemantic.POSITION,
|
|
430
459
|
).typedArray;
|
|
431
460
|
|
|
432
461
|
const attributeRotations = ModelUtility.getAttributeBySemantic(
|
|
433
|
-
|
|
462
|
+
gltfPrimitive,
|
|
434
463
|
VertexAttributeSemantic.ROTATION,
|
|
435
464
|
).typedArray;
|
|
436
465
|
|
|
437
466
|
const attributeScales = ModelUtility.getAttributeBySemantic(
|
|
438
|
-
|
|
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 (
|
|
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.
|
|
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
|
-
(
|
|
907
|
+
(gltfPrimitive) =>
|
|
792
908
|
ModelUtility.getAttributeBySemantic(
|
|
793
|
-
|
|
909
|
+
gltfPrimitive,
|
|
794
910
|
VertexAttributeSemantic.POSITION,
|
|
795
911
|
),
|
|
796
912
|
);
|
|
797
913
|
|
|
798
914
|
this._scales = aggregateAttributeValues(
|
|
799
915
|
ComponentDatatype.FLOAT,
|
|
800
|
-
(
|
|
916
|
+
(gltfPrimitive) =>
|
|
801
917
|
ModelUtility.getAttributeBySemantic(
|
|
802
|
-
|
|
918
|
+
gltfPrimitive,
|
|
803
919
|
VertexAttributeSemantic.SCALE,
|
|
804
920
|
),
|
|
805
921
|
);
|
|
806
922
|
|
|
807
923
|
this._rotations = aggregateAttributeValues(
|
|
808
924
|
ComponentDatatype.FLOAT,
|
|
809
|
-
(
|
|
925
|
+
(gltfPrimitive) =>
|
|
810
926
|
ModelUtility.getAttributeBySemantic(
|
|
811
|
-
|
|
927
|
+
gltfPrimitive,
|
|
812
928
|
VertexAttributeSemantic.ROTATION,
|
|
813
929
|
),
|
|
814
930
|
);
|
|
815
931
|
|
|
816
932
|
this._colors = aggregateAttributeValues(
|
|
817
933
|
ComponentDatatype.UNSIGNED_BYTE,
|
|
818
|
-
(
|
|
934
|
+
(gltfPrimitive) =>
|
|
819
935
|
ModelUtility.getAttributeBySemantic(
|
|
820
|
-
|
|
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
|
-
|
|
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
|
|
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 (
|
|
337
|
+
} else if (
|
|
338
|
+
vertexBufferLoader._attributeSemantic === "KHR_gaussian_splatting:SCALE" ||
|
|
339
|
+
vertexBufferLoader._attributeSemantic === "_SCALE"
|
|
340
|
+
) {
|
|
318
341
|
vertexBufferLoader._typedArray = gcloudData.scales;
|
|
319
|
-
} else if (
|
|
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 (
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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 (
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
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
|
-
|
|
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 (
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
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 (
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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:
|
|
566
|
+
batchTable: batchTableJson,
|
|
563
567
|
binaryBody: batchTableBinary,
|
|
564
568
|
parseAsPropertyAttributes: parseAsPropertyAttributes,
|
|
565
569
|
customAttributeOutput: customAttributeOutput,
|