three-tile 是一个开源的轻量级三维瓦片库,它基于threejs使用typescript开发,提供一个三维地形模型,能轻松给你的应用增加三维瓦片地图。
项目地址:GitHub - sxguojf/three-tile: 3D tile map using threejs
示例地址:GitHub - sxguojf/three-tile-example: three-tile Examples
接上篇,three-tile开发: 2. 选择或定义适合的地图瓦片服务-CSDN博客
三维开发中,我们并不能像二维gis那样指定地图的中心经纬度和缩放系数来控制地图大小和位置,如cesium中使用viewer.flyTo()、camera.flyTo()、camera.flyToBoundingSphere()等方法漫游到指定位置,主要是通过调整摄像机位置和姿态来完成。
因three-tile本身只是个地图模型,摄像机、控制器等都是用户自定义的,所以这部分需要自己实现。这里讲解通过控制摄像机位置和摄像机目标点来实现。
1. 坐标转换
三维场景的坐标是个无单位量,对于地图上某点,相对场景坐标,用经纬度海拔高度表述更适合人类,可以将摄像机移动到某经纬度更清楚明了,所以需要学会将经纬度转换为场景坐标(世界坐标),TileMap提供两个坐标转换函数:
TileMap.geo2pos():将经纬度海拔高度转换为地图模型坐标
TileMap.pos2geo(): 将地图模型坐标转换为经纬度海拔高度。
注意,这里参数和返回值都是地图模型坐标,有转为为世界坐标,还需要使用three的localToWorld和worldToLocal。
2. 直接调整地图位置
// 不动画,直接跳转定位
document.querySelector("#jump")!.addEventListener("click", () => {
const newCenterPos = map.localToWorld(map.geo2pos(new Vector3(107.8, 34.0, 0)));
const newCameraPos = map.localToWorld(map.geo2pos(new Vector3(107.9, 34.0, 7.8)));
console.log(newCameraPos, newCenterPos);
viewer.camera.position.copy(newCameraPos);
viewer.controls.target.copy(newCenterPos);
viewer.controls.dispatchEvent({ type: "change", target: viewer.controls });
});
我们计算两个坐标,先将经纬度转换为地图模型坐标,再转换为世界坐标,然后修改摄像机位置和控制器中心位置,最后发出控制器改变事件以生效:
- newCenterPos: 地图中心坐标,也是控制器中心坐标,它决定了摄像机向那个位置看。
- newCameraPos:摄像机坐标。就是你站在那个位置看地球
3. 定时器动画调整
cesium的地图位置调整提供很酷的动画漫游效果,three-tile里也可以使用定时器简单模拟:
// 使用定时器进行地图漫游动画定位
document.querySelector("#timer")!.addEventListener("click", () => {
const newCenterPos = map.localToWorld(map.geo2pos(new Vector3(110, 34, 0)));
viewer.controls.target.copy(newCenterPos);
const camerPos = viewer.camera.position;
camerPos.set(centerGeo.x, centerGeo.y, 1e4);
const timer = setInterval(() => {
camerPos.add(new Vector3(0, -200, 0));
if (camerPos.y < 2000) {
clearInterval(timer);
}
}, 20);
});
就是定时调整摄像机高度,上面的动画很简陋,仅定时修改了摄像机的y坐标。
4. 使用Tween动态调整
three中内置了Tween库,使用它可以做出更酷的动画,推荐用Tween,代码比较简单,这里就不贴了。
5. 如何方便地取得需要的两个位置坐标
虽然使用经纬度控制摄像机和地图中心位置比使用世界坐标或者摄像机方向要直观很多,但三维场景下,我们通常想精确地以某角度看向某个目标,找准这两坐标还是很困难,你可以先使用鼠标调整好地图位置角度,然后用代码读取摄像机和中心坐标输出记录下来。我想你这cesium中也会遇到同样问题,也是同样的解决方法。
示例程序中,地图下方输出了地图的各种坐标参数,可直接复制使用