diff --git a/src/scene/CesiumGlobe.js b/src/scene/CesiumGlobe.js index 4289847..581a595 100644 --- a/src/scene/CesiumGlobe.js +++ b/src/scene/CesiumGlobe.js @@ -383,6 +383,10 @@ export class CesiumGlobe { enu: new Cesium.Matrix4(), invEnu: new Cesium.Matrix4(), localDir: new Cesium.Cartesian3(), + enuUp: new Cesium.Cartesian3(), + u0: new Cesium.Cartesian3(), + un: new Cesium.Cartesian3(), + cross: new Cesium.Cartesian3(), }; handler.setInputAction((movement) => { @@ -477,9 +481,37 @@ export class CesiumGlobe { Cesium.Matrix4.multiplyByPointAsVector(sc.invEnu, dir, sc.localDir); const heading = Math.atan2(sc.localDir.x, sc.localDir.y); const pitch = Math.asin(sc.localDir.z); + + // 计算“北朝上”所需的 roll:把 roll=0 的 up(水平线方向)滚转到“世界 Z 投影”的 up, + // 这样倾斜时 up 不随方向转动(否则会又倾斜又旋转) + const dz = dir.z; + sc.un.x = -dir.x * dz; + sc.un.y = -dir.y * dz; + sc.un.z = 1 - dz * dz; + if (Cesium.Cartesian3.magnitudeSquared(sc.un) < 1e-12) { + Cesium.Cartesian3.clone(s.up, sc.un); + } else { + Cesium.Cartesian3.normalize(sc.un, sc.un); + } + Cesium.Cartesian3.normalize(sc.newPos, sc.enuUp); // 径向 = newPos 处的“上” + const d0 = Cesium.Cartesian3.dot(sc.enuUp, dir); + sc.u0.x = sc.enuUp.x - d0 * dir.x; + sc.u0.y = sc.enuUp.y - d0 * dir.y; + sc.u0.z = sc.enuUp.z - d0 * dir.z; + let roll = 0; + if (Cesium.Cartesian3.magnitudeSquared(sc.u0) > 1e-12) { + Cesium.Cartesian3.normalize(sc.u0, sc.u0); + Cesium.Cartesian3.cross(sc.u0, sc.un, sc.cross); + const sin = + Cesium.Cartesian3.magnitude(sc.cross) * + Math.sign(Cesium.Cartesian3.dot(sc.cross, dir)); + const cos = Cesium.Cartesian3.dot(sc.u0, sc.un); + roll = Math.atan2(sin, cos); + } + camera.setView({ destination: Cesium.Cartesian3.clone(sc.newPos), - orientation: { heading, pitch, roll: 0 }, + orientation: { heading, pitch, roll }, }); }