一、Cesium中的深度图应用
深度图(depth map)是一种灰度图像,其存储的是每个像素点到相机的距离信息。
根据深度图信息,我们可以还原每个像素点的世界坐标。已知摄像机坐标 ,将每个像素点位置映射到世界坐标(以中心点相机位置为起始点进行偏移映射),然后根据距离平移到正确位置。
Cesium中从屏幕拾取坐标的相关操作就是基于深度图的,相关操作封装在Picking类中(源码位于Scene/Picking,我们使用Cesium深度图时,可以参考此类中的很多方法)
二、从深度图中解析坐标
当我们需要拾取指定范围内大量点坐标的时候,如果使用Cesium自带的Pick操作,性能会比较低。因为Cesium自带的Pick操作,每次只能拾取一个点,而每一次拾取都会执行一次离屏渲染,然后从深度图中还原坐标。所以这时候我们就可以结合离屏渲染和深度图,自己封装一次渲染批量拾取点的操作。比如现在有个需求,我们项目的研究区域是一个多山地区,现在需要从场景中获取这个区域的最高海拔和最低海拔。
一个最简单的思路就是对这个区域插值构建很多点,然后求取这些点的高度进行对比,批量拾取点的操作,通过离屏渲染和深度图的方法无疑是最优的选择。深度图渲染的操作,我们可以参考Picking类,总结如下:
a、创建一个Picking类,设置picking的相关信息
b、使用picking进行离屏渲染
c、从离屏渲染结果中获取结果
比如研究区的坐标范围如下:
let positions =[[110.91995822563997,30.018123228872216,966.0229851512511],[110.88602280929696,30.02746264223286,992.25539021267],[110.87475288470748,30.00061781074165,673.7384986001304],[110.88525405115537,29.97371359878412,260.02837273046464],[110.89486388986987,29.962314482553314,639.5892410593838],[110.91982562243348,29.973771216309125,722.7884451776592],[110.92939046684434,30.003520348332533,1077.5538168551436]] ;
positions = Cesium.Cartesian3.fromDegreesArrayHeights([].concat.apply([], positions));
let entity = new Cesium.Entity({
polygon: {
hierarchy: new Cesium.PolygonHierarchy(positions),
material: Cesium.Color.BLUE.withAlpha(0.6)
},
})
viewer.entities.add(entity);
//研究区的矩形范围 (此方法获取的范围比实际范围稍大,但是不影响)
let boundingRectangle = Cesium.BoundingRectangle.fromRectangle(Cesium.Rectangle.fromCartesianArray(positions));
let range = Math.max(boundingRectangle.width, boundingRectangle.height);//宽高的最大值
1、创建离屏渲染的相机:为了方便计算,我们一般用正交相机,将相机置于研究区的上空,方向从上往下。
//创建相机 (正交投影)
const offscreenCamera = new Cesium.Camera(viewer.scene);
//设置相机的位置
let center = new Cesium.Cartesian3();
let n = positions.length;
let centerPosition = new Cesium.Cartesian3();
positions.forEach(p => {
centerPosition = Cesium.Cartesian3.add(centerPosition, p, centerPosition);
})
centerPosition = Cesium.Cartesian3.multiplyByScalar(centerPosition, 1 / n, centerPosition);//中心点
//获取中心点的法线
let normal = Cesium.Ellipsoid.WGS84.geodeticSurfaceNormal(centerPosition);
//中心点向上平移5000米
centerPosition = Cesium.Cartesian3.add(centerPosition, Cesium.Cartesian3.multiplyByScalar(normal, 5000, new Cesium.Cartesian3()), centerPosition);
offscreenCamera.position = centerPosition;
//相机方向 从上往下看
offscreenCamera.direction =