目录
一、请求优化
1.1 多子域
1.1.1 scene.open()打开场景
1.1.2 加载地形
1.1.3 加载影像
1.1.4 加载S3M
1.1.5 加载MVT
1.2 批量请求
1.2.1 地形
1.2.2 影像
二、内存优化
2.1 根节点驻留内存
2.2 自动释放缓存
2.3 内存管理
三、图层优化
3.1 LOD
3.2 空间索引
3.3 控制图层显示范围
3.4 控制图层显隐
3.5 最大最小高程/距离
3.6 最大最小层级
四、属性优化
4.1 开启indexDB
4.2 专题图
4.2.1 字段专题图
4.2.2 标签专题图
4.3 属性查询
在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 = new Cesium.Viewer('cesiumContainer',{
terrainProvider:new Cesium.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(new Cesium.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=new Cesium.CesiumTerrainProvider({
url :'url',
isSct : true,//地形服务源自SuperMap iServer发布时需设置isSct为true
packingRequest: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=false;//及时释放内存(默认)
当然,上述这种不在视野范围内模型就消失的情况,也有项目不满足这种需要,他们希望模型一直都在,这时就需要将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 Cesium 11i及以后版本支持自定义多边形范围裁剪影像图层。可以前往官网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)通过模型缓存进行属性查询。
上述查询方法各有优缺点,小编整理了根据不同数据类型发布服务在前端进行查询的功能对比,如下图所示:
可以根据自己的项目需求选择适合自己的属性查询方式。