更新于2017/5/31
Cesium地形简介
Cesium支持多种地形格式和服务,Cesium的母公司AGI提供了两份免费使用的地形数据,一个叫“STK World Terrain”,它是高分辨率,基于mesh的地形数据(若Cesium提供的STK服务地址用不了,将其改成https://assets02.agi.com/stk-terrain/world);另一个叫“PAMap Terrain”,处于美国宾夕法尼亚州的一处地形数据。
在Cesium中,地形和影像是不同处理的,默认是影像覆盖在地形上,任何的影像的provider都可以在任何的地形provider上使用。
Cesium的地形服务也包括地形光照以及水流。默认情况下,地形服务是不会将光照或者水流据随着地形瓦片一起发到前端的,当我们初始化CesiumTerrainProvider类的时候可以设置是否需要这些数据。
通过下面的方式可以添加地形光照和水流效果。
var terrainProvider = new Cesium.CesiumTerrainProvider({
url : '//assets.agi.com/stk-terrain/world',
requestVertexNormals: true});
viewer.terrainProvider = terrainProvider;
viewer.scene.globe.enableLighting = true;
水流效果:
随着时间的变化,海浪可以在太阳照射下显示高光效果。
Cesium的各种地形Provider
Cesium支持多种地形provider来接收地形数据,大多数provider使用rest类型的接口来请求地形瓦片。各种地形provider在请求方式和地形数据的组织上会有所不同。以下几种是Cesium支持的地形provider:
Cesium Terrain Server——高分辨率的全球地形数据,支持地形光照和水流效果。地形瓦片提交给客户端的数据的格式用的是quantized-mesh v1.0。详情见Cesium里的CesiumTerrainProvider。
Esri ArcGIS Image Server——从Esri影像服务里的高度图中产生地形数据集。详情见Cesium里的ArcGisImageServerTerrainProvider.
VR-TheWorld Server——从一个VR-TheWorld服务里的高度图中产生地形数据。它们的托管服务器有全球90米的数据,包括深度测量。详情见Cesium里的VRTheWorldTerrainProvider.(这个没用过,不了解)
Ellipsoid——是Cesium默认的地形provider,是一个光滑的椭球面,没有现实的地形,地形高度为0。
Heightmap格式介绍
heightmap 1.0的规则格式是一种简单多分辨率四叉树,瓦片后缀为.terrain格式,一个高程数据集的瓦片url类似于:
http://cesiumjs.org/tilesets/terrain/smallterrain/{z}/{x}/{y}.terrain。可惜现在访问不到了,应该是Cesium将数据下撤了。
cesium的这种高程数据集瓦片分割方式为第0级有两个瓦片,分别是:
(-180,-90)——>(0,90) 瓦片路径: http://cesiumjs.org/tilesets/terrain/smallterrain/0/0/0/terrain
(0,-90)——>(180,90) 瓦片路径: http://cesiumjs.org/tilesets/terrain/smallterrain/0/1/0/terrain
其他层瓦片按照规则以此类推。
高程瓦片大小为65*65,这些瓦片都是经过gzip压缩的,解压之后,它们的大小至少为8452字节。文件内容是一个由北到南,从西到东的简单的16位的、小端、整型高度值的数组。前两个字节是瓦片第一行第一列像素的高度值,接下来两个字节是瓦片第一行第二列的像素的高度值.以此类推.....传输过来的数据总共是65*65*2=8450字节。8452-8450=2字节。这样的话还剩两个字节,这其中第一个字节是代表当前瓦片子瓦片的标识,第二个字节代表是否添加水流效果,0代表陆地,255就代表水,介于0到255的也被允许,那是为了支持海岸线抗锯齿效果。
构造一个HeightmapTerrainData时,里面有个参数是structure对象,这里面描述了高程数据的结构,它包含的属性如下:
heightScale:高度缩放倍数,默认1.0.
heightOffset:高度偏移量,默认0.0.
elementsPerHeight: 在缓冲区里组成一个单一高度样本的元素的数量。通常是1,表明每个元素都是一个独立的高度。如果大于1,这一数字的元素共同构成一个高度样本,这个是根据elementMultiplier和isBigEndian两个属性来计算的。
stride:步长,从一个高度的第一个元素到下一个高度的第一个元素的跳过的数量。默认为1.
elementMultiplier:当stride(步长)值大于1时elementMultiplier被用来计算高度值。例如,如果stride为4,elementMultiplier为256,那么高度就按如下计算:height=buffer[index]+buffer[index+1]*256+buffer[index+2]*256*256+buffer[index+3]*256*256*256。在这里是假设isBigEndian属性是false.如果设为true,元素顺序需要颠倒一下。默认值是256.0。
isBigEndian:大小端设置。
lowestEncodedHeight:这个最小值能够被存储到高度buffer里。在进行heightScale和heightOffset计算后的任意高度值如果小于该值,都会替换成此值。
heighestEncodedHeight:同上,不过是最大值。
Cesium地形加载流程
在Cesium中,支持STK和Small Terrain两种地形格式,这两种地形数据在接收后都会分别封装成QuantizedMeshTerrainData或HeightMapTerrainData,这两种地形文件的格式后缀都是.terrain。
Cesium中有一个sampleTerrain类,这个类首先是通过请求一个地形provider获取的瓦片,经采样、插值后,得到一个位置的数组,通过这个数组来查询地形高度。插值在指定层级下会匹配渲染地形所需的三角形。这个请求是异步的,所以会返回一个promise,请求完成则进行解析。每一点的高度都会适当的修改。如果其中一个高度值是undefined,是因为当前层级此位置没有可用的地形数据,或者是发生错误,那么高度值会返回一个undefined。查询位置点的数据类型是Cartographic类型,提供的高度是依据椭球体Elipsoid.WGS84而不是基于海平面的高度.
利用ArcGisImageServerTerrainProvider加载:
Cesium的瓦片加载机制是基于状态的,在GlobeSurfaceTile中的processStateMachine方法中会去判断请求瓦片的状态,当瓦片的状态为“LOADING”时,开始进入地形的处理机制processTerrainStateMachine方法,这一步主要将高程数据加载到瓦片上,如果没有数据没有加载的话,会先走TileTerrain类里面的requestTileGeometry方法来请求。
在ArcGisImageServerTerrainProvider类里面,请求高程数据是根据一个矩形框范围来向后台查询的,比如在第0级,先通过sampleTerrain构建一个查询实例,通过doSampling方法来进行高度查询。
Cesium地形加载的一些注意事项
1.通过GeographicTillingScheme这个类里面的属性numberOfLevelZeroTilesX、numberOfLevelZeroTilesY可以设置行列规则。因为有的地形瓦片规则是第0级只有一张。