irpas技术客

cesium 按需加载实体(entity)_三维网格_cesium添加entity

网络 943

我们在使用cesium时,常常会有需要加载中国各地区名称的需求,然而cesium中能够添加的entity的数量是有上限的,当加载到一定数量时就会出现卡顿甚至是浏览器崩溃的情况,这时候就需要按需加载我们的实体类,接下来就给大家介绍一种按需加载的方式,在鼠标移动结束后根据当前地图层级判断是否显示或者删除实体entity

1、创建一个地球 // 默认看向中国 Cesium.Camera.DEFAULT_VIEW_RECTANGLE = Cesium.Rectangle.fromDegrees(90,-20,110,90) // 定义场景、标签位置数组、实体数组 let viewer,labelArr = [],entities = [] // 创建地球 viewer = new Cesium.Viewer('cesiumContainer') // 默认的显示地球纹理 viewer.baseLayerPicker.viewModel.selectedImagery= viewer.baseLayerPicker.viewModel.imageryProviderViewModels[3]; // 添加显示层级网格线 viewer.imageryLayers.addImageryProvider(new Cesium.TileCoordinatesImageryProvider()) // 是否应预加载渲染图块的祖先。将此设置为true可优化缩小体验,并在平移时新暴露的区域。缺点是需要加载更多的图块。 viewer.scene.globe.preloadAncestors = false // 关闭鼠标操作惯性 var CesiumViewerSceneController = viewer.scene.screenSpaceCameraController; CesiumViewerSceneController.inertiaSpin = 0; CesiumViewerSceneController.inertiaTranslate = 0; CesiumViewerSceneController.inertiaZoom = 0;

生成地球以后是这样的,外面的黄色的线就是层级网格线

2、加载数据

接下来我们加载将要作为示例的区域数据,我们打印一下可以发现,当前数据量达到了13w,远远超过了cesium所能容纳的实体数量

// 加载json文件 fetch('./AANP自然地名.geojson').then((res)=>{ return res.json() }) .then(json=>{ for(const item of json.features){ // 取出数据中各区域的位置 let obj = [item.geometry.coordinates[0],item.geometry.coordinates[1]] labelArr.push(obj) // 创建实体 let entity = new Cesium.Entity({ position:new Cesium.Cartesian3.fromDegrees(item.geometry.coordinates[0],item.geometry.coordinates[1]), label:{ text:item.properties.NAME, fillColor:Cesium.Color.fromCssColorString ('red'), font:'20pt monospace', heightReference:Cesium.CLAMP_TO_GROUND } }) // 使用数组保存实体,方便后续检索删除 entities.push(entity) } console.log(entities.length)

此次加载的json数据格式

{ "type": "FeatureCollection", "features": [ { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ 112.27967881000006, 3.9707323300000894 ] }, "properties": { "CLASS": "JH", "NAME": "曾母暗沙", "PINYIN": "Zengmu Ansha" } }, 3、实现按需加载 // 获取当前正在渲染的瓦片集合 const tilesToRender =viewer.scene.globe._surface._tilesToRender /** * 添加相机移动结束事件,也就是鼠标移动结束事件 * 由于相机自身有惯性,所以提前关闭惯性会有更好的体验 * 但是这本身并不影响该功能 * */ viewer.camera.moveEnd.addEventListener(()=>{ // 当前正在渲染的瓦片求并集为一个大的rectangle let renderRectangle = new Cesium.Rectangle() if( tilesToRender.length > 0 ) { // 初始化总的渲染的矩形瓦片 Cesium.Rectangle.clone(tilesToRender[0].rectangle,renderRectangle) let num = 0 tilesToRender.forEach(item => { /** * 获取当前层级大于等于12级的瓦片,该处可自定,具体层级可根据加载的实体多少决定 * 一般情况下由于相机视角的不同,我们能看见的瓦片数量也不同,所以尽量考虑瓦片数量 * 最多的情况下每块瓦片上的显示数量 */ if( item.level >= 12 ) { // 用来判断当前是否有符合条件的瓦片正在渲染 num += 1 // 所有大于12级的瓦片求交集 Cesium.Rectangle.union(item.rectangle, renderRectangle, renderRectangle) } }) if( num > 0 ){ // 判断点是否在所需渲染的瓦片内 for( let i = 0; i < entities.length; i++ ) { // 将度转为弧度 let cartographic = Cesium.Cartographic.fromDegrees(labelArr[i][0], labelArr[i][1]) // 判断点是否在矩形内 if(Cesium.Rectangle.contains(renderRectangle,cartographic)){ // 判断当前实体是否已经被加载,有则跳过,无则加载 if(viewer.entities.contains(entities[i])) continue viewer.entities.add(entities[i]) } else { // 不在点内,则判断是否被加载,有则删除 if(viewer.entities.contains(entities[i])){ viewer.entities.remove(entities[i]) } } } } else{ for( let i = 0; i < entities.length; i++ ){ /** * 当前可视范围内没有符合条件的瓦片加载,删除掉所欲瓦片 * 不能使用removeAll,我们只需要管理我们自己加载的部分即可 */ if(viewer.entities.contains(entities[i])){ viewer.entities.remove(entities[i]) } } } } }) 4、总结

实现方法和实现的思路都在注释中详细的讲解了,这肯定不是唯一的一种实现方式,也不是最好的一种实现方式,但我觉得这是最容易理解和上手的方法,不需要对cesium有非常的高的熟练度也能看懂并且能直接使用。

关键点 加载json数据,创建实体,控制加载实体的瓦片层级获取当前被渲染的瓦片构成的集合,通过求并集拼成一个大的矩形(也许称为范围可能更合适,但是毕竟使用的是矩形方法)根据矩形方法判断点是否在矩形中,如果在,则加载当前实体,否则删除当前实体

两个字:快,稳! 欢迎咨询,后台回复【商务合作】,获取联系方式! 欢迎关注微信公众号【三维网格3D】,第一时间获取最新文章


1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,会注明原创字样,如未注明都非原创,如有侵权请联系删除!;3.作者投稿可能会经我们编辑修改或补充;4.本站不提供任何储存功能只提供收集或者投稿人的网盘链接。

标签: #cesium添加entity #cesium #CesiumRectangle