Cesium是一个开源的,基于webgl的二、三维地图引擎,就其实现来说是目前开源版本中比较完备的一个版本,有完备的数据源支持、支持大场景、支持定制化的样式渲染。由于发起人是个三维可视化方面的大牛,我很乐意花点时间去学习一下大牛的作品,一探究竟,Cesium是如何实现大型(超过150000行代码)webgl前端程序的组织和渲染调度的。
Cesium就其支持的数据格式而言,支持大部分影像瓦片格式(当然是世界范围的,国内的几个厂商自定的格式,目前官方还没有完全支持,但是可以通过自定义瓦片格式去访问瓦片也不是什么大问题),Json格式的矢量数据,大场景数据格式3D Tiles,小场景的可以直接用gltf格式。影像和矢量目前行业内的方案比较成熟了,Cesium也只是兼收并蓄,没有特别出彩的地方。我想说的是关于三维数据格式这一块,这个gltf是由Khronos Group设计和规定的WebGL分发格式,对与前端渲染而言,紧凑的数据格式和高效的运行时解析是保证效率的两个关键因素,目前很多前端的库(比如three.js)还试图支持各种各样的交换3d格式,比如3ds obj等这些,这些数据格式是PC桌面端时代的产物,其目的是为了便于人的理解而不是利于机器的理解,所以这些格式必然是无法适应web场景的,而gltf将webgl中所需的几何数据以二进制的方式存储,当然数据的组织是完全根据webgl接口的需要进行组织,这样一来即能保证格式的紧凑又能保证解析的高效,运行时直接将数据塞给webgl而省却了格式解析的过程,基于这点考虑在三维模型上只支持gltf。在大场景数据格式方面,Cesium首先提出了3D Tiles的场景数据格式,虽然对于三维场景数据组织大家第一想法就是仿照二维瓦片的方式组织,但是大家只是想了想,而人家是落地了,所以人家是先驱,后期GIS届的两大厂商超图和ESRI也陆续推出了自己的三维场景格式S3M和I3S,基本原理都一样,我就说个基本思路就是:N叉树+三维瓦片。而每个瓦片的组织则是使用了gltf的思想,二进制几何数据加JSON格式元数据,这块不展开说了,目前的情况是OGC采用了I3S,从渲染效率来说超图和ESRI的都优于Cesium,此处需要说一下超图的s3m是3d tiles的改进,框架也是直接在cesium上面改的。
在代码方面也是我感兴趣的方面,因为我对JS一直保持着一颗敬畏的心,真心佩服能把JS玩的很溜的大牛X。首先在模块化方面,Cesium使用AMD的方案就行代码组织,这样一来就可以实现代码的按需加载,对于像Cesium这种大型的前端程序是很有必要的,尽可能的减少加载的延迟和对带宽的占用。对于服务端的部分,Cesium则使用的是CommoJS的组织方式,这也是NodeJs默认使用的模块方案,服务端部分则不存在延迟的问题,代码看起来也能优雅一点,顺便吐槽一下AMD那个define真是挫爆了,其他的在代码编写上总结了如下几点:
1、使用尽可能多的参数来构造对象。JS在我看来就是很随意,恰恰是这种很随意的特性让每次写代码的时候心里面很心虚,不知道后面VM在搞什么鬼,在Cesium中提倡尽量使用完备的构造参数来进行对象构建,而不推荐后期直接对实例进行instance.x= value这种操作,因为这会导致实例的重新分配和属性的拷贝。
2、直接暴露属性字段。在强类型语言中的属性定义有专门的语法,C#中是get,set;java中是getter, setter方法,对于JS来说定义属性就是Object.defineProperty,这样做本质上就是将属性转换为函数调用,可以在修改或者返回属性的时候做一些控制,增强程序的健壮性,但是这也恰恰增加了开销,对于Cesium而言这都需要小心翼翼,因而推荐直接暴露公有字段。
3、避免频繁的gc。gc是需要付出代价的,在整理内存的时候当前线程会被挂起,对于交互式的程序如果频繁gc那还搞个球,对于webgl程序都会有个loop,如果在每个loop里面都进行变量的分配那很快就会触发gc,形成很有规律的大波浪曲线,要改善这种情况就只能尽可能的减少变量的分配而是尽可能的利用现有变量,因而Cesium的函数参数都会带一个result的变量用来存储返回值,这样就能提高变量的利用效率。
4、使用Transfer Object进行跨线程通讯。说到跨线程必然就是Web Worker了,由于主线程和worker线程无法共享内存,线程之间的数据传递只能通过序列化,在js这边就是json,这种序列化必然式要拷贝然后传递,如果是数量较大,这种这种拷贝的代价就需要纳入考虑了,Cesium中使用的方案是使用Transfer Object进行跨线程传输,使用这种对象就会导致传递的对象在sender方不可再访问了,换来的是性能的提升,Cesium再这种场景下都会将实例pack到ArrayBuffer然后再post。
好就到这里,后面会再看一些关于调度方面的东西,有时间再分享出来。
网友评论