当前位置: 首页 > news >正文

Cesium如何高性能的实现上万条道路的流光穿梭效果

大家好,我是日拱一卒的攻城师不浪,专注可视化、数字孪生、前端、nodejs、AI学习、GIS等学习沉淀,这是2024年输出的第20/100篇文章;

前言

在智慧城市的项目中,经常会碰到这样一个需求:领导要求将全市的道路都能够用一个光流效果展示,能够一眼了解整个城市的路网概况。

Cesium高性能实现道路流光,并附修改底图颜色

今天,我们将在Cesium中从零到一实现这样的效果,一共2种方案可供选择:

  • entity实现:性能一般;
  • primitives实现:性能刚刚滴;

entity实现

首先我们需要拿到渲染道路所需要的数据,可以选择geojson数据格式,直接用Cesium.GeoJsonDataSource加载数据。

// 使用entity渲染
let _dataSource = null;
const material = new RoadThroughLine(1000, "/images/spriteline.png");
const onStartEntity = () => {// 道路闪烁线_dataSource = new Cesium.GeoJsonDataSource();_dataSource.load("/json/qdRoad_less.geojson").then(function (dataSource) {// 获取每条道路的实体const entities = dataSource.entities.values;// 设置每条道路的属性,宽度和材质等for (let i = 0; i < entities.length; i++) {let entity = entities[i];entity.polyline.width = 1.7;entity.polyline.material = material;}});viewer.dataSources.add(_dataSource);
};

啊?这就完了?细心的小伙伴可能发现了RoadThroughLine这个类,对,这不是Cesium提供的,而是需要我们自己封装,主要用来给道路赋予材质以及动画渲染的。

entity有一个属性是material,这个属性接收用户自定义材质,这个material需要的值是一个类的实例化,所以需要先去定义好这个类。

新开一个文件定义:

import * as Cesium from "cesium";
// 构造函数
function Spriteline1MaterialProperty(duration, image) {this._definitionChanged = new Cesium.Event(); // Cesium的事件订阅this.duration = duration; // 参数:光流的持续时间this.image = image; // 参数:光流的材质贴图this._time = performance.now(); // 记录时间线
}
Object.defineProperties(Spriteline1MaterialProperty.prototype, {isConstant: {get: function () {return false;},},definitionChanged: {get: function () {return this._definitionChanged;},},color: Cesium.createPropertyDescriptor("color"), // createPropertyDescriptor为color属性创建'setter'和'getter'的函数”duration: Cesium.createPropertyDescriptor("duration"),
});
// 设置材质类型名称
Spriteline1MaterialProperty.prototype.getType = function (time) {return "Spriteline1";
};
// 设置材质的值
Spriteline1MaterialProperty.prototype.getValue = function (time, result) {if (!Cesium.defined(result)) {result = {};}result.image = this.image;result.time =((performance.now() - this._time) % this.duration) / this.duration;return result;
};Cesium.Material.Spriteline1Type = "Spriteline1";
// 着色器代码
Cesium.Material.Spriteline1Source = `
// 定义一个名为czm_getMaterial的函数,它接受一个czm_materialInput类型的参数materialInput
czm_material czm_getMaterial(czm_materialInput materialInput)
{
// 使用Cesium提供的函数来获取默认材质。
czm_material material = czm_getDefaultMaterial(materialInput);// 从传入的materialInput中获取二维纹理坐标。
vec2 st = materialInput.st; 
// 使用texture函数对指定的纹理图像进行采样,并使用fract函数来实现纹理的流动效果。
// 这里的speed变量控制流动速度,用于实现动态效果。
vec4 colorImage = texture(image, vec2(fract(st.s - time), st.t));
// 将采样到的透明度附着给材质的透明度alpha属性
material.alpha = colorImage.a;
// 将采样得到的纹理的rgb值乘以1.5,设置为材质的diffuse颜色。
// 这里乘以1.5是为了增强颜色的亮度。
material.diffuse = colorImage.rgb * 1.5 ;
return material;
}
`;
// _materialCache是Cesium.Material的私有属性,用来缓存自定义材质
Cesium.Material._materialCache.addMaterial(Cesium.Material.Spriteline1Type, {fabric: {type: Cesium.Material.Spriteline1Type,// uniforms的属性都是传给着色器代码的Spriteline1Sourceuniforms: {color: new Cesium.Color(1, 0, 0, 0.5),image: "",transparent: true,time: 20,},source: Cesium.Material.Spriteline1Source,},translucent: function (material) {return true;},
});export default Spriteline1MaterialProperty;

流光材质图片

OK,代码注释已经都标明了,我们只需要实例化这个类,就可以渲染成功了。

primitive

如果是数据量比较小的情况下,entity渲染性能还能接受,但如果是一个市甚至是一个省的街道,那直接就把甲方爸爸卡到医院ICU了~

例如我这里有个数据,json数据达到了将近7万行。

其实这个数据量还不算大,比这大的还有很多,如果用entity的方案的话,再加上向服务器请求数据的时间,大概要等个几秒钟。

所以我们做项目,要尽可能的将性能调优,不放过每一个影响性能的蛀虫代码,因为千里之堤,溃于蚁穴

Primitive是Cesium提供的性能更优的几何体实例,只不过是Entity封装了了更多的常用方法,所以导致其比较重。

Primitive相对轻量化,Cesium在底层对其进行了一些性能调优,并且开发者可以更自由的使用。

let primitives = null;
const onStartPimitive = async () => {// 先拿到道路的json数据const { res } = await getGeojson(jsonUrl);const { features } = res;// primitive的实例集合const instance = [];if (features?.length) {features.forEach((item) => {const arr = item.geometry.coordinates;arr.forEach((el) => {let arr1 = [];el.forEach((_el) => {arr1 = arr1.concat(_el);});// 多线段几何体创建const polyline = new Cesium.PolylineGeometry({positions: Cesium.Cartesian3.fromDegreesArray(arr1),width: 1.7,vertexFormat: Cesium.PolylineMaterialAppearance.VERTEX_FORMAT, // 顶点属性,默认即可});const geometry = Cesium.PolylineGeometry.createGeometry(polyline);instance.push(new Cesium.GeometryInstance({geometry,}));});});// 着色器编写,跟上方entity的基本一致let source = `czm_material czm_getMaterial(czm_materialInput materialInput){czm_material material = czm_getDefaultMaterial(materialInput);vec2 st = materialInput.st;vec4 colorImage = texture(image, vec2(fract((st.s - speed * czm_frameNumber * 0.001)), st.t));material.alpha = colorImage.a * color.a;material.diffuse = colorImage.rgb * 1.5 ;return material;}`;const material = new Cesium.Material({fabric: {uniforms: {color: Cesium.Color.fromCssColorString("#7ffeff"),image: "/images/spriteline.png",speed: 10,},source,},translucent: function () {return true;},});// 材质着色的外观const appearance = new Cesium.PolylineMaterialAppearance();appearance.material = material;const primitive = new Cesium.Primitive({geometryInstances: instance,appearance,asynchronous: false,});primitives = viewer.scene.primitives.add(primitive);}
};

最后

作为cesium的开发者,日常开发过程中,遇到大量几何体的绘制和渲染的需求,建议还是直接无脑上Primitive,性能要比Entity好太多。

做程序,不要以能实现就好为目的,要尽可能追求产品的完美体验,也能不断提高自己开发能力的上限。

【开源地址】:https://github.com/tingyuxuan2302/cesium-vue3-vite/blob/github/src/views/material/throughRoad.vue

有需要进技术产品开发交流群(可视化&GIS)可以加我:brown_7778,也欢迎数字孪生可视化领域的交流合作。

最后,如果觉得文章对你有帮助,也希望可以一键三连👏👏👏,支持我持续开源和分享~

相关文章:

  • python3.9安装pysal库
  • 高通安卓12-固件升级
  • 创意产业如何应对AI的挑战。
  • 超越YOLOv8,飞桨推出精度最高的实时检测器RT-DETR!
  • 【CPP】归并排序
  • 网络知识 思维导图
  • MQTT协议与TCP/IP协议在性能上的区别
  • React AntDesign Layout组件布局刷新页面错乱闪动
  • c#音乐播放器续(联网下载)
  • 【驱动篇】龙芯LS2K0300之单总线驱动
  • 越复杂的CoT越有效吗?Complexity-Based Prompting for Multi-step Reasoning
  • 长亭谛听教程部署和详细教程
  • 【Android面试八股文】你能说一说在平常开发过程中你是如何解决事件冲突问题的吗?
  • 虚幻UE5发送 get、post 请求、读取 json 文件
  • 深入浅出Java的函数式编程
  • Git同步原始仓库到Fork仓库中
  • Java到底能干嘛?
  • JS变量作用域
  • Linux Process Manage
  • Lsb图片隐写
  • Mysql数据库的条件查询语句
  • PHP 小技巧
  • RedisSerializer之JdkSerializationRedisSerializer分析
  • ViewService——一种保证客户端与服务端同步的方法
  • vue和cordova项目整合打包,并实现vue调用android的相机的demo
  • webgl (原生)基础入门指南【一】
  • Yii源码解读-服务定位器(Service Locator)
  • 成为一名优秀的Developer的书单
  • 从PHP迁移至Golang - 基础篇
  • 回顾2016
  • 基于OpenResty的Lua Web框架lor0.0.2预览版发布
  • 基于Vue2全家桶的移动端AppDEMO实现
  • 什么软件可以剪辑音乐?
  • 使用阿里云发布分布式网站,开发时候应该注意什么?
  • 思否第一天
  • 微服务入门【系列视频课程】
  • Prometheus VS InfluxDB
  • puppet连载22:define用法
  • ​HTTP与HTTPS:网络通信的安全卫士
  • # Python csv、xlsx、json、二进制(MP3) 文件读写基本使用
  • (~_~)
  • (2)(2.10) LTM telemetry
  • (24)(24.1) FPV和仿真的机载OSD(三)
  • (8)Linux使用C语言读取proc/stat等cpu使用数据
  • (创新)基于VMD-CNN-BiLSTM的电力负荷预测—代码+数据
  • (仿QQ聊天消息列表加载)wp7 listbox 列表项逐一加载的一种实现方式,以及加入渐显动画...
  • (附源码)计算机毕业设计ssm基于B_S的汽车售后服务管理系统
  • (剑指Offer)面试题41:和为s的连续正数序列
  • (每日持续更新)信息系统项目管理(第四版)(高级项目管理)考试重点整理第3章 信息系统治理(一)
  • (亲测)设​置​m​y​e​c​l​i​p​s​e​打​开​默​认​工​作​空​间...
  • (四)模仿学习-完成后台管理页面查询
  • (算法)Travel Information Center
  • (一)Java算法:二分查找
  • (一)认识微服务
  • (转)http-server应用