kikitte/MVTImageryProvider

矢量瓦片上球展示后频繁更改要素属性会导致cesium地球崩溃

qiuuuy opened this issue · 13 comments

mbtiles矢量瓦片上球展示后,如果频繁更改某图层的要素属性会导致cesium地球崩溃。以线矢量图层的线宽属性为例,频繁更改线宽度值多次并更新视图,数次以后便会提示错误如下:【很奇怪,每次都是编辑属性15次就崩溃了】
错误3
错误2
错误1

这是控制图层更新的代码:
代码2

问题确认。Chrome浏览器支持的webgl context数量最多为16个,当webgl context数量超过时浏览器会产生警告并导致渲染失败WARNING: Too many active WebGL contexts. Oldest context will be lost。在你说的情况当中,cesium viewer占用一个webgl context,由于MVTImageryProvider使用mapbox gl js进行渲染,每个MVTImageryProvider会创建一个webgl context,所以第16次重复创建MVTImageryProvider会导致webgl context数量超标。

我考虑在MVTImageryProvider类中添加destroy方法来彻底销毁与当前实例相关的所有资源,包括webgl context.

临时解决这个报错的方法可在MVTImageryProvider添加如下方法,在新建MVTImageryProvider之前销毁上一个不使用的MVTImageryProvider。

destroy() {
   // TODO:该方法尚未释放其他资源

    this.mapboxRenderer._gl.getExtension('WEBGL_lose_context').loseContext();
}

已在58d6405 修复

首先感谢kikitte大神的仓库!
我在使用大神的代码时也发现了这个问题,解决的方法是在模块中创建一个全局变量作为BasicRenderer渲染模板,避免出现16个canvas上下文的浏览器限制,具体实现代码可以参考一下这里
此外,频繁创建MVTImageryProvider类会产生内存占用过大的问题,跟踪内存发现是BasicRenderer中的瓦片缓存没有被释放,所以我在releaseTile的同时释放了未在使用的瓦片缓存,可以看看这处的代码。
这相对于在移除Imagery对象时手动调用一次destory()方法,似乎要稍微简便一些,也期待大神的进一步完善。

首先感谢kikitte大神的仓库! 我在使用大神的代码时也发现了这个问题,解决的方法是在模块中创建一个全局变量作为BasicRenderer渲染模板,避免出现16个canvas上下文的浏览器限制,具体实现代码可以参考一下这里 此外,频繁创建MVTImageryProvider类会产生内存占用过大的问题,跟踪内存发现是BasicRenderer中的瓦片缓存没有被释放,所以我在releaseTile的同时释放了未在使用的瓦片缓存,可以看看这处的代码。 这相对于在移除Imagery对象时手动调用一次destory()方法,似乎要稍微简便一些,也期待大神的进一步完善。

这种实现方式我考虑的是多个BasicRenderer共用一个canvas可能会造成不可预期的错误,因为我对webgl和mapbox-basic-renderer不熟悉,所以采取保守的方式更为妥当。
这处代码只是放了id为origin的BasicSourceCache对象持有的缓存,具体可看 https://github.com/landtechnologies/Mapbox-vector-tiles-basic-js-renderer/blob/99ba6f3d94eea5dbfed098579f8b8c289854a5a3/src/basic/style.js#L20

如有错误,不吝赐教

首先感谢kikitte大神的仓库! 我在使用大神的代码时也发现了这个问题,解决的方法是在模块中创建一个全局变量作为BasicRenderer渲染模板,避免出现16个canvas上下文的浏览器限制,具体实现代码可以参考一下这里 此外,频繁创建MVTImageryProvider类会产生内存占用过大的问题,跟踪内存发现是BasicRenderer中的瓦片缓存没有被释放,所以我在releaseTile的同时释放了未在使用的瓦片缓存,可以看看这处的代码。 这相对于在移除Imagery对象时手动调用一次destory()方法,似乎要稍微简便一些,也期待大神的进一步完善。

这种实现方式我考虑的是多个BasicRenderer共用一个canvas可能会造成不可预期的错误,因为我对webgl和mapbox-basic-renderer不熟悉,所以采取保守的方式更为妥当。 这处代码只是放了id为origin的BasicSourceCache对象持有的缓存,具体可看 https://github.com/landtechnologies/Mapbox-vector-tiles-basic-js-renderer/blob/99ba6f3d94eea5dbfed098579f8b8c289854a5a3/src/basic/style.js#L20

如有错误,不吝赐教

感谢大神回复!
我对webgl和canvas也不熟悉,但在我最近的工作中使用这个模块进行pbf渲染,它工作得很好,在上百次频繁的渲染中并没有出现问题,所以我认为多个BasicRenderer共用一个canvas这种做法是可行的。
至于释放缓存的代码,确实有问题,我当时测试时创建的图层id叫origin……感谢大佬指出问题!

@qiuuuy @hongfaqiu 您好,请问pbf矢量数据渲染出来后,你是怎么修改这些要素的,比如线条宽度。是不是修改这些样式要再次调用new MVTImageryProvider,传入修改后的style,来重新渲染?

@qiuuuy @hongfaqiu 您好,请问pbf矢量数据渲染出来后,你是怎么修改这些要素的,比如线条宽度。是不是修改这些样式要再次调用new MVTImageryProvider,传入修改后的style,来重新渲染?

是这样的,但是因为瓦片数据已经请求过了,浏览器会有缓存,所以这个重新渲染的过程还是很快的

qiuuuy commented

@hongfaqiu @qiuuuy 还有两个问题再请教下您
1、pickFeatures这个方法你有用过吗,我在这个上面有描述
2、style.json中配置了两个图层,json如下:
image
我现在想实现的是,通过鼠标点击来获取被点击的图层,这该怎么确定,我点了那个图层呢?
上面这个json最终渲染的结果如下图:
image
灰色为"2022县矢量_0802152028"这个图层,红色的为“水体面积_10003”图层,我是想通过点击红色区域拿到这个这个区域的信息

@hongfaqiu @qiuuuy 还有两个问题再请教下您 1、pickFeatures这个方法你有用过吗,我在这个上面有描述 2、style.json中配置了两个图层,json如下: image 我现在想实现的是,通过鼠标点击来获取被点击的图层,这该怎么确定,我点了那个图层呢? 上面这个json最终渲染的结果如下图: image 灰色为"2022县矢量_0802152028"这个图层,红色的为“水体面积_10003”图层,我是想通过点击红色区域拿到这个这个区域的信息

看看构造MVTImageryProvider时有没有传入enablePickFeatures: true?

@hongfaqiu @qiuuuy 还有两个问题再请教下您 1、pickFeatures这个方法你有用过吗,我在这个上面有描述 2、style.json中配置了两个图层,json如下: image 我现在想实现的是,通过鼠标点击来获取被点击的图层,这该怎么确定,我点了那个图层呢? 上面这个json最终渲染的结果如下图: image 灰色为"2022县矢量_0802152028"这个图层,红色的为“水体面积_10003”图层,我是想通过点击红色区域拿到这个这个区域的信息

看看构造MVTImageryProvider时有没有传入enablePickFeatures: true?

有传入,并且鼠标点击图层时,也有聚焦的效果。

@wh1246935943 我在你开的issue里面回复了