草庐IT

SuperMap iClient3D for WebGL/Cesium端性能优化

nannan^_^ 2023-05-15 原文
   

目录

一、请求优化

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=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 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)通过模型缓存进行属性查询。

上述查询方法各有优缺点,小编整理了根据不同数据类型发布服务在前端进行查询的功能对比,如下图所示:

可以根据自己的项目需求选择适合自己的属性查询方式。

有关SuperMap iClient3D for WebGL/Cesium端性能优化的更多相关文章

  1. Ruby 的数字方法性能 - 2

    我正在使用Ruby解决一些ProjectEuler问题,特别是这里我要讨论的问题25(Fibonacci数列中包含1000位数字的第一项的索引是多少?)。起初,我使用的是Ruby2.2.3,我将问题编码为:number=3a=1b=2whileb.to_s.length但后来我发现2.4.2版本有一个名为digits的方法,这正是我需要的。我转换为代码:whileb.digits.length当我比较这两种方法时,digits慢得多。时间./025/problem025.rb0.13s用户0.02s系统80%cpu0.190总计./025/problem025.rb2.19s用户0.0

  2. ruby - Ruby 性能中的计时器 - 2

    我正在寻找一个用ruby​​演示计时器的在线示例,并发现了下面的代码。它按预期工作,但这个简单的程序使用30Mo内存(如Windows任务管理器中所示)和太多CPU有意义吗?非常感谢deftime_blockstart_time=Time.nowThread.new{yield}Time.now-start_timeenddefrepeat_every(seconds)whiletruedotime_spent=time_block{yield}#Tohandle-vesleepinteravalsleep(seconds-time_spent)iftime_spent

  3. ruby-on-rails - 如果条件与 &&,是否有任何性能提升 - 2

    如果用户是所有者,我有一个条件来检查说删除和文章。delete_articleifuser.owner?另一种方式是user.owner?&&delete_article选择它有什么好处还是它只是一种写作风格 最佳答案 性能不太可能成为该声明的问题。第一个要好得多-它更容易阅读。您future的自己和其他将开始编写代码的人会为此感谢您。 关于ruby-on-rails-如果条件与&&,是否有任何性能提升,我们在StackOverflow上找到一个类似的问题:

  4. ruby - 如何找到我的 Ruby 应用程序中的性能瓶颈? - 2

    我编写了一个Ruby应用程序,它可以解析来自不同格式html、xml和csv文件的源中的大量数据。我如何找出代码的哪些区域花费的时间最长?有没有关于如何提高Ruby应用程序性能的好资源?或者您是否有任何始终遵循的性能编码标准?例如,你总是用加入你的字符串吗?output=String.newoutput或者你会使用output="#{part_one}#{part_two}\n" 最佳答案 好吧,有一些众所周知的做法,例如字符串连接比“#{value}”慢得多,但是为了找出您的脚本在哪里消耗了大部分时间或比所需时间更多,您需要进行分

  5. STM32的HAL和LL库区别和性能对比 - 2

    LL库和HAL库简介LL:Low-Layer,底层库HAL:HardwareAbstractionLayer,硬件抽象层库LL库和hal库对比,很精简,这实际上是一个精简的库。LL库的配置选择如下:在STM32CUBEMX中,点击菜单的“ProjectManager”–>“AdvancedSettings”,在下面的界面中选择“AdvancedSettings”,然后在每个模块后面选择使用的库总结:1、如果使用的MCU是小容量的,那么STM32CubeLL将是最佳选择;2、如果结合可移植性和优化,使用STM32CubeHAL并使用特定的优化实现替换一些调用,可保持最大的可移植性。另外HAL和L

  6. ruby - GC.disable 的任何性能缺点? - 2

    是否存在GC.disable会降低性能的情况?只要我使用的是真正的RAM而不是交换内存,就可以这样做吗?我正在使用MRIRuby2.0,据我所知,它是64位的,并且使用的是64位的Ubuntu:ruby2.0.0p0(2013-02-24revision39474)[x86_64-linux]Linux[redacted]3.2.0-43-generic#68-UbuntuSMPWedMay1503:33:33UTC2013x86_64x86_64x86_64GNU/Linux 最佳答案 GC.disable将禁用垃圾回收。像rub

  7. Ruby 缺少常量表达式优化? - 2

    我希望Ruby的解析器会进行这种微不足道的优化,但似乎并没有(谈到YARV实现,Ruby1.9.x、2.0.0):require'benchmark'deffib1a,b=0,1whileb由于这两种方法除了在第二种方法中使用预定义常量而不是常量表达式外是相同的,因此Ruby解释器似乎在每个循环中一次又一次地计算幂常数。是否有一些Material说明为什么Ruby根本不进行这种基本优化或只在某些特定情况下进行? 最佳答案 很抱歉给出了另一个答案,但我不想删除或编辑我之前的答案,因为它下面有有趣的讨论。正如JörgWMittag所说,

  8. ruby-on-rails - Rails with angular 与 Rails pure(查看性能) - 2

    我尝试在Internet上搜索有关使用angularJS进入RubyonRails项目与RubyonRailspure的View性能的信息。我的问题是因为2个月前我开始使用纯AngularJS,现在我需要将AngularJS集成到一个新项目中,但需要展示使用带有RubyonRails的AngularJS呈现View的性能如何,并消除对RubyonRails的负担.例如:带Rails的Angular:使用RubyonRails获取数据(从数据库或GET请求),将信息发送到file.js.erb并使用AngularJS操作数据并显示带有解析数据的View。纯粹的Rails:(自然流程)使用

  9. ruby-on-rails - 在 Rails 3 应用程序中使用 require_dependency 对性能有何影响? - 2

    我觉得我理解require和require_dependency之间的区别(来自Howarerequire,require_dependencyandconstantsreloadingrelatedinRails?)。但是,我想知道如果我使用一些不同的方法(参见http://hemju.com/2010/09/22/rails-3-quicktip-autoload-lib-directory-including-all-subdirectories/和Bestwaytoloadmodule/classfromlibfolderinRails3?)来加载所有文件会发生什么,所以我们:

  10. ruby-on-rails - 优化读取数据库和写入csv文件 - 2

    我正在尝试从数据库中读取大量单元格(超过100.000个)并将它们写入VPSUbuntu服务器上的csv文件。碰巧服务器没有足够的内存。我正在考虑一次读取5000行并将它们写入文件,然后再读取5000行,等等。我应该如何重构我当前的代码以使内存不会被完全消耗?这是我的代码:defwrite_rows(emails)File.open(file_path,"w+")do|f|f该函数由sidekiqworker调用:write_rows(user.emails)感谢您的帮助! 最佳答案 这里的问题是,当您调用emails.each时,

随机推荐