cesium加载三维立体primitive图元并贴地展示

您所在的位置:网站首页 立体多边形素描图片 cesium加载三维立体primitive图元并贴地展示

cesium加载三维立体primitive图元并贴地展示

2024-07-02 17:08| 来源: 网络整理| 查看: 265

项目场景: 由于项目里需要加载很多三维立方体,之前用的方式是entity,但是数据量大的话会有点卡顿,于是换成primitive图元的方式加载。

简单记录一下遇到的问题。

问题描述

viewer.scene.primitives.add()添加primitive时,地球卡死了,没办法进行放大缩小拖拽等一系列地球操作。 值得注意的是:当用entity得方式是可以加载出来的,只不过会卡顿,但是也没有遇到过场景scene直接卡死的情况。也就是说可以用entity加载但是一旦换成primitive的方式scene就卡死了。

1.刚开始还以为是几何图形太复杂的问题,但是primitie比entity更接近底层,应该比entity渲染更快才对啊,但是相反entity能加载出来,primitive却卡死了,这也就排除了这换个原因。 2.还以为是电脑GPU的问题但是发现scene场景卡死的时候电脑GPU并没有占用多少,甚至为0%,这也就排除了电脑GPU这一项。 原因分析:

排查数据格式。

我们知道加载多边形primitive需要传入经纬度数组

const geometry = new Cesium.PolygonGeometry({ polygonHierarchy: new Cesium.PolygonHierarchy( new Cesium.Cartesian3.fromDegreesArray(geoms) // geoms为经纬度数组 ), extrudedHeight: entityHeight, });

于是就对数据进行一条一条加载。直到遇到scene卡死的那条数据。 知道找到了场景卡死的那条数据: [107.24044625699061, 31.291311316851022, 107.24047198601231, 31.291311468987722, 107.24047250052004, 31.291311493744068, 107.2404730097246, 31.29131156168811, 107.24047350872203, 31.291311672165513,NaN,NaN,107.24047399270674,31.291311824112327, 107.24047445701771, 31.291312016065213]。 注意里面竟然有两条NaN,这里就排查到了是这条数据的问题,导致加载暂停,场景卡死的。所以我查看了原始的WKT格式的数据。 大概长这样:

"MULTIPOLYGON(((107.25941467940206 31.291917660957814,107.25941751810778 31.291915276197532,107.2594241475583 31.29190534342199,107.25941467940206 31.291917660957814)),((107.25942693970325 31.291901710998584,107.2594272814655 31.291901545782753,107.25942773447713 31.291871994888496,107.25949975585885 31.291838338096827,107.25947575902191 31.291838199756548,107.25942693970325 31.291901710998584)))"

注意:这是一个多重多边形,这条数据里包含了两个polygon,于其他数据不一样,其他数据一个multipolygon只包含了一个polygon数据。 由于是需要我这边手动将wkt转为经纬度数组的。所以看了一下写的方法,代码如下:

const geoms = item .replace('MULTIPOLYGON(((', '') .replace(')))', '') .replace(/\s/g, ',') .split(',') .map(item => Number(item));

问题显而易见了,上面这种方法只处理了开头和结尾处的字段,并没有对中间的括号")),((" 进行处理。所以再数组中才会出现NaN这种情况。 从wkt数据里面提取经纬度方法就改为如下:

const geoms = item .replace('MULTIPOLYGON', '') .replace(/[()]/g, '') .replace(/\s/g, ',') .split(',') .map(item => Number(item));

这样就能正常渲染加载primitive了 可以看到中间有条线,将两个polygon连为一体了。 我这里没有做处理,这种情况在项目里并不常见。 如果想要处理的话,可以跟后端商量一下谁来调整。

三维primitive贴地展示:

这个根据自己的接口数据类型来调整。由于我这里数据量较大,所以先定位到具体的bbox再进行渲染数据,这里是每100条进行一次渲染。所以采用: 1.先处理所有的wkt数据转为一个二维经纬度数组。每一条数据为一个生成primitive所需的经纬度数据。 2.遍历生成的二维经纬度数组,每100条加载一次数据。 3.由于需要贴地展示,而如果用GroundPrimitive的话,是可以进行贴地的,但是就没有了拉伸高度,所以还需要用Primitie来加载。 如果需要拉伸高度的话需要根据经纬度点查询位置点的地形高度,然后加上你需要拉伸的立方体高度。

// 采用1先漫游到bbox,2再渲染primitive async loadGeoJSON(data) { const viewer = window.viewer; const chunkSize = 100; // 每100条数据加载一次 console.time(); //1 const coords = []; // 存储所有的坐标点,用于生成primitive和计算bbox for (let i = 0; i Number(item)); coords.push(geoms); } viewer.camera.flyTo({ destination: new Cesium.Rectangle.fromDegrees(...getBBoxByCoords(coords)), }); //2 for (let index = 0; index { // 异步根据经纬度获取地形高度 const height = await getHeigthByLonLat(item[0], item[1]); const entityHeight = height + 50; const geometry = new Cesium.PolygonGeometry({ polygonHierarchy: new Cesium.PolygonHierarchy( new Cesium.Cartesian3.fromDegreesArray(item) ), extrudedHeight: entityHeight, }); return new Cesium.GeometryInstance({ geometry, }); }) ); const primitive = new Cesium.Primitive({ geometryInstances: instances, appearance: new Cesium.MaterialAppearance({ material: new Cesium.Material({ fabric: { type: 'Color', uniforms: { color: new Cesium.Color(1.0, 1.0, 0.0, 1.0), }, }, }), }), }); viewer.scene.primitives.add(primitive); } console.timeEnd(); }, };

根据经纬度查询地形高度:

export const getHeigthByLonLat = async (lon, lat) => { var positions = Cesium.Cartographic.fromDegrees(lon, lat); const updatedPositions = await Cesium.sampleTerrain(window.viewer.terrainProvider, 13, [ positions, ]); if (updatedPositions && updatedPositions.length) { return updatedPositions[0].height; } else { return 0; } }; 总结:如果加载primitive,scene卡死,大概率就是数据的问题,只需要进行排查即可。


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3