右键环视改为原地倾倒(直接算 heading/pitch,修复近天底奇点翻转),并关闭相机惯性
This commit is contained in:
+17
-83
@@ -223,6 +223,10 @@ export class CesiumGlobe {
|
|||||||
modifier: Cesium.KeyboardEventModifier.CTRL,
|
modifier: Cesium.KeyboardEventModifier.CTRL,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
// 关闭相机惯性:避免左键旋转释放后的余力在右键环视时叠加,产生“两套机制打架”
|
||||||
|
controller.inertiaSpin = 0;
|
||||||
|
controller.inertiaTranslate = 0;
|
||||||
|
controller.inertiaZoom = 0;
|
||||||
|
|
||||||
// 阻止右键弹出浏览器菜单
|
// 阻止右键弹出浏览器菜单
|
||||||
scene.canvas.addEventListener('contextmenu', (e) => e.preventDefault());
|
scene.canvas.addEventListener('contextmenu', (e) => e.preventDefault());
|
||||||
@@ -360,65 +364,17 @@ export class CesiumGlobe {
|
|||||||
viewer.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);
|
viewer.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 右键环视:以点击处为球心,左右旋转 ±40°、上下倾角 ±20°,松开自动归位。
|
// 右键环视:相机“原地倾倒”(位置不动,只改视线方向)。左右 = 经度方向、上下 = 纬度方向,强制北朝上。
|
||||||
// 不用原生 tilt(RIGHT_DRAG):原生 tilt 会绕点击点做轨道移动,heading/pitch
|
// 关键:直接算 heading/pitch 传给 setView,绕过 setView 在近天底处用 up 反推 heading 的奇点——
|
||||||
// 是相对“不断移动的相机位置”计算的,无法干净地限制成 40°/20°。
|
// 否则初期的小角度倾斜会被翻转(表现为“向北平移”)。
|
||||||
_setupLookAround() {
|
_setupLookAround() {
|
||||||
const scene = this.viewer.scene;
|
const scene = this.viewer.scene;
|
||||||
const camera = this.viewer.camera;
|
const camera = this.viewer.camera;
|
||||||
const handler = new Cesium.ScreenSpaceEventHandler(scene.canvas);
|
const handler = new Cesium.ScreenSpaceEventHandler(scene.canvas);
|
||||||
this._lookState = null;
|
this._lookState = null;
|
||||||
this._orbitScratch = {
|
|
||||||
offset: new Cesium.Cartesian3(),
|
|
||||||
upAxis: new Cesium.Cartesian3(),
|
|
||||||
eastAxis: new Cesium.Cartesian3(),
|
|
||||||
northAxis: new Cesium.Cartesian3(),
|
|
||||||
qAz: new Cesium.Quaternion(),
|
|
||||||
qEl: new Cesium.Quaternion(),
|
|
||||||
q: new Cesium.Quaternion(),
|
|
||||||
rotMat: new Cesium.Matrix3(),
|
|
||||||
newOffset: new Cesium.Cartesian3(),
|
|
||||||
newPos: new Cesium.Cartesian3(),
|
|
||||||
dir: new Cesium.Cartesian3(),
|
|
||||||
upProj: new Cesium.Cartesian3(),
|
|
||||||
};
|
|
||||||
|
|
||||||
handler.setInputAction((movement) => {
|
handler.setInputAction((movement) => {
|
||||||
// 旋转中心 = 相机当前注视的屏幕中心点(与原生 tilt 一致),
|
|
||||||
// 而不是点击点:用点击点会导致一拖动就“瞬移”到点击处。
|
|
||||||
// 取“地形表面”点而不是椭球点:相机看到的是地形,若用椭球点做球心,
|
|
||||||
// 视觉中心(地形)会随旋转漂移,产生“两套体系”的错觉。
|
|
||||||
const canvas = scene.canvas;
|
|
||||||
const center = Cesium.Cartesian2.fromElements(
|
|
||||||
canvas.clientWidth / 2,
|
|
||||||
canvas.clientHeight / 2,
|
|
||||||
);
|
|
||||||
const ray = camera.getPickRay(center);
|
|
||||||
let pivot = scene.globe.pick(ray, scene);
|
|
||||||
if (!Cesium.defined(pivot)) {
|
|
||||||
pivot = camera.pickEllipsoid(center, scene.globe.ellipsoid);
|
|
||||||
}
|
|
||||||
if (!Cesium.defined(pivot)) return;
|
|
||||||
const sc = this._orbitScratch;
|
|
||||||
const offset = Cesium.Cartesian3.subtract(camera.position, pivot, sc.offset);
|
|
||||||
const upAxis = Cesium.Cartesian3.normalize(pivot, sc.upAxis);
|
|
||||||
const eastAxis = Cesium.Cartesian3.cross(Cesium.Cartesian3.UNIT_Z, pivot, sc.eastAxis); // 绕它转 = 上下拖动(纬度方向倾倒)
|
|
||||||
if (Cesium.Cartesian3.magnitudeSquared(eastAxis) < 1e-12) {
|
|
||||||
eastAxis.x = 1;
|
|
||||||
eastAxis.y = 0;
|
|
||||||
eastAxis.z = 0; // 极点退化兜底
|
|
||||||
} else {
|
|
||||||
Cesium.Cartesian3.normalize(eastAxis, eastAxis);
|
|
||||||
}
|
|
||||||
const northAxis = Cesium.Cartesian3.normalize(
|
|
||||||
Cesium.Cartesian3.cross(upAxis, eastAxis, sc.northAxis), // 绕它转 = 左右拖动(经度方向倾倒)
|
|
||||||
sc.northAxis,
|
|
||||||
);
|
|
||||||
this._lookState = {
|
this._lookState = {
|
||||||
pivot: Cesium.Cartesian3.clone(pivot),
|
|
||||||
startOffset: Cesium.Cartesian3.clone(offset),
|
|
||||||
eastAxis: Cesium.Cartesian3.clone(eastAxis),
|
|
||||||
northAxis: Cesium.Cartesian3.clone(northAxis),
|
|
||||||
position: Cesium.Cartesian3.clone(camera.position),
|
position: Cesium.Cartesian3.clone(camera.position),
|
||||||
direction: Cesium.Cartesian3.clone(camera.direction),
|
direction: Cesium.Cartesian3.clone(camera.direction),
|
||||||
up: Cesium.Cartesian3.clone(camera.up),
|
up: Cesium.Cartesian3.clone(camera.up),
|
||||||
@@ -438,7 +394,7 @@ export class CesiumGlobe {
|
|||||||
s.lastY = movement.endPosition.y;
|
s.lastY = movement.endPosition.y;
|
||||||
s.azimuth = Cesium.Math.clamp(s.azimuth + dx * LOOK_RATE, -MAX_LOOK_ROT, MAX_LOOK_ROT);
|
s.azimuth = Cesium.Math.clamp(s.azimuth + dx * LOOK_RATE, -MAX_LOOK_ROT, MAX_LOOK_ROT);
|
||||||
s.elevation = Cesium.Math.clamp(s.elevation + dy * LOOK_RATE, -MAX_LOOK_TILT, MAX_LOOK_TILT);
|
s.elevation = Cesium.Math.clamp(s.elevation + dy * LOOK_RATE, -MAX_LOOK_TILT, MAX_LOOK_TILT);
|
||||||
this._orbitCamera(s);
|
this._tiltCamera(s);
|
||||||
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
|
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
|
||||||
|
|
||||||
handler.setInputAction(() => {
|
handler.setInputAction(() => {
|
||||||
@@ -454,37 +410,15 @@ export class CesiumGlobe {
|
|||||||
this._lookHandler = handler;
|
this._lookHandler = handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 按累计角度(已限制)把相机绕点击点倾倒:左右 = 经度方向(绕南北轴),
|
// 原地倾倒:由累计的经度角(azimuth)/纬度角(elevation)直接求 heading/pitch,roll 固定 0(北朝上)
|
||||||
// 上下 = 纬度方向(绕东西轴);up 始终强制北朝上。
|
_tiltCamera(s) {
|
||||||
_orbitCamera(s) {
|
const el = s.elevation;
|
||||||
const camera = this.viewer.camera;
|
const az = s.azimuth;
|
||||||
const sc = this._orbitScratch;
|
const heading = Math.atan2(-Math.cos(el) * Math.sin(az), Math.sin(el));
|
||||||
Cesium.Quaternion.fromAxisAngle(s.northAxis, s.azimuth, sc.qAz);
|
const pitch = Math.asin(-Math.cos(el) * Math.cos(az));
|
||||||
Cesium.Quaternion.fromAxisAngle(s.eastAxis, s.elevation, sc.qEl);
|
this.viewer.camera.setView({
|
||||||
Cesium.Quaternion.multiply(sc.qEl, sc.qAz, sc.q);
|
destination: s.position,
|
||||||
Cesium.Matrix3.fromQuaternion(sc.q, sc.rotMat);
|
orientation: { heading, pitch, roll: 0 },
|
||||||
Cesium.Matrix3.multiplyByVector(sc.rotMat, s.startOffset, sc.newOffset);
|
|
||||||
Cesium.Cartesian3.add(s.pivot, sc.newOffset, sc.newPos);
|
|
||||||
const dir = Cesium.Cartesian3.normalize(
|
|
||||||
Cesium.Cartesian3.subtract(s.pivot, sc.newPos, sc.dir),
|
|
||||||
sc.dir,
|
|
||||||
);
|
|
||||||
// 强制北朝上:up = 世界 Z 投影到垂直于视线的方向
|
|
||||||
const z = dir.z;
|
|
||||||
sc.upProj.x = -dir.x * z;
|
|
||||||
sc.upProj.y = -dir.y * z;
|
|
||||||
sc.upProj.z = 1 - z * z;
|
|
||||||
if (Cesium.Cartesian3.magnitudeSquared(sc.upProj) < 1e-12) {
|
|
||||||
Cesium.Cartesian3.clone(s.up, sc.upProj); // 垂直俯视时北朝上无定义,回退起始 up
|
|
||||||
} else {
|
|
||||||
Cesium.Cartesian3.normalize(sc.upProj, sc.upProj);
|
|
||||||
}
|
|
||||||
camera.setView({
|
|
||||||
destination: Cesium.Cartesian3.clone(sc.newPos),
|
|
||||||
orientation: {
|
|
||||||
direction: Cesium.Cartesian3.clone(dir),
|
|
||||||
up: Cesium.Cartesian3.clone(sc.upProj),
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user