From dd82a80f6e54eabbe06dea3e0547d091b590e087 Mon Sep 17 00:00:00 2001 From: Adam Beili Date: Tue, 7 Oct 2025 12:45:34 +0300 Subject: [PATCH 1/5] Remove Cesium3DTilesetStatistics.textureReferenceCounterById destructure --- .../Source/Scene/Cesium3DTilesetStatistics.js | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/packages/engine/Source/Scene/Cesium3DTilesetStatistics.js b/packages/engine/Source/Scene/Cesium3DTilesetStatistics.js index 17b094f33ad0..c70b1c40acac 100644 --- a/packages/engine/Source/Scene/Cesium3DTilesetStatistics.js +++ b/packages/engine/Source/Scene/Cesium3DTilesetStatistics.js @@ -30,7 +30,7 @@ function Cesium3DTilesetStatistics() { // Memory statistics this.geometryByteLength = 0; this.texturesByteLength = 0; - this.texturesReferenceCounterById = {}; + this.texturesReferenceCounterById = new Map(); this.batchTableByteLength = 0; // batch textures and any binary metadata properties not otherwise accounted for } @@ -100,12 +100,12 @@ Cesium3DTilesetStatistics.prototype.incrementLoadCounts = function (content) { const textureIds = content.getTextureIds(); for (const textureId of textureIds) { const referenceCounter = - this.texturesReferenceCounterById[textureId] ?? 0; + this.texturesReferenceCounterById.get(textureId) ?? 0; if (referenceCounter === 0) { const textureByteLength = content.getTextureByteLengthById(textureId); this.texturesByteLength += textureByteLength; } - this.texturesReferenceCounterById[textureId] = referenceCounter + 1; + this.texturesReferenceCounterById.set(textureId, referenceCounter + 1); } } @@ -146,13 +146,13 @@ Cesium3DTilesetStatistics.prototype.decrementLoadCounts = function (content) { // total textures byte length const textureIds = content.getTextureIds(); for (const textureId of textureIds) { - const referenceCounter = this.texturesReferenceCounterById[textureId]; + const referenceCounter = this.texturesReferenceCounterById.get(textureId); if (referenceCounter === 1) { - delete this.texturesReferenceCounterById[textureId]; + this.texturesReferenceCounterById.delete(textureId); const textureByteLength = content.getTextureByteLengthById(textureId); this.texturesByteLength -= textureByteLength; } else { - this.texturesReferenceCounterById[textureId] = referenceCounter - 1; + this.texturesReferenceCounterById.set(textureId, referenceCounter - 1); } } } @@ -187,9 +187,7 @@ Cesium3DTilesetStatistics.clone = function (statistics, result) { statistics.numberOfTilesCulledWithChildrenUnion; result.geometryByteLength = statistics.geometryByteLength; result.texturesByteLength = statistics.texturesByteLength; - result.texturesReferenceCounterById = { - ...statistics.texturesReferenceCounterById, - }; + result.texturesReferenceCounterById = statistics.texturesReferenceCounterById; result.batchTableByteLength = statistics.batchTableByteLength; }; export default Cesium3DTilesetStatistics; From 599f11ae32178aa0c313d24d3a2d3c384d5662c7 Mon Sep 17 00:00:00 2001 From: Adam Beili Date: Tue, 7 Oct 2025 12:56:02 +0300 Subject: [PATCH 2/5] Why are credits getting cloned? This forces element creation every frame --- packages/engine/Source/Core/Credit.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/engine/Source/Core/Credit.js b/packages/engine/Source/Core/Credit.js index 98525c04c799..23b9caea8ed9 100644 --- a/packages/engine/Source/Core/Credit.js +++ b/packages/engine/Source/Core/Credit.js @@ -166,7 +166,8 @@ Credit.getIonCredit = function (attribution) { */ Credit.clone = function (credit) { if (defined(credit)) { - return new Credit(credit.html, credit.showOnScreen); + return credit; + // return new Credit(credit.html, credit.showOnScreen); } }; export default Credit; From e699c1cb4a3c2c5ce54919962b852fb045b6a00a Mon Sep 17 00:00:00 2001 From: Adam Beili Date: Tue, 7 Oct 2025 15:18:15 +0300 Subject: [PATCH 3/5] Minor traversal performance improvement --- packages/engine/Source/Scene/Cesium3DTilesetTraversal.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/engine/Source/Scene/Cesium3DTilesetTraversal.js b/packages/engine/Source/Scene/Cesium3DTilesetTraversal.js index fd13b76d9d4a..7ecc0681303f 100644 --- a/packages/engine/Source/Scene/Cesium3DTilesetTraversal.js +++ b/packages/engine/Source/Scene/Cesium3DTilesetTraversal.js @@ -188,6 +188,11 @@ function isOnScreenLongEnough(tile, frameState) { * @param {FrameState} frameState */ Cesium3DTilesetTraversal.updateTile = function (tile, frameState) { + if (tile._visitedFrame === frameState.frameNumber) { + // Prevents another pass from visiting the frame again + return; + } + Cesium3DTilesetTraversal.visitTile(tile, frameState); updateTileVisibility(tile, frameState); tile.updateExpiration(); @@ -279,6 +284,9 @@ function anyChildrenVisible(tile, frameState) { const child = children[i]; child.updateVisibility(frameState); anyVisible = anyVisible || child.isVisible; + if (anyVisible) { + break; + } } return anyVisible; } From 7585f647b3016d8aef0e923100bc95a4e1596612 Mon Sep 17 00:00:00 2001 From: Adam Beili Date: Tue, 7 Oct 2025 15:24:20 +0300 Subject: [PATCH 4/5] Support camera clamping choice at the scene level --- packages/engine/Source/Scene/Scene.js | 15 ++++++- .../Scene/ScreenSpaceCameraController.js | 44 ++++++++++++++++--- 2 files changed, 51 insertions(+), 8 deletions(-) diff --git a/packages/engine/Source/Scene/Scene.js b/packages/engine/Source/Scene/Scene.js index 16149ca8b23a..4cc389eb6290 100644 --- a/packages/engine/Source/Scene/Scene.js +++ b/packages/engine/Source/Scene/Scene.js @@ -3831,12 +3831,23 @@ function callAfterRenderFunctions(scene) { functions.length = 0; } +/** + * @param {Scene} scene + * @returns {Number|undefined} The height of the globe at the camera position, or undefined if the height cannot be determined. + */ function getGlobeHeight(scene) { - if (scene.mode === SceneMode.MORPHING) { + if ( + scene.mode === SceneMode.MORPHING || + scene._screenSpaceCameraController.collisionHeightReference === + HeightReference.NONE + ) { return; } const cartographic = scene.camera.positionCartographic; - return scene.getHeight(cartographic); + return scene.getHeight( + cartographic, + scene._screenSpaceCameraController.collisionHeightReference, + ); } function getMaxPrimitiveHeight(primitive, cartographic, scene) { diff --git a/packages/engine/Source/Scene/ScreenSpaceCameraController.js b/packages/engine/Source/Scene/ScreenSpaceCameraController.js index d4864da3e041..ccf9e788962c 100644 --- a/packages/engine/Source/Scene/ScreenSpaceCameraController.js +++ b/packages/engine/Source/Scene/ScreenSpaceCameraController.js @@ -24,6 +24,7 @@ import MapMode2D from "./MapMode2D.js"; import SceneMode from "./SceneMode.js"; import SceneTransforms from "./SceneTransforms.js"; import TweenCollection from "./TweenCollection.js"; +import HeightReference from "./HeightReference.js"; /** * Modifies the camera position and orientation based on mouse input to a canvas. @@ -265,13 +266,13 @@ function ScreenSpaceCameraController(scene) { : ellipsoid.minimumRadius * 1.175; this._minimumTrackBallHeight = this.minimumTrackBallHeight; /** - * When disabled, the values of maximumZoomDistance and minimumZoomDistance are ignored. - * Also used in conjunction with {@link Cesium3DTileset#enableCollision} to prevent the camera from moving through or below a 3D Tileset surface. - * This may also affect clamping behavior when using {@link HeightReference.CLAMP_TO_GROUND} on 3D Tiles. - * @type {boolean} - * @default true + * This value controls the height reference for the {@link ScreenSpaceCameraController} collision, which is used to limit the camera minimum and maximum zoom. + * When set to {@link HeightReference.NONE}, the camera can go underground, and the values of maximumZoomDistance and minimumZoomDistance are ignored. + * For all other values, the camera is constrained to be above the terrain and/or 3D Tiles (depending on {@link Cesium3DTileset#enableCollision}). + * @type {HeightReference} + * @default HeightReference.CLAMP_TO_GROUND */ - this.enableCollisionDetection = true; + this.collisionHeightReference = HeightReference.CLAMP_TO_GROUND; /** * The angle, relative to the ellipsoid normal, restricting the maximum amount that the user can tilt the camera. If undefined, the angle of the camera tilt is unrestricted. * @type {number|undefined} @@ -353,6 +354,27 @@ function ScreenSpaceCameraController(scene) { this._maximumUndergroundPickDistance = 10000.0; } +Object.defineProperties(ScreenSpaceCameraController.prototype, { + /** + * When disabled, the values of maximumZoomDistance and minimumZoomDistance are ignored. + * Also used in conjunction with {@link Cesium3DTileset#enableCollision} to prevent the camera from moving through or below a 3D Tileset surface. + * This may also affect clamping behavior when using {@link HeightReference.CLAMP_TO_GROUND} on 3D Tiles. + * @type {boolean} + * @default true + * @deprecated Use {@link ScreenSpaceCameraController#collisionHeightReference} instead. + */ + enableCollisionDetection: { + get: function () { + return this.collisionHeightReference !== HeightReference.NONE; + }, + set: function (value) { + this.collisionHeightReference = value + ? HeightReference.CLAMP_TO_GROUND + : HeightReference.NONE; + }, + }, +}); + function decay(time, coefficient) { if (time < 0) { return 0.0; @@ -556,6 +578,16 @@ const scratchZoomViewOptions = { orientation: new HeadingPitchRoll(), }; +/** + * + * @param {ScreenSpaceCameraController} object + * @param {*} startPosition + * @param {*} movement + * @param {*} zoomFactor + * @param {*} distanceMeasure + * @param {*} unitPositionDotDirection + * @returns + */ function handleZoom( object, startPosition, From f67f8dc8f780bafdd00c4893563907a3fccdabe8 Mon Sep 17 00:00:00 2001 From: Adam Beili Date: Wed, 8 Oct 2025 15:39:24 +0300 Subject: [PATCH 5/5] Matrix performance boost --- packages/engine/Source/Core/Matrix3.js | 52 ++++--- packages/engine/Source/Core/Matrix4.js | 187 +++++++++++-------------- 2 files changed, 109 insertions(+), 130 deletions(-) diff --git a/packages/engine/Source/Core/Matrix3.js b/packages/engine/Source/Core/Matrix3.js index 7a7ab6c3213e..7887f3c53ba3 100644 --- a/packages/engine/Source/Core/Matrix3.js +++ b/packages/engine/Source/Core/Matrix3.js @@ -35,28 +35,30 @@ import CesiumMath from "./Math.js"; * @see Matrix2 * @see Matrix4 */ -function Matrix3( - column0Row0, - column1Row0, - column2Row0, - column0Row1, - column1Row1, - column2Row1, - column0Row2, - column1Row2, - column2Row2, -) { - this[0] = column0Row0 ?? 0.0; - this[1] = column0Row1 ?? 0.0; - this[2] = column0Row2 ?? 0.0; - this[3] = column1Row0 ?? 0.0; - this[4] = column1Row1 ?? 0.0; - this[5] = column1Row2 ?? 0.0; - this[6] = column2Row0 ?? 0.0; - this[7] = column2Row1 ?? 0.0; - this[8] = column2Row2 ?? 0.0; +class Matrix3 extends Float64Array { + constructor( + column0Row0, + column1Row0, + column2Row0, + column0Row1, + column1Row1, + column2Row1, + column0Row2, + column1Row2, + column2Row2, + ) { + super(9); + this[0] = column0Row0 ?? 0.0; + this[1] = column0Row1 ?? 0.0; + this[2] = column0Row2 ?? 0.0; + this[3] = column1Row0 ?? 0.0; + this[4] = column1Row1 ?? 0.0; + this[5] = column1Row2 ?? 0.0; + this[6] = column2Row0 ?? 0.0; + this[7] = column2Row1 ?? 0.0; + this[8] = column2Row2 ?? 0.0; + } } - /** * The number of elements used to pack the object into an array. * @type {number} @@ -1671,9 +1673,7 @@ Matrix3.equalsEpsilon = function (left, right, epsilon) { * @type {Matrix3} * @constant */ -Matrix3.IDENTITY = Object.freeze( - new Matrix3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0), -); +Matrix3.IDENTITY = new Matrix3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0); /** * An immutable Matrix3 instance initialized to the zero matrix. @@ -1681,9 +1681,7 @@ Matrix3.IDENTITY = Object.freeze( * @type {Matrix3} * @constant */ -Matrix3.ZERO = Object.freeze( - new Matrix3(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0), -); +Matrix3.ZERO = new Matrix3(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0); /** * The index into Matrix3 for column 0, row 0. diff --git a/packages/engine/Source/Core/Matrix4.js b/packages/engine/Source/Core/Matrix4.js index f30b8a733905..80e0afeea836 100644 --- a/packages/engine/Source/Core/Matrix4.js +++ b/packages/engine/Source/Core/Matrix4.js @@ -53,40 +53,43 @@ import RuntimeError from "./RuntimeError.js"; * @see Matrix3 * @see Packable */ -function Matrix4( - column0Row0, - column1Row0, - column2Row0, - column3Row0, - column0Row1, - column1Row1, - column2Row1, - column3Row1, - column0Row2, - column1Row2, - column2Row2, - column3Row2, - column0Row3, - column1Row3, - column2Row3, - column3Row3, -) { - this[0] = column0Row0 ?? 0.0; - this[1] = column0Row1 ?? 0.0; - this[2] = column0Row2 ?? 0.0; - this[3] = column0Row3 ?? 0.0; - this[4] = column1Row0 ?? 0.0; - this[5] = column1Row1 ?? 0.0; - this[6] = column1Row2 ?? 0.0; - this[7] = column1Row3 ?? 0.0; - this[8] = column2Row0 ?? 0.0; - this[9] = column2Row1 ?? 0.0; - this[10] = column2Row2 ?? 0.0; - this[11] = column2Row3 ?? 0.0; - this[12] = column3Row0 ?? 0.0; - this[13] = column3Row1 ?? 0.0; - this[14] = column3Row2 ?? 0.0; - this[15] = column3Row3 ?? 0.0; +class Matrix4 extends Float64Array { + constructor( + column0Row0, + column1Row0, + column2Row0, + column3Row0, + column0Row1, + column1Row1, + column2Row1, + column3Row1, + column0Row2, + column1Row2, + column2Row2, + column3Row2, + column0Row3, + column1Row3, + column2Row3, + column3Row3, + ) { + super(16); + this[0] = column0Row0 ?? 0.0; + this[1] = column0Row1 ?? 0.0; + this[2] = column0Row2 ?? 0.0; + this[3] = column0Row3 ?? 0.0; + this[4] = column1Row0 ?? 0.0; + this[5] = column1Row1 ?? 0.0; + this[6] = column1Row2 ?? 0.0; + this[7] = column1Row3 ?? 0.0; + this[8] = column2Row0 ?? 0.0; + this[9] = column2Row1 ?? 0.0; + this[10] = column2Row2 ?? 0.0; + this[11] = column2Row3 ?? 0.0; + this[12] = column3Row0 ?? 0.0; + this[13] = column3Row1 ?? 0.0; + this[14] = column3Row2 ?? 0.0; + this[15] = column3Row3 ?? 0.0; + } } /** @@ -1929,41 +1932,23 @@ Matrix4.multiplyTransformation = function (left, right, result) { const right13 = right[13]; const right14 = right[14]; - const column0Row0 = left0 * right0 + left4 * right1 + left8 * right2; - const column0Row1 = left1 * right0 + left5 * right1 + left9 * right2; - const column0Row2 = left2 * right0 + left6 * right1 + left10 * right2; - - const column1Row0 = left0 * right4 + left4 * right5 + left8 * right6; - const column1Row1 = left1 * right4 + left5 * right5 + left9 * right6; - const column1Row2 = left2 * right4 + left6 * right5 + left10 * right6; - - const column2Row0 = left0 * right8 + left4 * right9 + left8 * right10; - const column2Row1 = left1 * right8 + left5 * right9 + left9 * right10; - const column2Row2 = left2 * right8 + left6 * right9 + left10 * right10; - - const column3Row0 = - left0 * right12 + left4 * right13 + left8 * right14 + left12; - const column3Row1 = - left1 * right12 + left5 * right13 + left9 * right14 + left13; - const column3Row2 = - left2 * right12 + left6 * right13 + left10 * right14 + left14; - - result[0] = column0Row0; - result[1] = column0Row1; - result[2] = column0Row2; + result[0] = left0 * right0 + left4 * right1 + left8 * right2; + result[1] = left1 * right0 + left5 * right1 + left9 * right2; + result[2] = left2 * right0 + left6 * right1 + left10 * right2; result[3] = 0.0; - result[4] = column1Row0; - result[5] = column1Row1; - result[6] = column1Row2; + result[4] = left0 * right4 + left4 * right5 + left8 * right6; + result[5] = left1 * right4 + left5 * right5 + left9 * right6; + result[6] = left2 * right4 + left6 * right5 + left10 * right6; result[7] = 0.0; - result[8] = column2Row0; - result[9] = column2Row1; - result[10] = column2Row2; + result[8] = left0 * right8 + left4 * right9 + left8 * right10; + result[9] = left1 * right8 + left5 * right9 + left9 * right10; + result[10] = left2 * right8 + left6 * right9 + left10 * right10; result[11] = 0.0; - result[12] = column3Row0; - result[13] = column3Row1; - result[14] = column3Row2; + result[12] = left0 * right12 + left4 * right13 + left8 * right14 + left12; + result[13] = left1 * right12 + left5 * right13 + left9 * right14 + left13; + result[14] = left2 * right12 + left6 * right13 + left10 * right14 + left14; result[15] = 1.0; + return result; }; @@ -2968,25 +2953,23 @@ Matrix4.inverseTranspose = function (matrix, result) { * @type {Matrix4} * @constant */ -Matrix4.IDENTITY = Object.freeze( - new Matrix4( - 1.0, - 0.0, - 0.0, - 0.0, - 0.0, - 1.0, - 0.0, - 0.0, - 0.0, - 0.0, - 1.0, - 0.0, - 0.0, - 0.0, - 0.0, - 1.0, - ), +Matrix4.IDENTITY = new Matrix4( + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, ); /** @@ -2995,25 +2978,23 @@ Matrix4.IDENTITY = Object.freeze( * @type {Matrix4} * @constant */ -Matrix4.ZERO = Object.freeze( - new Matrix4( - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - ), +Matrix4.ZERO = new Matrix4( + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, ); /**