Cesium 二三维视图联动
近期做了二三维视图联动,简单记录一下。
主要功能就是同时开启二维和三维视图一起查看。
大概思路就是新创建一个 2D 视图,相机实时同步(其实部分资源也应该同步,不过这需要做一个数据状态管理的功能,让数据在两个视图同步,懒得做了,后面要做资源管理的功能再说吧)。
二维和三维视图其实相机焦点是有区别的,因为二维视图只有平移和缩放,没有旋转,故如何正确找到三维视图中的相机焦点是关键。
方法一:获取屏幕中心坐标,转为世界坐标
// canvas 中心位置为相机焦点 let viewCenter = new Cesium.Cartesian2( Math.floor(this.#viewer3D.canvas.clientWidth / 2), Math.floor(this.#viewer3D.canvas.clientHeight / 2) ); // 给定中心的像素,获取世界位置 let worldPosition = this.#viewer3D.scene.camera.pickEllipsoid( viewCenter, this.#viewer3D.scene.globe.ellipsoid );
方法二:通过射线求交获取坐标
构建射线:
// 构建相机射线 let ray = new Cesium.Ray( this.#viewer3D.camera.positionWC, this.#viewer3D.camera.directionWC );
求射线与椭球交点:
方法1:
使用IntersectionTests,获取射线与椭球交点,注意,Intercal 属性包括两个标量,因为交点应该是两个,正面与反面,我们取正面的交点,然后通过 getPoint 方法获取具体坐标
let interval = Cesium.IntersectionTests.rayEllipsoid( ray, this.#viewer3D.scene.globe.ellipsoid ); let worldPosition = Cesium.Ray.getPoint(ray, interval.start);
方法2:
使用 global 中的 pick 方法直接获取
let worldPosition = this.#viewer3D.scene.globe.pick( ray, this.#viewer3D.scene )
其实方法还有很多,不一一列举了
获取到坐标后,我们需要获取缩放距离
Cartesian3 提供了计算方法,我们只需要计算出高度,设置 camera 即可
// 同步相机视角 if (Cesium.defined(worldPosition)) { // 计算高度 let distance = Cesium.Cartesian3.distance( worldPosition!, this.#viewer3D.camera.positionWC ); this.#viewer2D!.camera.lookAt( worldPosition!, new Cesium.Cartesian3(0, 0, distance) ); }
若想只保存 3D 视图的移动,让 2D 视图跟随,也可关闭 2D 视图的鼠标控制
// 禁止移动缩放 this.#viewer2D.scene.screenSpaceCameraController.enableZoom = false; this.#viewer2D.scene.screenSpaceCameraController.enableTranslate = false;
若想更换其他厂商的地图,直接在新建 viewer 时设置即可
完整版请移步LiZzhi/cesium-plugin (github.com),如果对您有帮助,请给我一颗star,谢谢。