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

第八章 Cesium 实现动态模型拖尾效果:从原理到完整实现

效果图

在三维地理信息可视化中,为移动模型添加拖尾效果可以极大增强视觉表现力,常用于模拟飞行器尾迹、导弹轨迹等动态场景。本文将详细介绍如何使用 Cesium 引擎实现模型拖尾效果,并提供完整可运行的代码示例。

实现原理

Cesium 中的粒子系统 (ParticleSystem) 是实现拖尾效果的核心,其原理是:

  • 持续发射大量微小粒子
  • 为粒子设置物理运动规律
  • 控制粒子生命周期中的颜色和透明度变化
  • 将粒子发射器绑定到移动模型上

通过这种方式,可以模拟出自然流畅的拖尾效果,且可以通过参数调整实现不同的视觉效果。

完整代码实现

以下是带有详细注释的完整代码:

Cesium模型拖尾效果实现

<!DOCTYPE html>
<html lang="zh-CN"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>cesium模型拖尾效果</title><!-- 加载Cesium核心库和样式 --><script src="https://cesium.com/downloads/cesiumjs/releases/1.95/Build/Cesium/Cesium.js"></script><link href="https://cesium.com/downloads/cesiumjs/releases/1.95/Build/Cesium/Widgets/widgets.css" rel="stylesheet"><style>body {margin: 0;padding: 0;overflow: hidden;height: 100vh;}#cesiumContainer {width: 100%;height: 100%;}</style>
</head><body><div id="cesiumContainer"></div><script>// 初始化Cesium Viewerconst viewer = new Cesium.Viewer("cesiumContainer", {shouldAnimate: true,  // 启用动画});// 清除默认图层viewer.imageryLayers.removeAll();// 添加ArcGIS卫星影像图层(高清卫星地图)viewer.imageryLayers.addImageryProvider(new Cesium.ArcGisMapServerImageryProvider({url: 'https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer'}));// 定义飞机初始位置(经纬度和高度)const planePosition = Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883, 800.0);// 粒子系统相对于模型的偏移量const particlesOffset = new Cesium.Cartesian3(-8.950115473940969,34.852766731753945,-30.235411095432937,);// 计算相机位置(基于飞机位置和偏移量)const cameraLocation = Cesium.Cartesian3.add(planePosition,particlesOffset,new Cesium.Cartesian3(),);// 重置相机视角函数const resetCamera = function () {viewer.camera.lookAt(cameraLocation, new Cesium.Cartesian3(-450, -300, 200));};resetCamera();// 创建粒子图像(圆形粒子)let particleCanvas;function getImage() {if (!Cesium.defined(particleCanvas)) {particleCanvas = document.createElement("canvas");particleCanvas.width = 20;particleCanvas.height = 20;const context2D = particleCanvas.getContext("2d");// 绘制圆形粒子context2D.beginPath();context2D.arc(8, 8, 8, 0, Cesium.Math.TWO_PI, true);context2D.closePath();context2D.fillStyle = "rgb(255, 255, 255)";context2D.fill();}return particleCanvas;}// 向场景添加飞机模型const hpr = new Cesium.HeadingPitchRoll(0.0, Cesium.Math.PI_OVER_TWO, 0.0);const orientation = Cesium.Transforms.headingPitchRollQuaternion(planePosition,hpr,);const entity = viewer.entities.add({model: {uri: "../../../public/scene.gltf", // 模型路径(请替换为实际模型路径)scale: 10.0, // 缩放比例},position: planePosition,orientation: orientation,// 模型加载回调onLoad: (model) => {console.log("模型加载成功", model);},onError: (error) => {console.error("模型加载失败", error);},});// 创建粒子系统的模型矩阵(确定粒子系统位置)const translationOffset = Cesium.Matrix4.fromTranslation(particlesOffset,new Cesium.Matrix4(),);const translationOfPlane = Cesium.Matrix4.fromTranslation(planePosition,new Cesium.Matrix4(),);const particlesModelMatrix = Cesium.Matrix4.multiplyTransformation(translationOfPlane,translationOffset,new Cesium.Matrix4(),);// 定义火箭推进器粒子系统参数const rocketOptions = {numberOfSystems: 50.0,       // 粒子系统数量iterationOffset: 0.1,        // 迭代偏移量cartographicStep: 0.000001,  // 经纬度步长baseRadius: 0.0005,          // 基础半径// 粒子颜色选项colorOptions: [{minimumRed: 1.0,green: 0.5,minimumBlue: 0.05,alpha: 1.0,},{red: 0.9,minimumGreen: 0.6,minimumBlue: 0.01,alpha: 1.0,},{red: 0.8,green: 0.05,minimumBlue: 0.09,alpha: 1.0,},{minimumRed: 1,minimumGreen: 0.05,blue: 0.09,alpha: 1.0,},],};// 定义彗星尾迹粒子系统参数const cometOptions = {numberOfSystems: 100.0,      // 粒子系统数量iterationOffset: 0.003,      // 迭代偏移量cartographicStep: 0.0000001, // 经纬度步长baseRadius: 0.0005,          // 基础半径// 粒子颜色选项colorOptions: [{red: 0.6,green: 0.6,blue: 0.6,alpha: 1.0,},{red: 0.6,green: 0.6,blue: 0.9,alpha: 0.9,},{red: 0.5,green: 0.5,blue: 0.7,alpha: 0.5,},],};// 粒子运动函数(控制粒子的物理行为)let scratchCartesian3 = new Cesium.Cartesian3();let scratchCartographic = new Cesium.Cartographic();const forceFunction = function (options, iteration) {return function (particle, dt) {// 限制时间增量,避免大跳变dt = Cesium.Math.clamp(dt, 0.0, 0.05);// 计算粒子位置变化scratchCartesian3 = Cesium.Cartesian3.normalize(particle.position,new Cesium.Cartesian3(),);scratchCartesian3 = Cesium.Cartesian3.multiplyByScalar(scratchCartesian3,-40.0 * dt,scratchCartesian3,);scratchCartesian3 = Cesium.Cartesian3.add(particle.position,scratchCartesian3,scratchCartesian3,);// 转换为地理坐标进行计算scratchCartographic = Cesium.Cartographic.fromCartesian(scratchCartesian3,Cesium.Ellipsoid.WGS84,scratchCartographic,);// 计算角度,使粒子呈圆形分布const angle = (Cesium.Math.PI * 2.0 * iteration) / options.numberOfSystems;iteration += options.iterationOffset;// 应用水平和垂直方向的偏移scratchCartographic.longitude +=Math.cos(angle) * options.cartographicStep * 30.0 * dt;scratchCartographic.latitude +=Math.sin(angle) * options.cartographicStep * 30.0 * dt;// 将地理坐标转换回笛卡尔坐标particle.position = Cesium.Cartographic.toCartesian(scratchCartographic);};};// 创建粒子系统const matrix4Scratch = new Cesium.Matrix4();let scratchAngleForOffset = 0.0;const scratchOffset = new Cesium.Cartesian3();const imageSize = new Cesium.Cartesian2(15.0, 15.0);// 创建多个粒子系统的函数function createParticleSystems(options, systemsArray) {const length = options.numberOfSystems;for (let i = 0; i < length; ++i) {// 计算每个粒子系统的角度偏移scratchAngleForOffset = (Math.PI * 2.0 * i) / options.numberOfSystems;scratchOffset.x += options.baseRadius * Math.cos(scratchAngleForOffset);scratchOffset.y += options.baseRadius * Math.sin(scratchAngleForOffset);// 创建发射器模型矩阵const emitterModelMatrix = Cesium.Matrix4.fromTranslation(scratchOffset,matrix4Scratch,);// 随机选择颜色const color = Cesium.Color.fromRandom(options.colorOptions[i % options.colorOptions.length],);// 获取粒子力函数const force = forceFunction(options, i);// 创建并添加粒子系统const item = viewer.scene.primitives.add(new Cesium.ParticleSystem({image: getImage(),              // 粒子图像startColor: color,              // 初始颜色endColor: color.withAlpha(0.0), // 结束颜色(透明)particleLife: 3.5,              // 粒子生命周期speed: 0.00005,                 // 粒子速度imageSize: imageSize,           // 粒子大小emissionRate: 30.0,             // 发射率emitter: new Cesium.CircleEmitter(0.1), // 发射器形状lifetime: 0.1,                  // 发射器生命周期updateCallback: force,          // 更新回调函数modelMatrix: particlesModelMatrix, // 模型矩阵emitterModelMatrix: emitterModelMatrix, // 发射器模型矩阵}));systemsArray.push(item);}}// 创建两种粒子系统数组const rocketSystems = [];const cometSystems = [];createParticleSystems(rocketOptions, rocketSystems);createParticleSystems(cometOptions, cometSystems);// 控制粒子系统显示的工具函数function showAll(systemsArray, show) {const length = systemsArray.length;for (let i = 0; i < length; ++i) {systemsArray[i].show = show;}}// 切换不同拖尾效果的选项const options = [{text: "彗星尾迹",onselect: function () {showAll(rocketSystems, false);showAll(cometSystems, true);resetCamera();},},{text: "火箭推进器",onselect: function () {showAll(cometSystems, false);showAll(rocketSystems, true);resetCamera();},},];// 默认显示彗星尾迹showAll(cometSystems, true);</script>
</body>
</html>
代码解析
  1. 初始化 Cesium 环境

    • 创建 Viewer 实例并配置基础参数
    • 移除默认图层,添加卫星影像图层提升视觉效果
  2. 模型与相机设置

    • 定义模型初始位置和姿态
    • 计算合适的相机视角,确保模型和拖尾效果清晰可见
  3. 粒子系统核心

    • 创建粒子图像:使用 canvas 绘制圆形粒子
    • 定义粒子系统参数:包括数量、颜色、生命周期等
    • 实现粒子运动函数:控制粒子的物理行为,使其呈现拖尾效果
  4. 多样化拖尾效果

    • 定义两种不同风格的拖尾效果(火箭推进器和彗星尾迹)
    • 通过参数差异实现不同的视觉表现:颜色、密度、扩散范围等
自定义与扩展
  1. 修改粒子属性

    • 调整imageSize改变粒子大小
    • 修改particleLife控制拖尾长度
    • 调整emissionRate改变粒子密度
  2. 更改拖尾颜色

    • colorOptions数组中添加或修改颜色配置
    • 可以使用Cesium.Color的静态方法创建更丰富的颜色
  3. 实现模型移动

    • 添加模型位置更新逻辑
    • 同步更新粒子系统的位置矩阵,保持拖尾与模型的相对位置
  4. 性能优化

    • 减少numberOfSystemsemissionRate可提升性能
    • 复杂场景下可考虑使用 Billboard 替代部分粒子

通过以上方法,可以实现各种炫酷的模型拖尾效果,为三维地理信息可视化增添更多动态元素和视觉冲击力。


文章转载自:

http://DAa2BGVQ.nbfkk.cn
http://pkCAsloH.nbfkk.cn
http://ZsLNt3i4.nbfkk.cn
http://2s1SdMQc.nbfkk.cn
http://LBVp0t6w.nbfkk.cn
http://AnxtWzeN.nbfkk.cn
http://XF5AOkPJ.nbfkk.cn
http://N2tu1EzW.nbfkk.cn
http://krIOlE8Z.nbfkk.cn
http://lBO6Dw7T.nbfkk.cn
http://HBw8k3NI.nbfkk.cn
http://lef0RBKx.nbfkk.cn
http://WrKhViHs.nbfkk.cn
http://wFe2na8F.nbfkk.cn
http://SI1YXPCD.nbfkk.cn
http://lROeZJk5.nbfkk.cn
http://hDbQ2yTh.nbfkk.cn
http://jOJm7EkJ.nbfkk.cn
http://8ao59HHx.nbfkk.cn
http://8QxENMpd.nbfkk.cn
http://qf27IKab.nbfkk.cn
http://YuUS1pwv.nbfkk.cn
http://tCRH0jxx.nbfkk.cn
http://w5iZqqhB.nbfkk.cn
http://srglUY6z.nbfkk.cn
http://Vm4cmOQC.nbfkk.cn
http://RCI13OgX.nbfkk.cn
http://31lEzlSd.nbfkk.cn
http://aWNnwWbG.nbfkk.cn
http://5l0fOCQq.nbfkk.cn
http://www.dtcms.com/a/369617.html

相关文章:

  • java基础学习(四):类 - 了解什么是类,类中都有什么?
  • VMWare上搭建大数据集群
  • TGRSL-2017《Fast Spectral Clustering with Anchor Graph》
  • 雅菲奥朗SRE知识墙分享(七):『可观测性的定义与实践』
  • SQLServer死锁监测方案:如何使用XE.Core解析xel文件里包含死锁扩展事件的死锁xml
  • 人脑算力究竟有多强?1000 到 100万 TOPS 的秘密!
  • 各种exec 系列函数
  • 推荐收藏!5款低代码工具,告别复杂开发!
  • 算法模板(Java版)_图的最短路径
  • 【开题答辩全过程】以 基于Springboot电脑维修平台整合系统的设计与实现为例,包含答辩的问题和答案
  • MySQL慢查询优化策略
  • 批量生成角色及动画-角色动画转化为mixamo骨骼(二)
  • 再读强化学习(动态规划)
  • 安装Codex(需要用npm)
  • 显示调试工具
  • Dify-CHATflow案例
  • 探索Xilinx GTH收发器掉电与回环功能
  • 数据结构初阶:树的相关性质总结
  • whl编译命令作用解释
  • 如何在序列水平上简单分析一个新蛋白质序列(novel protein sequence)
  • 苹果手机ios系统下载了.apk文件程序怎么安装?
  • 认知篇#11:计算机视觉研究领域的大致分类
  • 如何高效比对不同合同版本差异,避免法律风险?
  • 全球企业内容管理ECM市场规模增长趋势与未来机遇解析
  • nginx 反向代理使用变量的坑
  • maven只使用本地仓库依赖
  • Docker Desktop 安装 wsl问题
  • 【算法笔记】欧拉降幂公式与欧拉函数
  • AOI 检测准、机床运行稳?杰和 AR707 撑起工控 “精准 + 高效”
  • 解决“找不到 pip”