大家好,我是日拱一卒的攻城师不浪,专注可视化、数字孪生、前端提效、nodejs、AI学习、GIS等学习沉淀,这是2024年输出的第25/100篇文章。
交流合作:brown_7778
前言
在智慧城市的产品设计过程中,产品经常会提一个要求,将不同的区按照其边界进行划分,每个区块通过使用不同的颜色进行高亮凸起的一个3D效果。
这种效果通常也适用于四色安全图
或四色交通图
。
但是有一个问题,这种效果通常涉及到大批量的json数据,如果你用Entity
去加载渲染的话,在数据体量足够大的情况下,性能应该不是很理想。
所以,今天我们就来聊下Cesium中如何实现3D立体面
,并提高其渲染性能。
GeoJSON数据
首先我们还是需要先拿到要渲染的区域的geojson
数据,之前我一直没有提及这是什么数据格式,对于初次接触的小白来讲可能不是很了解,下边来简单介绍一下:
GeoJSON 是一种基于 JSON(JavaScript Object Notation)的地理数据格式
,主要用于存储和传输地理空间数据。
GeoJSON 数据格式的特点
- 基于 JSON:GeoJSON 是一种轻量级的地理数据交换格式,完全基于 JSON,易于人阅读和编写,同时也易于机器解析和生成。
- 地理空间数据:GeoJSON 可以表示各种地理空间数据,如
点
、线
、多边形
等。 - 属性存储:GeoJSON 允许将
属性
与地理特征
关联,这些属性可以存储在特征对象中,通常以键值对的形式存在。 - 坐标系统:GeoJSON 通常使用经度和纬度坐标来表示地理空间数据,坐标系为经纬度坐标系,即
WGS84
。
GeoJSON 数据结构
- Feature:表示单个地理特征,如一个点、一条线或一个多边形。
- Feature Collection:包含多个 Feature 的集合。
- Geometry:表示地理特征的几何形状,如点、线、多边形等。
- Properties:存储与地理特征相关的属性信息。
示例
一个简单的 GeoJSON 文件可能看起来像这样:
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [102.0, 0.5]
},
"properties": {
"name": "Dinagat Islands",
"population": 4567
}
},
{
"type": "Feature",
"geometry": {
"type": "LineString",
"coordinates": [
[102.0, 0.0],
[103.0, 1.0],
[104.0, 0.0],
[105.0, 1.0]
]
},
"properties": {
"name": "Line"
}
}
]
}
在这个示例中:
FeatureCollection
是一个包含多个 Feature 的集合。- 每个
Feature
包含一个geometry
和一个properties
。 geometry
可以是Point
(点)、LineString
(线)或Polygon
(多边形)等。
好了,接下来我要渲染整个青岛市10个
区/县的色块,可以先看下这惊人的数据量
大概有23万
条数据!
我一开始尝试了一下使用Entity
去渲染,RTX4070
的独显,16G
的运行内存,数据是放在本地的,大约耗时6s左右才渲染完成。
然而我换成了Primitive
之后,耗时在2s左右,提高了60%
多的速度!
几何体构建
先渲染面PolygonGeometry
const polygon = new Cesium.PolygonGeometry({
// 包含孔的多边形层次结构,polygonArray是我们拿到的经纬度数据
polygonHierarchy: new Cesium.PolygonHierarchy(
Cesium.Cartesian3.fromDegreesArray(polygonArray)
),
// 计算的顶点属性,选择为每个面实例添加颜色外观
vertexFormat: Cesium.PerInstanceColorAppearance.VERTEX_FORMAT,
// 设置面的拉伸高度
extrudedHeight: 100,
});
由于我们要渲染10
个区域,所以要构建10个几何体实例,使用GeometryInstance
GeometryInstance:几何实例化允许一个 Geometry 对象位于多个不同位置并具有唯一颜色。
附着颜色
// 提前预设好要附着的颜色
const colorArrs = [
"AQUAMARINE",
"BEIGE",
"CORNFLOWERBLUE",
"DARKORANGE",
"GOLD",
"GREENYELLOW",
"LIGHTPINK",
"ORANGERED",
"YELLOWGREEN",
"TOMATO",
];
const instances = []
const geometry = Cesium.PolygonGeometry.createGeometry(polygon);
instances.push(
new Cesium.GeometryInstance({
id: `polygon-${i}`,
geometry: geometry,
// 几何体实例属性设置
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(
Cesium.Color.fromAlpha(Cesium.Color[colorArrs[i]], 0.6)
),
show: new Cesium.ShowGeometryInstanceAttribute(true),
},
})
);
Primitive参数配置
使用primitive
渲染,并且将所有区的polygon
进行合并渲染,提高渲染的效率。
const primitive = new Cesium.Primitive({
releaseGeometryInstances: true,
geometryInstances: instances,
appearance: new Cesium.PerInstanceColorAppearance({
translucent: true, // 当 true 时,几何体应该是半透明的,因此 PerInstanceColorAppearance#renderState 启用了 alpha 混合。
closed: false, // 当 true 时,几何体应该是关闭的,因此 PerInstanceColorAppearance#renderState 启用了背面剔除。
})
});
viewer.scene.primitives.add(primitive);
OK,这样一个区域轮廓凸起就渲染成功了。
完整代码和源数据可从下方链接获取,如果开源对你有帮助,也希望点一个star
,支持我开源更多代码。
【开源地址】:github.com/tingyuxuan2…
有需要进技术产品开发交流群(可视化&GIS)可以加我:brown_7778,也欢迎
数字孪生可视化领域
的交流合作。
最后,如果觉得文章对你有帮助,也希望可以一键三连👏👏👏,支持我持续开源和分享~