From 13f8023621aa7b8cbf8f230409b276c3e7764f43 Mon Sep 17 00:00:00 2001 From: fukunee Date: Sat, 19 Sep 2026 15:45:54 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8F=B3=E9=94=AE=E7=8E=AF=E8=A7=86=EF=BC=9A?= =?UTF-8?q?=E8=AE=A1=E7=AE=97=E5=8C=97=E6=9C=9D=E4=B8=8A=E6=89=80=E9=9C=80?= =?UTF-8?q?=E7=9A=84=20roll=EF=BC=8C=E6=B6=88=E9=99=A4=E5=80=BE=E6=96=9C?= =?UTF-8?q?=E6=97=B6=E7=9A=84=E9=99=84=E5=8A=A0=E6=97=8B=E8=BD=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/scene/CesiumGlobe.js | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) 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 }, }); }