山海鲸可视化

GIS融合之路(三)CesiumJS和ThreeJS相机同步

同样在这篇文章开始前重申一下:山海鲸并没有使用 ThreeJS 引擎。但由于 ThreeJS 引擎使用广泛,下文中直接用ThreeJS 同 CesiumJS 的整合方案代替山海鲸中 3D 引擎和 CesiumJS 整合。

系列传送门:
山海鲸可视化:GIS 融合之路(一)技术选型 CesiumJS/loaders.gl/iTowns
山海鲸可视化:GIS 融合之路(二)CesiumJS 和 ThreeJS 深度缓冲区整合

按照惯例,文章开始前先自夸,大家可以参考一下山海鲸中相机整合的效果。详细的内容可以前往这篇视频教程:
【山海鲸可视化 GIS 系统】第九课 GIS 相机控制

感兴趣朋友也欢迎下载软件试一试:
山海鲸可视化-一站式数字孪生开发平台-海量数据可视化大屏模板

相机的整合分为三个部分,分别是:

  1. 同步相机 fov
  2. 同步相机位置
  3. 同步相机方向

一、同步相机 fov

我们先来处理最简单的相机 fov,我们先看下相机的 fov 是什么:

相机的 fov 示意

可以看出,相机的 fov 就是相机的视角宽度和高度,我们日常所说的广角相机、鱼眼相机就是 fov 很大的相机。而相机主要有两个 fov 参数,一个是横向的 vfov,一个是纵向的 hfov,因此我们只需要把两个相机自己的 fov 对应设置上即可,我们先看一下两边的文档中分别怎么描述自己的 fov 的:


CesiumJS 中的 fov


ThreeJS 中的 fov

此处一定要敲黑板,fov 本身是一个很简单的概念,理论上直接同步两边相机的 fov 就可以完成。但这里面起码有两个坑,一个是Cesium 用的是 radians,而threejs 用的是 degrees,需要做一次转换。另外 CesiumJS 有两个 fov,和 threejs 对应的是 fovy。这两个问题处理好了就简单了,代码也很简单。

1
THREE.camera.fov = Cesium.Math.toDegrees(CESIUM.viewer.camera.frustum.fovy)

当然山海鲸采用的是双向同步,反过来的话只需要根据文档内容将山海鲸引擎的 fov 赋值给 CESIUM 即可。

二、同步相机位置

搞定了相机 fov,下一步就是同步相机的位置。同步相机位置就得先了解一下 Cesium 的坐标系,我们主要要用到 Cesium 的两套坐标系,一个是地心坐标,一个是经纬度坐标系。这两个坐标系间 Cesium 提供了标准的转换方法。

而 Cesium 同 Threejs 的坐标转换时,Threejs 使用的坐标系对应在 Cesium 中实际上是东北上坐标系,这两个坐标系的关系如图所示:

Cesium 三种坐标系

Cesium 也提供的标准的函数来获得东北上坐标系和地心坐标系的转换矩阵,因此我们可以通过如下代码将 Threejs 中的坐标转换为 Cesium 中的地心坐标系,同理也可以反过来将 Cesium 中的地心坐标系转换为东北天坐标系,也就是 threejs 中的坐标系,实现坐标系的双向转换。

1
2
3
let origin = Cesium.Cartographic.toCartesian(originCartographic)
let transform = Cesium.Transforms.eastNorthUpToFixedFrame(origin);
let result1 = Cesium.Matrix4.multiplyByPoint(transform, cameraPosition);

山海鲸中需要提供了两种控制方式,一种是控制 Threejs 相机同步到 Cesium 相机中,一种是控制 Cesium 相机同步到 Threejs 中。所以最后值得注意的就是在第一种方式中需要将 Cesium 相机自己的控制个关闭掉,这个也很简单,只需要调用以下代码即可:

1
scene.screenSpaceCameraController.enableInputs = false;

最后,值得注意的是 Cesium 除了提供3d 球面绘制模式( Cesium.SceneMode.SCENE3D)以外,还提供了2.5d 的绘制模式(Cesium.SceneMode.COLUMBUS_VIEW),在 COLUMBUS_VIEW 的模式下,则需要做一步 web 墨卡托坐标的投影才能够完成坐标转换。

好了至此,我们终于实现了双向的相机同步。完成了这些,GIS 系统算是正式可以在山海鲸中使用了。而且后面的章节我们会提到,山海鲸开放了整合 CesiumJS 的接口,因此只需要开启反向相机同步,即可无缝的将之前的 CesiumJS 代码迁移过来了。虽然整合成功了,但是 CesiumJS 依然是 CesiumJS 的样子,并没有任何变化,如果是这样,为什么不直接用 CesiumJS,干嘛还有整合呢?

我们当然不能就此止步,作为一个对客户负责的技术负责人,客户不仅要求山海鲸可以加载所有的 GIS 数据,还拿效果和 UE 对比,觉得 Cesium For Unreal 的视觉效果更好看。要求我们把 Unreal 的效果搬到 Web 上来,什么,你说不可能?没有条件,创造条件也要上。只能再苦一苦开发团队了。