Hello大家好,我是日拱一卒的攻城师不浪,专注前端、后端、AI学习、二三维可视化、GIS等学习沉淀,这是2024年输出的第11/100篇文章,欢迎志同道合的朋友一起学习交流;
公众号:攻城师不浪绿泡泡:brown_7778
视频效果
前言
今天再一次带来我的开源
项目Cesium-test
,这个项目主要收集了cesium
在日常业务开发中常用到的一些场景效果的开发。
项目地址
我用我的廉价服务器给它搭了一个窝,感兴趣的可以点击查看(服务器带宽很低,带这种3D肯定很慢,嫌慢的可以直接看上方视频效果,还有动感的音药噢~)
Cesium-test网址:www.brown77.cn:3389
Cesium
首先,我先来简单介绍一下cesium,可能有的同学还不太了解,毕竟业务可能没有涉及到这块领域。
Cesiumjs
一个开源的JavaScript库
,用于在Web浏览器中创建三维
地球仪和二维
地图。它利用了 WebGL
技术,可以在不需要插件的情况下,为用户提供丰富的交互式三维地理信息可视化体验。
应用领域
通过介绍我们不难看出,这个框架主要应用于二三维可视化
以及GIS
领域,可以说非常强大。
Cesium-test
cesium-test
是我近期开源的一个项目,里面集结了一些常用的业务场景效果,包括:
- 粒子效果
- 下雨
- 下雪
- 雾天
- 火焰
- POI点位
- 基础打点
- 聚合
- primitive底层打点(性能佳)
- primitive聚合(性能佳)
- 点位动态弹窗
- 第三方服务加载
- xyz瓦片
- 3D Tiles
- 材质
- 道路闪烁
- 道路流光效果
- 辐射圈
- 圆扩散
- 四色图
- 流动的水面
- 天空盒
- 几何
- 量测
- 点线面绘制
- 态势图、箭头
- 场景
- 水淹模拟
- 热力图
- 时间轴
- 遮罩反选(边界)
- 分析
- 天际线分析
- 高程(限高)分析
其中primitive聚合
这个解决方案还被知名开源项目vue-cesium
所收纳!
这个开源我目前还没用过,因为我用Cesium比较少,不过看项目里场景效果覆盖的已经很全了,用需要的小伙伴可以用用试试,也欢迎给我反馈。
项目中还封装了一些公共的类以及方法,例如:绘制
、测量
、天气类
、聚合类
等等,方便重复使用。
项目初始化
几个关键点:
- cesium token:必须要有,到cesium官网申请,项目跑起来需要用到的
- viewer:视角,3D场景中必备
- 根元素:初始化
canvas
要用到的根元素
js
import { onMounted } from "vue";
import store from "@/store/store.js";
import * as Cesium from "cesium";
// cesium的token,可自行申请
Cesium.Ion.defaultAccessToken =
"xxx";
onMounted(() => {
init();
});
const init = () => {
const viewer = new Cesium.Viewer("cesiumContainer", {
infoBox: false,
timeline: false, // 是否显示时间线控件
// 图层插件
imageryProvider: new Cesium.ArcGisMapServerImageryProvider({
url: "https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer",
}),
// 地形插件
terrainProvider: new Cesium.CesiumTerrainProvider({
url: "http://data.marsgis.cn/terrain",
}),
});
相机
3D场景中必备的相机,当你在上一步初始化成功viewer
之后,就可以在viewer中拿到相机实例了。
js
const store = useStore()
const { viewer } = store.state
viewer.camera.flyTo({
// 从以度为单位的经度和纬度值返回笛卡尔3位置。
destination: Cesium.Cartesian3.fromDegrees(120.36, 36.09, 40000),
orientation: {
// heading:默认方向为正北,正角度为向东旋转,即水平旋转,也叫偏航角。
// pitch:默认角度为-90,即朝向地面,正角度在平面之上,负角度为平面下,即上下旋转,也叫俯仰角。
// roll:默认旋转角度为0,左右旋转,正角度向右,负角度向左,也叫翻滚角
heading: Cesium.Math.toRadians(0.0), // 正东,默认北
pitch: Cesium.Math.toRadians(-90), // 向正下方看
roll: 0.0, // 左右
},
duration: 3, // 飞行时间(s)
})
几何图形
在3D场景中,每一个元素小品实例都是由几何元素所构成渲染的,例如:点
、线
、面
等。
聚合打点
这个需求其实应该在大部分业务项目中都会遇到,属于一个高频知识点,但是在碰到上万甚至是上十万的点位进行聚合
的时候,我发现极大一部分人都会遇到性能
上的问题,官方貌似并没有出手解决这个问题,而且我之前在网上找解决方案也很难找到。
后来我就自己倒腾了好几天,终于研发出一个还不错的解决方案。
其实官方是有现成的entity聚合类的:EntityCluster
,但是这个类在碰到大批量点位的时候,性能卡的一批,因为entity
是基于primitive
的一个封装,而primitive才是底层的几何类,它的性能才是最优的。
因此我就按照这个思路,心想能不能仿照EntityCluster的源码以及它的算法:KDBush
,去构建一个primitiveCluster大类呢,功夫不负有心人,最终还真让我实现了,在项目的src\utils\cesiumCtrl\primitiveCluster.js
里。
但是我发现虽然封装好了这个类,但是还是有很多人不会用,所以怎么用也是个技术活哈哈。
js
const billboardsCollection = viewer.scene.primitives.add(
new Cesium.BillboardCollection()
);
let billboardsCollectionCombine = new Cesium.BillboardCollection();
let primitivesCollection = null;
let primitives = null;
const formatClusterPoint = (features) => {
primitivesCollection = new Cesium.PrimitiveCollection();
billboardsCollectionCombine = new Cesium.BillboardCollection();
var scene = viewer.scene;
let primitivecluster = null;
primitivecluster = new PrimitiveCluster();
//与entitycluster相同设置其是否聚合 以及最大最小值
primitivecluster.enabled = true;
primitivecluster.pixelRange = 60;
primitivecluster.minimumClusterSize = 2;
//后面设置聚合的距离及聚合后的图标颜色显示与官方案例一样
for (let i = 0; i < features.length; i++) {
const feature = features[i];
const coordinates = feature.geometry.coordinates;
const position = Cesium.Cartesian3.fromDegrees(
coordinates[0],
coordinates[1],
2000
);
// 带图片的点
billboardsCollectionCombine.add({
image: "/images/mark-icon.png",
width: 32,
height: 32,
position,
});
}
primitivecluster._billboardCollection = billboardsCollectionCombine;
// 同时在赋值时调用_initialize方法
primitivecluster._initialize(scene);
primitivesCollection.add(primitivecluster);
primitives = viewer.scene.primitives.add(primitivesCollection);
primitivecluster.clusterEvent.addEventListener(
(clusteredEntities, cluster) => {
// 关闭自带的显示聚合数量的标签
cluster.label.show = false;
cluster.billboard.show = true;
cluster.billboard.verticalOrigin = Cesium.VerticalOrigin.BOTTOM;
// 根据聚合数量的多少设置不同层级的图片以及大小
cluster.billboard.image = combineIconAndLabel(
"/images/school-icon.png",
clusteredEntities.length,
64
);
// cluster.billboard.image = "/images/school-icon.png";
cluster.billboard._imageHeight = 60;
cluster.billboard._imageWidth = 60;
cluster.billboard._dirty = false;
cluster.billboard.width = 40;
cluster.billboard.height = 40;
}
);
return primitivecluster;
};
有了这个类,就再也不怕大批量点位渲染卡顿的烦恼啦!
项目思考
其实别看cesium也是一个js框架,但是说实话,对一个没接触过三维的或者GIS方向的前端(比如我)来说,上手还是有一定难度的,因为它里面包含了太多的专业知识需要我们去一一攻坚。
并且,cesium封装了大量的类,毛估大概有几百个!一开始看到密密麻麻的API的时候,头瞬间就大了一圈。
而且,如果想要更好地运用 CesiumJS,不止要会一些三维的知识,学习一定的地理信息系统(GIS)知识也是有一定必要的。例如:
-
地理坐标系统:了解地理坐标系统(如 WGS 84、GCS、PCS 等)的基本概念和区别,以及如何在 CesiumJS 中正确设置和转换坐标系统。
-
地图投影:理解地图投影的原理和不同类型的地图投影(如墨卡托投影、Web墨卡托投影等),以及它们如何在 CesiumJS 中应用。
-
地理数据格式:熟悉常见的地理数据格式,如 GeoJSON、KML、GPX、Shapefile 等,以及如何在 CesiumJS 中加载和处理这些数据格式。
-
矢量数据和栅格数据:了解矢量数据(如点、线、面)和栅格数据(如卫星图像、地形数据)的区别及其在 CesiumJS 中的应用方式。
-
空间分析:掌握基本的空间分析概念,如缓冲区分析、叠加分析、网络分析等,这有助于你在 CesiumJS 中进行更复杂的地理信息处理。
-
地图符号化:理解如何在 CesiumJS 中对地图元素进行符号化,包括设置样式、颜色、图标等,以提高地图的可读性和美观性。
-
图层管理:了解如何在 CesiumJS 中管理和操作图层,包括添加、移除、显示和隐藏图层,以及调整图层顺序和透明度。
-
API 和 SDK 使用:熟悉 CesiumJS 提供的 API 和 SDK,了解如何使用它们来定制地图功能和创建交互式应用。
-
性能优化:掌握一些性能优化的技巧,如数据简化、级别细节(LOD)、视锥体剔除等,以确保 CesiumJS 应用在不同设备上都能流畅运行。
-
三维建模和动画:了解基本的三维建模和动画原理,这可以帮助你在 CesiumJS 中创建更丰富的三维场景和动画效果。
-
实时数据集成:了解如何将实时数据(如传感器数据、社交媒体信息等)集成到 CesiumJS 应用中,以提供动态更新的地理信息服务。
最后
这个项目我已开源,也欢迎感兴趣的小伙伴能够加入进来,一起参与共建(目前还是有一定的star基础的🤭)
如果觉得项目对你有帮助,希望可以随手点一个star
,激励我去开源更多优秀的代码。
如果有在做
数字孪生
或者GIS
方面的同学也可以加我交流:brown_7778,我拉你进交流群。
如果觉得文章对你有帮助,也欢迎一键三连👏👏👏,你的鼓励是支持我持续原创下去的动力~