在GIS项目中,SuperMap iClient for WebGL/Cesium加载的服务图层很多、种类也很多,经常会出现少部分数据可以,但是大批量数据加载进来会出现掉帧严重,性能急速下跌,甚至导致浏览器崩溃的情况。本文争对这种情况来罗列出了下列四大类性能优化的方案,供GIS用户参考使用。
一、请求优化
1.1 多子域
由于浏览器对同一个域名服务的并发请求数量有限制,是6个,所以运行大场景三维需要用到多子域。通过Nginx 服务搭建多个子域名,加大向SuperMap iServer 发送数据请求的并发量,从而达到提升加载速度的目的。
描述:利用Nginx客户端,映射不同的端口地址来对SuperMap iServer进行访问,搭建子域环境,提升性能。
应用场景:充分利用SuperMap iServer机器的硬件性能,加大并发量,提升加载速度。
Nginx 服务如何搭建多个子域名请详见博客:Nginx服务搭建多个子域名
SuperMap iClient3D for Cesium支持多子域加载地形、影像、S3M以及MVT,关键接口是subdomains(获取或者设置子域名称。通过该接口可以向指定的子域请求数据),具体代码如下:
1.1.1 scene.open()打开场景
var promise = scene.open("http://{s}/iserver/services/3D-CBD/rest/realspace",undefined,{ subdomains:['localhost:8090','localhost:8092']}); viewer.flyTo(promise);
1.1.2 加载地形
var viewer =newCesium.Viewer('cesiumContainer',{ terrainProvider:newCesium.CesiumTerrainProvider({ url:'http://{s}/iserver/services/3D-SiChuanDiXingYingXiang/rest/realspace/datas/DatasetDEM', isSct :true,//是否为iServer发布的TIN地形服务,stk地形设置为false。 subdomains:['localhost:8081','localhost:8082','localhost:8083'],//获取或者设置子域名称。通过该接口可以向指定的子域请求数据。 invisibility:true//是否开启设置地形显隐的功能,默认为false。})});
1.1.3 加载影像
var imageLayer = viewer.imageryLayers.addImageryProvider(newCesium.SuperMapImageryProvider({ url:"http://{s}/iserver/services/3D-SiChuanDiXingYingXiang/rest/realspace/datas/MosaicResult", subdomains:['localhost:8081','localhost:8082','localhost:8083']})); viewer.flyTo(imageLayer);
1.1.4 加载S3M
var config ={ subdomainConfig:{ urlScheme:" http://{s}/iserver/services/3D-CBD/rest/realspace", subdomains:['localhost:8081','localhost:8082','localhost:8083']//设置子域}, name:"building"};var promise = viewer.scene.addS3MTilesLayerByScp('http://localhost:8090/iserver/services/3D-CBD/rest/realspace/datas/building/config', config); Cesium.when(promise,function(layer){ viewer.flyTo(promise);})
1.1.5 加载MVT
var mvtMap = scene.addVectorTilesMap({ url:"http://{s}/iserver/services/map-mvt-GLDZJSYDSPDKBZD/restjsr/v1/vectortile/maps/GL_DZ_JSYDSP_DKB_ZD", subdomains:['localhost:8081','localhost:8082','localhost:8083'], canvasWidth:512, name:'testMVT', viewer:viewer});
加载效果:从网络请求里看是否有不同端口的请求,比如'localhost:8081', 'localhost:8082', 'localhost:8083'。
1.2 批量请求
批量请求可以加快图层的下载请求速度,地形和影像图层支持批量请求。
1.2.1 地形
如果是 10.1 之前的SuperMap iDesktop版本,TIN 地形要生成紧凑存储类型,在前端开启批量请求,也能体验 10.1 版本块存储的加载效果,块存储的数据不需要再加 packingRequest:1 这行代码。
var provider_terrain=newCesium.CesiumTerrainProvider({url :'url',isSct :true,//地形服务源自SuperMap iServer发布时需设置isSct为truepackingRequest:1//批量请求})
1.2.2 影像
为了加快影像的下载速度,使周边切片一次请求下来,需要用到批量请求packingRequest:1 这行代码。
var provider=new Cesium.SuperMapImageryProvider({ url:'url', packingRequest:1//批量请求});"
二、内存优化
2.1 根节点驻留内存
根节点驻留内存residentRootTile是为了屏幕区域外不清除根节点内存。而这个前提还需要设置保存根节点indexedDBSetting.isGeoTilesRootNodeSave,这个是为了将缓存根节点下载保存到本地,根节点不需要重复下载。当清除浏览器缓存后,本地缓存也将被清除掉。所以当请适当选择清楚浏览器缓存
var layer = scene.layers.find('Config');//打开倾斜数据的Config图层layer.indexedDBSetting.isGeoTilesRootNodeSave =true;//设置是否保存根节点layer.residentRootTile=true;//设置根节点是否驻留内存不删除
2.2 自动释放缓存
S3MTilesLayer.clearMemoryImmediately是否及时释放内存,默认值为true。其表现在加载倾斜或者其他S3M图层完全加载到了客户端,但是一转动视角,不在视野范围内的模型消失(这是默认的渲染机制,为了保证性能),再把视角转回来,它会继续加载(按说数据已经加载过了)。
S3MTilesLayer.clearMemoryImmediately=true;//及时释放内存(默认)
当然,上述这种不在视野范围内模型就消失的情况,也有项目不满足这种需要,他们希望模型一直都在,这时就需要将clearMemoryImmediately设置为false,则还需要设置缓存空间的大小setCacheSize,不然浏览器内存不够会造成页面崩溃。
S3MTilesLayer.clearMemoryImmediately=false;//不及时释放内存Cesium.MemoryManager.setCacheSize(4096);//设置缓存空间的大小,单位为MB
2.3 内存管理
实际项目中经常会遇到下图这种渲染错误,出现这种报错需要从很多方面考虑,比如硬件显卡、浏览器内存、数据等。其中浏览器内存至关重要,可以设置场景总的显存资源占用阈值,根据机器内存显存大小,适当调整这个值,可以避免因为资源占满导致的崩溃,由于用户机器差异较大,这个值在Web端也没法获取到,因此产品包中设置的默认大小4GB,建议您们根据实际情况在前端设置(如果阈值太小会导致数据加载不全的问题)。
scene.context.memoryThreshold = 6;//显存资源占用阈值,单位是GB。
超过内存,修改设置最大内存,防止内存超限导致崩溃。设置以下这两个参数,出现不加载的情况就会少了一些。
Cesium.MemoryManager.showMemoryInfo(true);//显示内存调用 Cesium.MemoryManager.setMaxMemory(4096);//设置最大内存
三、图层优化
3.1 LOD
LOD机制使数据拥有不同的精细层级,在特定的情境下使用合适精细层级可提高数据的浏览效率,降低场景帧率。在SuperMap iDesktop中,对模型数据集生成缓存时默认构建3层LOD。在SuperMap iClient3D for Cesium中,场景通过数据与相机的直线距离来调度显示不同LOD,每一个LOD层级之间的切换距离大约是1000米。
举个例子:当相机距离模型3000米以上时,显示第一层LOD,当相机距离模型2000米-3000米时,显示第二层LOD,当相机距离模型小于1000米时,显示第三层LOD。
根据业务需求,SuperMap iClient3D for Cesium中可调整LOD层级的切换距离:
S3MTilesLayer.lodRangeScale = 1 //图层层级缩放比例系数
该值默认为1,如果想要在远距离时加载精细层LOD,将该值调小,同时会导致加载数据量变大;如果对场景性能要求高,将该值调大,同时会导致数据相对模糊。
3.2 空间索引
SuperMap iClient3D for Cesium中有4种数据加载模式,分为深度优先、层优先、空间索引、深度优先非线性切换。默认为深度优先。
采用空间索引加载方式,可减少LOD层级切换,从而提高加载到数据精细层LOD的速度
(ps:需要结合数据使用,SuperMap iDesktop 11i及以后缓存的数据可直接使用空间索引,SuperMap iDesktop 11i之前缓存的数据,需要用新版本桌面对缓存图层右键【创建空间索引】)
S3MTilesLayer.LoadingPriority = Cesium.LoadingPriorityMode.UsePagedLodInfo //空间索引加载模式
3.3 控制图层显示范围
控制图层显示范围是指影像加载只显示指定区域内,其他隐藏。SuperMap iClient3D for Cesium11i及以后版本支持自定义多边形范围裁剪影像图层。可以前往官网SuperMap技术资源中心|为您提供全面的在线技术服务下载SuperMap iClient3D 11i (2022) SP1 for Cesium包,代码如下:
viewer.scene.globe.addImageryClipRegions({ position: positions, layers:[imageryLayer], name:"test"})//控制影像图层显示范围
3.4 控制图层显隐
在满足业务需求的前提下,减少场景中的模型渲染量,比如,浏览地上数据时隐藏地下数据,浏览地下数据时隐藏地上数据,浏览室外数据时隐藏室内数据......
S3MTilesLayer.visible = false //隐藏图层
3.5 最大最小高程/距离
在满足业务需求的前提下,减少场景中的模型渲染量,适用于大场景下可以不显示,相机拉近再显示的图层
S3MTilesLayer.visibleDistanceMax = 1000; //最大可见距离值,单位为米S3MTilesLayer.visibleDistanceMin = 100; //最小可见距离值,单位为米S3MTilesLayer.maxVisibleAltitude = 1000; //最大可见高度值,单位为米S3MTilesLayer.minVisibleAltitude = 100; //最小可见高度值,单位为米
3.6 最大最小层级
对于影像数据而言,可设置最大最小请求层级
var layer = viewer.imageryLayers.addImageryProvider(new Cesium.SuperMapImageryProvider({ url: URL_CONFIG.SiChuan_IMG, minimumLevel:2, //最小请求层级 maximumLevel:8 //最大请求层级}));
四、属性优化
4.1 开启indexDB
在SuperMap iClient3D for WebGL 10i以及之后版本中,提供了indexedDB缓存功能,通过设置S3MTileslayer中的indexDBSetting属性开启缓存机制,开启之后首次访问下载的s3m文件将被写入indexedDB数据库中,再访问时将从indexedDB中直接读取,极大提高二次浏览性能。同时indexedDB也支持大量数据的存储,以及索引查询。
indexDBSetting获取或者设置indexedDB属性信息(IE浏览器不支持)。其中,在设置indexeDB属性时, 有三个布尔类型的分支属性:isGeoTilesSave——是否保存切片; isAttributesSave--是否保存属性;isGeoTilesRootNodeSave--是否保存根节点。
开启indexedDB之后的客户端缓存,这些缓存的文件都在浏览器的安装目录下,一般是在C:\Users\CYKJ\AppData\Local\Google\Chrome\User Data\Default\IndexedDB目录下。
开启代码:
var layer = scene.layers.find('Config'); layer.indexedDBSetting.isGeoTilesRootNodeSave=true;
4.2 专题图
4.2.1 字段专题图
前端项目中用户往往有对s3m图层(这里指线、面和白模数据)根据属性信息赋予不同颜色的需求。虽然咱们前端可以支持SQL查询获取属性对象信息,实现上面需求思路是根据不同字段属性查出对应图元ID数组,再根据图元ID数组用接口setObjsColor(ids, color)来设置对应的颜色。这种流程可以走下来,但是往往查询渲染起来特别慢,这时我们就可以用前端做字段专题图的方法来提升它的性能。
下面是前端制作字段专题图的关键代码:
//生成缓存时需要在桌面软件中把“属性存储类型”改为“ATTRIBUTE”在web端会根据指定属性字段设置专题图。var infos =[{ url:'http://www.supermapol.com/realspace/services/3D-bjBaiMo/rest/realspace/datas/bjBaiMo3/config', cullEnabled:true, queryFieldNames:['name']}];//默认是layer.indexedDBSetting.isAttributesSave=true,会开启图层的全部属性字段下载,数据量大会影响性能S3MTilesLayer.queryFieldNames =['name'];//指定仅下载需要的属性字段,提升性能;桌面缓存生成时,‘属性存属类型’需要选择ATTRIBUTE才支持S3MTilesLayer.themeStyle =new Cesium.Cesium3DTileStyle({ color:{ conditions:[//根据字段的不同属性值赋予不同颜色['${name} === "北京"','color("purple")'],['${name} === "上海"','color("yellow")'],['${name} === "成都"','color("green")'],['false','color("blue")']//当属性值不符合上述条件时,设置该颜色]},//show: '${name} === "成都"',//只显示字段符合该属性值的对象,其它不满足的会被过滤掉});
4.2.2 标签专题图
在GIS项目中将标签、图标在SuperMap iDesktop中做好后生成场景缓存,在SuperMap iServer发布三维服务,在前端代码加载会出现下图这种图标和标签密密麻麻的现象,这种可视效果差而且还影响性能。
那我们可以同时开启图标和标签避让,来达到视觉美观和提升性能的效果。具体代码见下图:
var iconlayer = scene.layers.find('BusPoint@RealspaceSample');//图标图层var textlayer = scene.layers.find('BusPoint@RealspaceSample#1');//文字图层iconlayer.isOverlapDisplayed =false;//开启图标避让textlayer.isOverlapDisplayed =false;//开启标签避让iconlayer.iconRelatedTextLayerID = textlayer.id;//图标随着文字避让而避让
效果如下:
4.3 属性查询
SuperMap官网WebGL范例里对模型进行属性查询,用到三种方法:
(1)模型数据集发布数据服务进行查询;
(2)模型数据集转成二维面数据集或者属性表,对二维面或者属性表发布数据服务进行查询;
(3)通过模型缓存进行属性查询。
上述查询方法各有优缺点,小编整理了根据不同数据类型发布服务在前端进行查询的功能对比,如下图所示:
可以根据自己的项目需求选择适合自己的属性查询方式。
版权归原作者 nannan^_^ 所有, 如有侵权,请联系我们删除。