Skip to content

Commit 7e376b6

Browse files
authored
Merge branch 'main' into label-clamping-performance
2 parents 3f678ca + edccce4 commit 7e376b6

File tree

9 files changed

+267
-64
lines changed

9 files changed

+267
-64
lines changed

CHANGES.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
- Improved performance and reduced memory usage of `Event` class. [#12896](https://github.com/CesiumGS/cesium/pull/12896)
1313
- Fixes vertical misalignment of glyphs in labels with small fonts [#8474](https://github.com/CesiumGS/cesium/issues/8474)
1414
- Prevent runtime errors for certain forms of invalid PNTS files [#12872](https://github.com/CesiumGS/cesium/issues/12872)
15-
- Improved performance of clamped labels [#12905](https://github.com/CesiumGS/cesium/pull/12905)
15+
- Improved performance of clamped labels. [#12905](https://github.com/CesiumGS/cesium/pull/12905)
16+
- Fixes issue where multiple instances of a Gaussian splat tileset would transform tile positions incorrectly and render out of position. [#12795](https://github.com/CesiumGS/cesium/issues/12795)
1617

1718
#### Additions :tada:
1819

CONTRIBUTORS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,3 +431,4 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to contribute to Cesiu
431431
- [Easy Mahaffey](https://github.com/easymaahffey)
432432
- [Pamela Augustine](https://github.com/pamelaAugustine)
433433
- [宋时旺](https://github.com/BlockCnFuture)
434+
- [Marco Zhan](https://github.com/marcoYxz)

gulpfile.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ function handleBuildWarnings(result) {
123123
export async function build() {
124124
// Configure build options from command line arguments.
125125
const minify = argv.minify ?? false;
126-
const removePragmas = argv.pragmas ?? false;
126+
const removePragmas = argv.removePragmas ?? false;
127127
const sourcemap = argv.sourcemap ?? true;
128128
const node = argv.node ?? true;
129129

packages/engine/Source/Scene/ClippingPolygon.js

Lines changed: 91 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,90 @@ function ClippingPolygon(options) {
4646
//>>includeEnd('debug');
4747

4848
this._ellipsoid = options.ellipsoid ?? Ellipsoid.default;
49-
this._positions = [...options.positions];
49+
this._positions = copyArrayCartesian3(options.positions);
50+
51+
/**
52+
* A copy of the input positions.
53+
*
54+
* This is used to detect modifications of the positions in
55+
* <code>coputeRectangle</code>: The rectangle only has
56+
* to be re-computed when these positions have changed.
57+
*
58+
* @type {Cartesian3[]|undefined}
59+
* @private
60+
*/
61+
this._cachedPositions = undefined;
62+
63+
/**
64+
* A cached version of the rectangle that is computed in
65+
* <code>computeRectangle</code>.
66+
*
67+
* This is only re-computed when the positions have changed, as
68+
* determined by comparing the <code>_positions</code> to the
69+
* <code>_cachedPositions</code>
70+
*
71+
* @type {Rectangle|undefined}
72+
* @private
73+
*/
74+
this._cachedRectangle = undefined;
75+
}
76+
77+
/**
78+
* Returns a deep copy of the given array.
79+
*
80+
* If the input is undefined, then <code>undefined</code> is returned.
81+
*
82+
* Otherwise, the result will be a copy of the given array, where
83+
* each element is copied with <code>Cartesian3.clone</code>.
84+
*
85+
* @param {Cartesian3[]|undefined} input The input array
86+
* @returns {Cartesian3[]|undefined} The copy
87+
*/
88+
function copyArrayCartesian3(input) {
89+
if (!defined(input)) {
90+
return undefined;
91+
}
92+
const n = input.length;
93+
const output = Array(n);
94+
for (let i = 0; i < n; i++) {
95+
output[i] = Cartesian3.clone(input[i]);
96+
}
97+
return output;
98+
}
99+
100+
/**
101+
* Returns whether the given arrays are component-wise equal.
102+
*
103+
* When both arrays are undefined, then <code>true</code> is returned.
104+
* When only one array is defined, or they are both defined but have
105+
* different lengths, then <code>false</code> is returned.
106+
*
107+
* Otherwise, returns whether the corresponding elements of the arrays
108+
* are equal, as of <code>Cartesian3.equals</code>.
109+
*
110+
* @param {Cartesian3[]|undefined} a The first array
111+
* @param {Cartesian3[]|undefined} b The second array
112+
* @returns {boolean} Whether the arrays are equal
113+
*/
114+
function equalsArrayCartesian3(a, b) {
115+
if (!defined(a) && !defined(b)) {
116+
return true;
117+
}
118+
if (defined(a) !== defined(b)) {
119+
return false;
120+
}
121+
if (a.length !== b.length) {
122+
return false;
123+
}
124+
const n = a.length;
125+
for (let i = 0; i < n; i++) {
126+
const ca = a[i];
127+
const cb = b[i];
128+
if (!Cartesian3.equals(ca, cb)) {
129+
return false;
130+
}
131+
}
132+
return true;
50133
}
51134

52135
Object.defineProperties(ClippingPolygon.prototype, {
@@ -138,12 +221,18 @@ ClippingPolygon.equals = function (left, right) {
138221
* @returns {Rectangle} The result rectangle
139222
*/
140223
ClippingPolygon.prototype.computeRectangle = function (result) {
141-
return PolygonGeometry.computeRectangleFromPositions(
224+
if (equalsArrayCartesian3(this._positions, this._cachedPositions)) {
225+
return Rectangle.clone(this._cachedRectangle, result);
226+
}
227+
const rectangle = PolygonGeometry.computeRectangleFromPositions(
142228
this.positions,
143229
this.ellipsoid,
144230
undefined,
145231
result,
146232
);
233+
this._cachedPositions = copyArrayCartesian3(this._positions);
234+
this._cachedRectangle = Rectangle.clone(rectangle);
235+
return rectangle;
147236
};
148237

149238
const scratchRectangle = new Rectangle();

packages/engine/Source/Scene/GaussianSplat3DTileContent.js

Lines changed: 54 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,28 @@ function GaussianSplat3DTileContent(loader, tileset, tile, resource) {
3131
}
3232

3333
/**
34-
* Original position, scale and rotation values for splats. Used to maintain
35-
* consistency when multiple transforms may occur. Downstream consumers otherwise may not know
36-
* the underlying data was modified.
34+
* Local copy of the position attribute buffer that has been transformed into root tile space. Originals are kept in the gltf loader.
35+
* Used for rendering
3736
* @type {undefined|Float32Array}
3837
* @private
3938
*/
40-
this._originalPositions = undefined;
41-
this._originalRotations = undefined;
42-
this._originalScales = undefined;
39+
this._positions = undefined;
40+
41+
/**
42+
* Local copy of the rotation attribute buffer that has been transformed into root tile space. Originals are kept in the gltf loader.
43+
* Used for rendering
44+
* @type {undefined|Float32Array}
45+
* @private
46+
*/
47+
this._rotations = undefined;
48+
49+
/**
50+
* Local copy of the scale attribute buffer that has been transformed into root tile space. Originals are kept in the gltf loader.
51+
* Used for rendering
52+
* @type {undefined|Float32Array}
53+
* @private
54+
*/
55+
this._scales = undefined;
4356

4457
/**
4558
* glTF primitive data that contains the Gaussian splat data needed for rendering.
@@ -368,6 +381,38 @@ Object.defineProperties(GaussianSplat3DTileContent.prototype, {
368381
},
369382
},
370383

384+
/**
385+
* Get the transformed positions of this tile's Gaussian splats.
386+
* @type {undefined|Float32Array}
387+
* @private
388+
*/
389+
positions: {
390+
get: function () {
391+
return this._positions;
392+
},
393+
},
394+
/**
395+
* Get the transformed rotations of this tile's Gaussian splats.
396+
* @type {undefined|Float32Array}
397+
* @private
398+
*/
399+
rotations: {
400+
get: function () {
401+
return this._rotations;
402+
},
403+
},
404+
405+
/**
406+
* Get the transformed scales of this tile's Gaussian splats.
407+
* @type {undefined|Float32Array}
408+
* @private
409+
*/
410+
scales: {
411+
get: function () {
412+
return this._scales;
413+
},
414+
},
415+
371416
/**
372417
* The number of spherical harmonic coefficients used for the Gaussian splats.
373418
* @type {number}
@@ -629,21 +674,21 @@ GaussianSplat3DTileContent.prototype.update = function (primitive, frameState) {
629674
this.worldTransform = loader.components.scene.nodes[0].matrix;
630675
this._ready = true;
631676

632-
this._originalPositions = new Float32Array(
677+
this._positions = new Float32Array(
633678
ModelUtility.getAttributeBySemantic(
634679
this.gltfPrimitive,
635680
VertexAttributeSemantic.POSITION,
636681
).typedArray,
637682
);
638683

639-
this._originalRotations = new Float32Array(
684+
this._rotations = new Float32Array(
640685
ModelUtility.getAttributeBySemantic(
641686
this.gltfPrimitive,
642687
VertexAttributeSemantic.ROTATION,
643688
).typedArray,
644689
);
645690

646-
this._originalScales = new Float32Array(
691+
this._scales = new Float32Array(
647692
ModelUtility.getAttributeBySemantic(
648693
this.gltfPrimitive,
649694
VertexAttributeSemantic.SCALE,

packages/engine/Source/Scene/GaussianSplatPrimitive.js

Lines changed: 44 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -450,9 +450,9 @@ GaussianSplatPrimitive.transformTile = function (tile) {
450450
computedModelMatrix,
451451
scratchMatrix4A,
452452
);
453-
const positions = tile.content._originalPositions;
454-
const rotations = tile.content._originalRotations;
455-
const scales = tile.content._originalScales;
453+
const positions = tile.content.positions;
454+
const rotations = tile.content.rotations;
455+
const scales = tile.content.scales;
456456
const attributePositions = ModelUtility.getAttributeBySemantic(
457457
gltfPrimitive,
458458
VertexAttributeSemantic.POSITION,
@@ -471,19 +471,19 @@ GaussianSplatPrimitive.transformTile = function (tile) {
471471
const position = new Cartesian3();
472472
const rotation = new Quaternion();
473473
const scale = new Cartesian3();
474-
for (let i = 0; i < positions.length / 3; ++i) {
475-
position.x = positions[i * 3];
476-
position.y = positions[i * 3 + 1];
477-
position.z = positions[i * 3 + 2];
474+
for (let i = 0; i < attributePositions.length / 3; ++i) {
475+
position.x = attributePositions[i * 3];
476+
position.y = attributePositions[i * 3 + 1];
477+
position.z = attributePositions[i * 3 + 2];
478478

479-
rotation.x = rotations[i * 4];
480-
rotation.y = rotations[i * 4 + 1];
481-
rotation.z = rotations[i * 4 + 2];
482-
rotation.w = rotations[i * 4 + 3];
479+
rotation.x = attributeRotations[i * 4];
480+
rotation.y = attributeRotations[i * 4 + 1];
481+
rotation.z = attributeRotations[i * 4 + 2];
482+
rotation.w = attributeRotations[i * 4 + 3];
483483

484-
scale.x = scales[i * 3];
485-
scale.y = scales[i * 3 + 1];
486-
scale.z = scales[i * 3 + 2];
484+
scale.x = attributeScales[i * 3];
485+
scale.y = attributeScales[i * 3 + 1];
486+
scale.z = attributeScales[i * 3 + 2];
487487

488488
Matrix4.fromTranslationQuaternionRotationScale(
489489
position,
@@ -498,18 +498,18 @@ GaussianSplatPrimitive.transformTile = function (tile) {
498498
Matrix4.getRotation(scratchMatrix4C, rotation);
499499
Matrix4.getScale(scratchMatrix4C, scale);
500500

501-
attributePositions[i * 3] = position.x;
502-
attributePositions[i * 3 + 1] = position.y;
503-
attributePositions[i * 3 + 2] = position.z;
501+
positions[i * 3] = position.x;
502+
positions[i * 3 + 1] = position.y;
503+
positions[i * 3 + 2] = position.z;
504504

505-
attributeRotations[i * 4] = rotation.x;
506-
attributeRotations[i * 4 + 1] = rotation.y;
507-
attributeRotations[i * 4 + 2] = rotation.z;
508-
attributeRotations[i * 4 + 3] = rotation.w;
505+
rotations[i * 4] = rotation.x;
506+
rotations[i * 4 + 1] = rotation.y;
507+
rotations[i * 4 + 2] = rotation.z;
508+
rotations[i * 4 + 3] = rotation.w;
509509

510-
attributeScales[i * 3] = scale.x;
511-
attributeScales[i * 3 + 1] = scale.y;
512-
attributeScales[i * 3 + 2] = scale.z;
510+
scales[i * 3] = scale.x;
511+
scales[i * 3 + 1] = scale.y;
512+
scales[i * 3 + 2] = scale.z;
513513
}
514514
};
515515

@@ -860,21 +860,27 @@ GaussianSplatPrimitive.prototype.update = function (frameState) {
860860
const aggregateAttributeValues = (
861861
componentDatatype,
862862
getAttributeCallback,
863+
numberOfComponents,
863864
) => {
864865
let aggregate;
865866
let offset = 0;
866867
for (const tile of tiles) {
867-
const primitive = tile.content.gltfPrimitive;
868-
const attribute = getAttributeCallback(primitive);
868+
const content = tile.content;
869+
const attribute = getAttributeCallback(content);
870+
const componentsPerAttribute = defined(numberOfComponents)
871+
? numberOfComponents
872+
: AttributeType.getNumberOfComponents(attribute.type);
873+
const buffer = defined(attribute.typedArray)
874+
? attribute.typedArray
875+
: attribute;
869876
if (!defined(aggregate)) {
870877
aggregate = ComponentDatatype.createTypedArray(
871878
componentDatatype,
872-
totalElements *
873-
AttributeType.getNumberOfComponents(attribute.type),
879+
totalElements * componentsPerAttribute,
874880
);
875881
}
876-
aggregate.set(attribute.typedArray, offset);
877-
offset += attribute.typedArray.length;
882+
aggregate.set(buffer, offset);
883+
offset += buffer.length;
878884
}
879885
return aggregate;
880886
};
@@ -906,36 +912,27 @@ GaussianSplatPrimitive.prototype.update = function (frameState) {
906912

907913
this._positions = aggregateAttributeValues(
908914
ComponentDatatype.FLOAT,
909-
(gltfPrimitive) =>
910-
ModelUtility.getAttributeBySemantic(
911-
gltfPrimitive,
912-
VertexAttributeSemantic.POSITION,
913-
),
915+
(content) => content.positions,
916+
3,
914917
);
915918

916919
this._scales = aggregateAttributeValues(
917920
ComponentDatatype.FLOAT,
918-
(gltfPrimitive) =>
919-
ModelUtility.getAttributeBySemantic(
920-
gltfPrimitive,
921-
VertexAttributeSemantic.SCALE,
922-
),
921+
(content) => content.scales,
922+
3,
923923
);
924924

925925
this._rotations = aggregateAttributeValues(
926926
ComponentDatatype.FLOAT,
927-
(gltfPrimitive) =>
928-
ModelUtility.getAttributeBySemantic(
929-
gltfPrimitive,
930-
VertexAttributeSemantic.ROTATION,
931-
),
927+
(content) => content.rotations,
928+
4,
932929
);
933930

934931
this._colors = aggregateAttributeValues(
935932
ComponentDatatype.UNSIGNED_BYTE,
936-
(gltfPrimitive) =>
933+
(content) =>
937934
ModelUtility.getAttributeBySemantic(
938-
gltfPrimitive,
935+
content.gltfPrimitive,
939936
VertexAttributeSemantic.COLOR,
940937
),
941938
);

0 commit comments

Comments
 (0)