需求
有如下需求,根据接口返回来的经纬度坐标,要正确的在three.js中的三维场景中将数据渲染出来,或者是根据经纬度坐标绘制出物体的运动轨迹
分析
我们都知道三维three.js的渲染用的是右手笛卡坐标,并没有像cesium那样给我们提供经纬度和笛卡尔坐标的转换方式,转换的时候注意坐标的方向(是否涉及到旋转),缩放,坐标原点等
那我们可以借助cesium的方法将经纬度转成的卡尔坐标,然后在three.js或者babylon.js进行渲染吗?
答案是可以的,但是存在一个问题,就是坐标轴指向、原点都是不一样的,光靠一个坐标点是没办法定位,还需要坐标系的信息,在这些坐标系中,一旦涉及到旋转,那么难度将以指数的形式增加。
在three.js右手笛卡尔中表示高度是Y值,但是在cesium的笛卡尔是没办法表示高度的,只能是用经纬度表示例如(lon,lat,height),坐标系信息可以看下面的图
cesium WGS84坐标系
cesium笛卡尔坐标系
three.js坐标系
举个例子,比如cesium开发的系统,用的是cesium的笛卡尔坐标系,一辆车朝着某个方向运动,比如朝着正北方向运动,而你的系统中,比如是three.js的系统,你很难根据经纬度或者cesium的笛卡尔坐标信息将两边的运动进行同步,那怎么办呢?不妨看看下面的方法吧
实现步骤如下
步骤一:设置原点,经纬度转墨卡托,平移,墨卡托转three.js的右手笛卡尔
既然如此那我们可以手动将经纬度转成墨卡托;然后将转换后的经度对应成three.js中位置的x,维度对应成three.js中的z值即可,但是用过cesium或者openlayers的兄弟都应该知道,经过转换的坐标,数值上是非常大的,这对我们的无论是计算还是啥的都不方便,我们可以先指定一个坐标原点,接下里输入的坐标,都以这个原点定位,相当于做了一个平移,这个才坐标转换是常用的手段
步骤二:正确缩放
在坐标轴指向和尺度上来看,首先是指向,当时向着正东方向运动时经纬度的经度会增加,此时对于的three.js中的x会增加,维度亦是如此
重点:WGS84坐标经纬度转成墨卡托,再放到三维场景定位存在一定的缩放,缩放系数要根据场景的大小,如何确定呢,比如在一些卫星底图下载软件,你要下载直径5公里的底图,但是发现得到的是大于5公里的,那缩放系数就是实际得到的直径出于输入的直径,当我们要一比一还原实际场景的时候,建模时也要按照这个系数进行缩放;
接下来是代码实现,代码每个方法的命名就是注释,应该挺好看懂的,分别有两个版本,一个是通过手动将经纬度转墨卡托(伪墨卡托3857),另一个是通过proj4
步骤三:旋转
这里不涉及到旋转,跳过
以下babylon.js版本(左手坐标系),three.js(右手坐标系)
export default class CoordinateConverter {
private centerMercX: number;
private centerMercY: number;
constructor(private centerLng: number, private centerLat: number) {
// 将中心点的经纬度转换成墨卡托坐标
const { mercX, mercY } = this.latLngToMercator(centerLng, centerLat);
this.centerMercX = mercX;
this.centerMercY = mercY;
}
// 经纬度转换为 Web 墨卡托
private latLngToMercator(lng: number, lat: number): { mercX: number, mercY: number } {
const mercX = (lng * 20037508.34) / 180;
let mercY = Math.log(Math.tan(((90 + lat) * Math.PI) / 360)) / (Math.PI / 180);
mercY = (mercY * 20037508.34) / 180;
return { mercX, mercY };
}
// 墨卡托坐标转换为 Babylon.js 的 xz 平面坐标
private mercatorToBabylon(mercX: number, mercY: number): { x: number, z: number } {
const x = (mercX - this.centerMercX ) * -2.53;
const z = (mercY - this.centerMercY) * -2.53;
return { x, z };
}
// 将经纬度转换为 Babylon.js 的 xz 平面坐标
public latLngToBabylon(lng: number, lat: number): { x: number, z: number } {
const { mercX, mercY } = this.latLngToMercator(lng, lat);
return this.mercatorToBabylon(mercX, mercY);
}
}
为什么上面说要乘以一个缩放系数-2.53,正负修正坐标系轴指向(babylon.js),three.js的方向不一样正负值要改一下,缩放值这个是手动调整的,建模的时候被缩放了吧