Cesium原理篇:3最长的一帧之地形(1)

前面我们从宏观上分析了Cesium的整体调度以及网格方面的内容,通过前两篇,读者应该可以比较清楚的明白一个Tile是怎么来的吧(如果还不明白全是我的错)。接下来,在前两篇的基础上,我们着重讨论一下地形相关的内容。

Cesium提供了TerrainProvider基类,该Provider负责每一个Tile对应的地形数据的构建,定义了一套地形Provider需要实现的接口和规范,但本身并不会参与其中的操作。这里列举一些关键的属性和函数:

  • tilingScheme
    Provider内部地球网格的剖分方式,通常是WGS84坐标,也可以选择墨卡托坐标系
  • hasWaterMask
    是否支持水面效果
  • hasVertexNormals
    地形数据中是否包含法向量(光照是否支持)
  • heightmapTerrainQuality
    地形显示的精度,在上一篇中介绍的一个Tile占多少像素,其中这个参数作为调整系数
  • requestTileGeometry
    Provider的对外接口,参数为Tile对应的XYZ,返回其对应的TerrainData,基类中为空实现。

如上就是TerrainProvider,基本都是空实现,仅仅提供了一套规范,在Cesium中有三个继承类,EllipsoidTerrainProvider和CesiumTerrainProvider,还有最新提供的ArcGisImageServerTerrainProvider。

       详细介绍地形前我们先说明一下TileScheme、Terrain和Imagery之间的一个关联。TileScheme是坐标系,Cesium中目前支持WGS1984和墨卡托投影两种。Terrain和Imagery分别采用自己的TileScheme,比如目前Terrain默认采用WGS1984的坐标系,这和经纬高的真实数据更接近,而目前Imagery影像服务基本都是墨卡托投影(据我了解,只有天地图提供WGS84的影像服务)。

TileScheme

Imagery(WGS1984)

Imagery(Mercator)

Terrain(WGS1984)

坐标相同

坐标不同

Terrain(Mercator

坐标不同

坐标相同

如上图,首先,Globe,也就是地球网格是根据TerrainProvider的TileScheme来划分的;其次,如果地形和影像之间采用不同的坐标系,则影像切片需要动态的转换为地形切片下对应的效果,也就是动态投影的过程,这个计算量是不可忽略的;       最后,在实际中,EllipsoidTerrainProvider支持WGS和Mercator两种坐标系,而CesiumTerrainProvider只能支持WGS一种,因此选择何种地形和影像来互相匹配,在性能上也是有差异的。

EllipsoidTerrainProvider

EllipsoidTerrainProvider是Globe默认采用的地形Provider,该Provider不支持水面,没有法向量,所以即使开启光照,对Tile也是无效的。

EllipsoidTerrainProvider功能弱爆了,那还有它存在的价值吗?答案是肯定的。它提供了一个全球范围内高度为0的地形,不需要额外的地形文件,就可以实时的自己来构建这个高度为0的Mesh。对那些没有网络环境,或网络不理想,或不需要地形的应用,EllipsoidTerrainProvider提供了最简单的,无需额外负担的地形数据来构网。

来看一下requestTileGeometry的实现:

Cesium原理篇:3最长的一帧之地形(1)

原来EllipsoidTerrainProvider采用的高度图方式来构网,但buffer直接new出来,所以值都为0,而高宽为16,也就是把一个Tile的行列分为16*16。至于Cesium如何通过高度图构网的过程,我们在下一篇会介绍,本篇主要在于思路和流程的理解。如下是截取的XYZ为412的地形网格效果,是一个15*15的高度为0的网格:

Cesium原理篇:3最长的一帧之地形(1)

另外,EllipsoidTerrainProvider有一个更为灵活的地方,TileScheme默认采用WGS84,但用户可以选择,这个在性能优化上还是值得考虑的,目前的影像服务绝大多数都是采用墨卡托,如果地形采用WGS84,如果所用的EllipsoidTerrainProvider内部坐标系是WGS84,这样就需要讲墨卡托的影像切片转换为WGS的切片的过程,所以,在这种情况下,反正怎么划分,最后的网格都没什么区别,索性让地形的TileScheme和影像的保持一致,性能会更好。理论上讲这个思路是正确的,但事实真的如此吗?因为这个牵扯到Imagery模块,我们在后面讲影像时再详细讨论。

ArcGisImageServerTerrainProvider

我们下来在看看年轻的ArcGIS的地形,这个可以说是一个真实的(凹凸的)高度图,原理和EllipsoidTerrainProvider如出一辙,因此同样的不支持法线,水面,但可以选择TileScheme,与EllipsoidTerrainProvider不一样之处在于每一个切片会根据ArcGIS规范请求一张图片,该图片中的像素对应的值就是该像素对应的高度,真的是名副其实的高度图。我们来看看ArcGisImageServerTerrainProvider的requestTileGeometry实现:

Cesium原理篇:3最长的一帧之地形(1)

如上,不同于EllipsoidTerrainProvider,ArcGisImageServerTerrainProvider需要根据当前的XYZ获取对应的范围bbox,然后向ArcGIS World Elevation Image Services请求对应该范围的一个_heightmapWidth*_heightmapWidth大小的高度图。heightmapWidth默认为65,可想而知该网格会比较密。

遗憾的是,根据Cesium提供的url,我本机无法访问,所以看不到效果,如果对这个感兴趣,可以参考之前的一篇文章《ArcGIS Earth数据小析》,两者应该是同源的。

CesiumTerrainProvider

最后,就轮到了CesiumTerrainProvider,在该Provider中支持两种地形格式,一种是高度图,一种则是TIN网格的STK地形。我们一一道来。

createHeightmapTerrainData

这个是Cesium提供的高度图方式,和ArcGIS的很相似,目前Cesium已经废弃,确实在技术上,高度图有很多缺陷,我们在介绍完STK的TIN效果后,大家就一目了然。

Cesium原理篇:3最长的一帧之地形(1)

这个就不用介绍了吧,和前面的一模一样,效果如下,相比EllipsoidTerrainProvider,同一个XYZ(412)这个比较密,因为这次确实有高度了,而不是清一色的0:

Cesium原理篇:3最长的一帧之地形(1)

另外,Cesium的高度图支持水面效果,水面涉及到渲染层面,我们会在影像渲染中涉及这个问题。

createQuantizedMeshTerrainData

Cesium厉害的指出就在于目前采用STK的地形服务,这个地形的难度和技术细节已经无法在这一个章节内一一道来了,我们也主要说思路,后面单独一个章节来具体的说一下。支持。Cesium通过QuantizedMeshTerrainData封装了STK地形数据格式,它的优点是支持水面和法线,同时数据量比较小。个人认为STK的地形数据代表目前最好的TIN地形生成技术,没有之一,相比之下,高度图的形式可能更容易在应用层面解决问题,但在技术角度不值得一提。

当然,下载STK的数据思路和高度图的一直,也是根据XYZ请求一个Terrain文件,返回值是一个arraybuffer,不过这一次,不是用HeightmapTerrainData来封装,而是用QuantizedMeshTerrainData,本篇不讨论QuantizedMeshTerrainData细节,先看看同一个Tile(412)下的效果图:

Cesium原理篇:3最长的一帧之地形(1)

可见STK的地形网格看上去很简单,甚至比EllipsoidTerrainProvider还要稀疏,那为什么还能具有如此多的优点呢,现卖个关子,下回分解。

回顾

本文主要介绍了目前Cesium支持的三种TerrainProvider的相关细节,每一个Tile切片,对应不同的TerrainProvider,地形数据会封装成HeightMapTerrainData或者QuantizedMeshTerrainData对象。

下两篇,我们详细介绍高度图,也就是HeightMapTerrainData和QuantizedMeshTerrainData中的细节。

上一篇:对Qt下对话服务器客户端的总结(MyTcpServer与MyTcpClient)


下一篇:Cesium原理篇:7最长的一帧之Entity(上)