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

Cesium材质特效

文章目录

  • 0.引言
  • 1.视频材质
  • 2.分辨率尺度
  • 3.云
  • 4.雾
  • 5.动态水面
  • 6.雷达扫描
  • 7.流动线
  • 8.电子围栏
  • 9.粒子烟花
  • 10.粒子火焰
  • 11.粒子天气

0.引言

现有的gis开发方向较流行的是webgis开发,其中Cesium是一款开源的WebGIS库,主要用于实时地球和空间数据的可视化和分析。它提供了丰富的地图显示和数据可视化功能,并能实现三维可视化开发。本文将使用一些特殊的材质,如视频材质、自定义材质和Cesium内置的一些特殊效果类、粒子系统等实现一些特效场景的模拟,包括云、雾、动态水面、雷达扫描、流动线、电子围栏、粒子烟花、粒子火焰及粒子天气等。

1.视频材质

对于通过Entity方式和Primitive方式创建的几何实体,下面介绍如何给几何实体贴上一个特殊的材质,即视频材质。
视频资源网址: https://cesium.com/public/SandcastleSampleData/big-buck-bunny_trailer.mp4
(1)实现代码
  在这里插入图片描述

6_1_视频材质.html
<!DOCTYPE html>
<html lang="en">  <head>  <meta charset="UTF-8">  <meta http-equiv="X-UA-Compatible" content="IE=edge">  <meta name="viewport" content="width=device-width, initial-scale=1.0">  <title>视频</title>  <script src="./Build/Cesium/Cesium.js"></script>  <link rel="stylesheet" href="./Build/Cesium/Widgets/widgets.css">  <style>  html,  body,  #cesiumContainer {  width: 100%;  height: 100%;  margin: 0;  padding: 0;  }  .toolbar {  position: absolute;  top: 10px;  left: 20px;  background-color: rgb(0, 0, 0, 0);  }  </style>  
</head>  <body>  <div id="cesiumContainer">  </div>  <div class="toolbar">  <select id="dropdown" onchange="change()">  <option value="edit1">视频材质</option>  <option value="edit2">视频重复</option>  </select>  </div>  <video id="myVideo" muted="true" autoplay="true" loop="true" style="display: none;">  <source src="./vedio/big-buck-bunny_trailer.mp4" type="video/mp4">  </video>  <script>  Cesium.Ion.defaultAccessToken = '你的token';  var viewer = new Cesium.Viewer("cesiumContainer", {  timeline: false,  animation: false,  fullscreenButton: false,  });  //viewer.scene.globe.depthTestAgainstTerrain = false;  const videoElement = document.getElementById("myVideo");  //将视频元素与模拟时钟同步  let synchronizer = new Cesium.VideoSynchronizer({  clock: viewer.clock,  element: videoElement  });  viewer.clock.shouldAnimate = true;  var sphere = viewer.entities.add({  position: Cesium.Cartesian3.fromDegrees(104, 39, 2200),  ellipsoid: {  radii: new Cesium.Cartesian3(1000, 1000, 1000),  material: videoElement,  },  });  //相机视角锁定sphere  viewer.trackedEntity = sphere;  //改变视频重复个数  var isRepeat = false;  sphere.ellipsoid.material.repeat = new Cesium.CallbackProperty(  function (result) {  if (isRepeat) {  result.x = 8;  result.y = 8;  } else {  result.x = 1;  result.y = 1;  }  return result;  },  false  );  var dropdown = document.getElementById('dropdown');  function change() {  switch (dropdown.value) {  case 'edit1':  isRepeat = false;  break;  case 'edit2':  isRepeat = true;  break;  default:  break;  }  }  </script>  
</body>  </html>

(2)结果显示
  在这里插入图片描述
   在这里插入图片描述

2.分辨率尺度

在Cesium中,可以通过viewer.resolutionScale获取或者设置渲染分辨率的缩放比例。当该属性值小于1.0时,可以改善性能不佳的设备的显示效果,而当该属性值大于1.0时,将以更快的速度呈现分辨率,并缩小比例,从而提高视觉保真度。例如,如果窗口的尺寸为640像素×480像素,则将viewer.resolutionScale的值设置为0.5,会导致场景以320像素×240像素渲染,之后设置为2.0,会导致场景以1280像素×960像素渲染。
(1)实现代码
  在这里插入图片描述

6_2_分辨率尺度.html
<!DOCTYPE html>
<html lang="en">  <head>  <meta charset="UTF-8">  <meta http-equiv="X-UA-Compatible" content="IE=edge">  <meta name="viewport" content="width=device-width, initial-scale=1.0">  <title>材质特效篇_分辨率尺度</title>  <script src="./Build/Cesium/Cesium.js"></script>  <link rel="stylesheet" href="./Build/Cesium//Widgets/widgets.css">  <style>  html,  body,  #cesiumContainer {  width: 100%;  height: 100%;  margin: 0;  padding: 0;  overflow: hidden;  }  .toolbar {  position: absolute;  top: 10px;  left: 20px;  background-color: rgba(0, 0, 0, 0.6);  }  </style>  </head>  <body>  <div id="cesiumContainer">  </div>  <div class="toolbar">  <label style="color: white;">分辨率尺度</label> <br />  <input type="range" max="2" step="0.1" oninput="change()" id="R" value="1">  <input type="text" style="width:70px; " id="resolutionValue" value="1" onchange="change2()">  </div>  <script>  Cesium.Ion.defaultAccessToken = '你的token';  var viewer = new Cesium.Viewer("cesiumContainer", {  animation: false, //是否显示动画工具  timeline: false,  //是否显示时间轴工具  fullscreenButton: false,  //是否显示全屏按钮工具  });  var tileset = viewer.scene.primitives.add(  new Cesium.Cesium3DTileset({  url: './倾斜摄影/大雁塔3DTiles/tileset.json',  }));  viewer.zoomTo(tileset);  function change() {  //拿到滑动条当前值  var resolutionScale = Number(R.value);  //将值约束在0.1和2.0之间  resolutionScale = Cesium.Math.clamp(resolutionScale, 0.1, 2.0);  //文本框显示当前值  resolutionValue.value = resolutionScale;  //修改分辨率尺度  viewer.resolutionScale = resolutionScale;  }  function change2() {  var resolutionScale = Number(resolutionValue.value);  //将值约束在0.1和2.0之间  resolutionScale = Cesium.Math.clamp(resolutionScale, 0.1, 2.0);  R.value = resolutionScale;  change();  }  </script>  </body>  </html>

(2)结果显示
调整前:
  在这里插入图片描述
调整后:
  在这里插入图片描述

3.云

在模拟实际场景时,可以通过CloudCollection类在场景中渲染云,同时支持手动修改云的大小、亮度等来模拟积云。基本思路为先使用CloudCollection类创建一个云集合,然后在云集合中添加定义的不同样式的云。
(1)实现代码
  在这里插入图片描述

6_3_云.html
<!DOCTYPE html>
<html lang="en">  <head>  <meta charset="utf-8" />  <meta http-equiv="X-UA-Compatible" content="IE=edge" />  <meta name="viewport"  content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no" />  <meta name="description" content="Fog post process">  <meta name="cesium-sandcastle-labels" content="Showcases, Post Processing">  <title>材质特效篇_云</title>  <link rel="stylesheet" href="./Build/Cesium/Widgets/widgets.css">  <script type="text/javascript" src="./Build/Cesium/Cesium.js"></script>  </head>  
<style>  html,  body,  #cesiumContainer {  width: 100%;  height: 100%;  margin: 0;  padding: 0;  overflow: hidden;  }  .toolbar {  position: absolute;  top: 10px;  left: 20px;  color: white;  background-color: rgba(0, 0, 0, 0.6);  }  
</style>  <body>  <div id="cesiumContainer"></div>  <div class="toolbar">  <label>X轴尺寸</label> <br />  <input type="range" min="5" max="50" step="1" oninput="changeScale()" id="ScaleX" value="25">  <input type="text" style="width:70px; " id="ScaleXValue" value="25" onchange="changeScaleX()"> <br>  <label>Y轴尺寸</label> <br />  <input type="range" min="5" max="50" step="1" oninput="changeScale()" id="ScaleY" value="12">  <input type="text" style="width:70px; " id="ScaleYValue" value="12" onchange="changeScaleY()"> <br>  <label>亮度</label> <br />  <input type="range" min="0" max="1" step="0.01" oninput="changeBrightness()" id="Brightness" value="1">  <input type="text" style="width:70px; " id="BrightnessValue" value="1" onchange="changeBrightnessValue()"> <br>  </div>  <script>  Cesium.Ion.defaultAccessToken = '你的token';  var viewer = new Cesium.Viewer("cesiumContainer", {  animation: false, //是否显示动画工具  timeline: false,  //是否显示时间轴工具  fullscreenButton: false,  //是否显示全屏按钮工具  });  //创建并添加云集合  var clouds = viewer.scene.primitives.add(  new Cesium.CloudCollection({  noiseDetail: 16.0,  })  );  //添加云  var cloud = clouds.add({  position: Cesium.Cartesian3.fromDegrees(114.39264, 30.52252, 100),  scale: new Cesium.Cartesian2(25, 12),  slice: 0.36,  brightness: 1,  })  //设置相机位置及方向  viewer.camera.lookAt(  Cesium.Cartesian3.fromDegrees(114.39264, 30.52252, 100),  new Cesium.Cartesian3(30, 30, -10)  );  var ScaleX = document.getElementById('ScaleX'); //X轴尺寸  var ScaleXValue = document.getElementById('ScaleXValue'); //ScaleX滑动条值  var ScaleY = document.getElementById('ScaleY'); //Y轴尺寸  var ScaleYValue = document.getElementById('ScaleYValue'); //ScaleY滑动条值  var Brightness = document.getElementById('Brightness'); //亮度  var BrightnessValue = document.getElementById('BrightnessValue'); //亮度滑动条值  //Scale滑动条  function changeScale() {  //拿到scaleX滑动条当前值  var sX = Number(ScaleX.value);  //文本框显示当前值  ScaleXValue.value = sX;  //拿到scaleY滑动条当前值  var sY = Number(ScaleY.value);  //x轴旋转文本框显示当前值  ScaleYValue.value = sY;  //修改云的比例  cloud.scale = new Cesium.Cartesian2(sX, sY);  }  //ScaleX文本框  function changeScaleX() {  //拿到scaleX文本框的值并赋值给滑动条  ScaleX.value = Number(ScaleXValue.value);  changeScale();  }  //ScaleY文本框  function changeScaleY() {  //拿到scaleY文本框的值并赋值给滑动条  ScaleY.value = Number(ScaleYValue.value);  changeScale();  }  //Brightness滑动条  function changeBrightness() {  //拿到Brightness滑动条滑动条当前值  var brightness = Number(Brightness.value);  //文本框显示当前值  BrightnessValue.value = brightness;  //修改云的亮度  cloud.brightness = brightness;  }  //Brightness文本框  function changeBrightnessValue() {  //拿到文本框的值并赋值给滑动条  Brightness.value = Number(BrightnessValue.value);  changeBrightness();  }  </script>  
</body>  </html>

(2)结果显示
  在这里插入图片描述

4.雾

Cesium在1.46版本之后新增了场景后处理功能。所谓场景后处理,我们可以将其理解为一个不断叠加的过程。例如,我们拍了一张照片,拍完之后觉得该照片亮度不够,于是我们在该照片的基础上进行了亮度的调整,得到了一张新照片,然后觉得新照片不够好看,又在新照片的基础上添加了滤镜,此后我们可能还会进行多次处理,直到最后得到的照片满足我们的要求为止,这个过程就类似于场景后处理,即我们在绘制场景时可能会不断地对场景进行一些处理,将最终符合我们要求的处理结果绘制到屏幕上。下面通过Cesium的场景后处理功能来实现雾的效果。
(1)实现代码
  在这里插入图片描述

6_4_雾效果.html
<!DOCTYPE html>
<html lang="en">  <head>  <meta charset="utf-8" />  <meta http-equiv="X-UA-Compatible" content="IE=edge" />  <meta name="viewport"  content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no" />  <meta name="description" content="Fog post process">  <meta name="cesium-sandcastle-labels" content="Showcases, Post Processing">  <title>材质特效篇_雾效果</title>  <link rel="stylesheet" href="./Build/Cesium/Widgets/widgets.css">  <script type="text/javascript" src="./Build/Cesium/Cesium.js"></script>  </head>  
<style>  html,  body,  #cesiumContainer {  width: 100%;  height: 100%;  margin: 0;  padding: 0;  overflow: hidden;  }  
</style>  <body>  <div id="cesiumContainer"></div>  <script>  Cesium.Ion.defaultAccessToken = '你的token';  var viewer = new Cesium.Viewer("cesiumContainer", {  animation: false, //是否显示动画工具  timeline: false,  //是否显示时间轴工具  fullscreenButton: false,  //是否显示全屏按钮工具  });  var tileset = viewer.scene.primitives.add(  new Cesium.Cesium3DTileset({  url: './倾斜摄影/大雁塔3DTiles/tileset.json',  }));  viewer.zoomTo(tileset);  var fragmentShaderSource =  `//计算每个渲染顶点和视点(相机)的距离  float getDistance(sampler2D depthTexture, vec2 texCoords)  {  float depth = czm_unpackDepth(texture2D(depthTexture, texCoords));  if (depth == 0.0) {  return czm_infinity;  }  vec4 eyeCoordinate = czm_windowToEyeCoordinates(gl_FragCoord.xy, depth);  return -eyeCoordinate.z / eyeCoordinate.w;  }  //按距离进行插值  float interpolateByDistance(vec4 nearFarScalar, float distance)  {  float startDistance = nearFarScalar.x;  float startValue = nearFarScalar.y;  float endDistance = nearFarScalar.z;  float endValue = nearFarScalar.w;  float t = clamp((distance - startDistance) / (endDistance - startDistance), 0.0, 1.0);  return mix(startValue, endValue, t);  }  //计算透明度  vec4 alphaBlend(vec4 sourceColor, vec4 destinationColor)  {  return sourceColor * vec4(sourceColor.aaa, 1.0) + destinationColor * (1.0 - sourceColor.a);  }  uniform sampler2D colorTexture; //颜色纹理 内置变量  uniform sampler2D depthTexture; //深度纹理  内置变量  varying vec2 v_textureCoordinates;  //屏幕采样点坐标 内置变量  uniform vec4 fogByDistance; //自定义属性 外部变量  uniform vec4 fogColor;  //自定义属性 外部变量  void main(void)  {  float distance = getDistance(depthTexture, v_textureCoordinates);  vec4 sceneColor = texture2D(colorTexture, v_textureCoordinates);  float blendAmount = interpolateByDistance(fogByDistance, distance);  vec4 finalFogColor = vec4(fogColor.rgb, fogColor.a * blendAmount);  gl_FragColor = alphaBlend(finalFogColor, sceneColor);  }`;  var postProcessStage = new Cesium.PostProcessStage({  //片源着色器  fragmentShader: fragmentShaderSource,  uniforms: {  fogByDistance: new Cesium.Cartesian4(0, 0, 600, 1.0), //距离  fogColor: Cesium.Color.WHITE, //颜色  },  })  viewer.scene.postProcessStages.add(postProcessStage);  </script>  
</body>  </html>

(2)结果显示
  在这里插入图片描述

5.动态水面

模拟水面效果也是Cesium场景中常见的功能,例如,有的项目可能通过绘制实体面,并设置材质为淡蓝色来模拟水面。但是,在实际生活中,水面往往不是静止的而是动态的,下面通过修改水面的材质来实现动态水面的效果。动态水面的具体实现思路为:先准备一张水面纹理图片,然后通过Primitive方式创建一个矩形实体,使用EllipsoidSurfaceAppearance定义一个水面材质,并给矩形实体设置该材质,即可实现简单的动态水面效果。
(1)实现代码
  在这里插入图片描述

6_5_动态水面.html
<!DOCTYPE html>
<html lang="en">  <head>  <meta charset="UTF-8">  <meta http-equiv="X-UA-Compatible" content="IE=edge">  <meta name="viewport" content="width=device-width, initial-scale=1.0">  <title>材质特效篇_动态水面</title>  <script src="./Build/Cesium/Cesium.js"></script>  <link rel="stylesheet" href="./Build/Cesium/Widgets/widgets.css">  <style>  html,  body,  #cesiumContainer {  width: 100%;  height: 100%;  margin: 0;  padding: 0;  overflow: hidden;  }  </style>  </head>  <body>  <div id="cesiumContainer">  </div>  <script>  Cesium.Ion.defaultAccessToken = '你的token';  var viewer = new Cesium.Viewer("cesiumContainer", {  animation: false, //是否显示动画工具  timeline: false,  //是否显示时间轴工具  fullscreenButton: false,  //是否显示全屏按钮工具  terrainProvider: Cesium.createWorldTerrain()  });  viewer.scene.globe.depthTestAgainstTerrain = true;//开启深度检测后 会有高程遮挡效果  var rectangle = new Cesium.GeometryInstance({  geometry: new Cesium.RectangleGeometry({  rectangle: Cesium.Rectangle.fromDegrees(95.0, 39.0, 100.0, 42.0),  height: 3500.0  })  });  //定义外观  var rectangleAppearance = new Cesium.EllipsoidSurfaceAppearance({  aboveGround: true,  material: new Cesium.Material({  fabric:  {  type: 'Water',        //材质类型  uniforms: {  //baseWaterColor: new Cesium.Color.fromBytes(24, 173, 247, 100),//基础颜色  normalMap: './RasterImage/图片/动态水面.jpg',        //法线纹理贴图  frequency: 100.0,        //波的数量  animationSpeed: 0.01,        //水波震动速度  amplitude: 10.0                //振幅大小  },  }  }),  //重写shader,修改水面的透明度  fragmentShaderSource: 'varying vec3 v_positionMC;\n' +  'varying vec3 v_positionEC;\n' +  'varying vec2 v_st;\n' +  'void main()\n' +  '{\n' +  'czm_materialInput materialInput;\n' +  'vec3 normalEC = normalize(czm_normal3D * czm_geodeticSurfaceNormal(v_positionMC, vec3(0.0), vec3(1.0)));\n' +  '#ifdef FACE_FORWARD\n' +  'normalEC = faceforward(normalEC, vec3(0.0, 0.0, 1.0), -normalEC);\n' +  '#endif\n' +  'materialInput.s = v_st.s;\n' +  'materialInput.st = v_st;\n' +  'materialInput.str = vec3(v_st, 0.0);\n' +  'materialInput.normalEC = normalEC;\n' +  'materialInput.tangentToEyeMatrix = czm_eastNorthUpToEyeCoordinates(v_positionMC, materialInput.normalEC);\n' +  'vec3 positionToEyeEC = -v_positionEC;\n' +  'materialInput.positionToEyeEC = positionToEyeEC;\n' +  'czm_material material = czm_getMaterial(materialInput);\n' +  '#ifdef FLAT\n' +  'gl_FragColor = vec4(material.diffuse + material.emission, material.alpha);\n' +  '#else\n' +  'gl_FragColor = czm_phong(normalize(positionToEyeEC), material, czm_lightDirectionEC);\n' +  'gl_FragColor.a=0.55;\n' +  '#endif\n' +  '}\n'  });  var addRectangleGeometry = new Cesium.Primitive({  geometryInstances: rectangle,  appearance: rectangleAppearance  })  viewer.scene.primitives.add(addRectangleGeometry);  viewer.camera.flyTo({  destination: Cesium.Cartesian3.fromDegrees(108, 42, 6000000),  })  </script>  </body>  </html>

(2)结果显示
  在这里插入图片描述
   在这里插入图片描述

6.雷达扫描

使用飞机或无人机沿着飞行路线进行雷达扫描的效果在实际应用中是很常见的。在Cesium中实现雷达扫描效果的方法有很多,可以通过对Entity实体贴纹理并对材质进行不断的旋转来实现,或者通过着色器重写Entity实体的材质shader来实现。比较而言,前者对于新手来说更容易实现,下面通过第一种方法来模拟雷达扫描效果。
(1)实现代码
  在这里插入图片描述

6_6_雷达扫描.html
<!DOCTYPE html>
<html lang="en">  <head>  <meta charset="UTF-8">  <meta http-equiv="X-UA-Compatible" content="IE=edge">  <meta name="viewport" content="width=device-width, initial-scale=1.0">  <title>材质特效篇_雷达扫描</title>  <script src="./Build/Cesium/Cesium.js"></script>  <link rel="stylesheet" href="./Build/Cesium//Widgets/widgets.css">  <style>  html,  body,  #cesiumContainer {  width: 100%;  height: 100%;  margin: 0;  padding: 0;  overflow: hidden;  }  </style>  </head>  <body>  <div id="cesiumContainer">  </div>  <script>  Cesium.Ion.defaultAccessToken = '你的token';  var viewer = new Cesium.Viewer("cesiumContainer", {  animation: false, //是否显示动画工具  timeline: false,  //是否显示时间轴工具  fullscreenButton: false,  //是否显示全屏按钮工具  });  var rotation = 0; //纹理旋转角度  var amount = 4;        //旋转变化量  var rader = {  position: Cesium.Cartesian3.fromDegrees(114.40372, 30.52252),  ellipse: {  semiMajorAxis: 300.0,  semiMinorAxis: 300.0,  //指定材质  material: new Cesium.ImageMaterialProperty({  image: './RasterImage/图片/color.png',  color: new Cesium.Color(1.0, 0.0, 0.0, 0.7),  }),  // 不设置高度则无法渲染外框线  height: 0.0,  //heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,  //外边框  outline: true,  outlineWidth: 2,  outlineColor: new Cesium.Color(1.0, 1.0, 0.0, 1.0),  //纹理旋转角度通过CallbackProperty回调  stRotation: new Cesium.CallbackProperty(function () {  rotation += amount;  if (rotation >= 360 || rotation <= -360) {  rotation = 0;  }  //度数转弧度  return Cesium.Math.toRadians(rotation);  }, false)  }  }  //将rader添加进entity集合  viewer.entities.add(rader)  var point = viewer.entities.add({  position: Cesium.Cartesian3.fromDegrees(114.40372, 30.52252),  point: {  pixelSize: 10,  color: Cesium.Color.RED,  heightReference: Cesium.HeightReference.CLAMP_TO_GROUND  }  });  viewer.camera.setView({  destination: Cesium.Cartesian3.fromDegrees(114.40372, 30.52252, 2000)  });  </script>  </body>  </html>

(2)结果显示
  在这里插入图片描述
   在这里插入图片描述

7.流动线

Cesium中有许多封装好的内置纹理,如条纹、颜色、虚线、棋盘、水面等,但是这些内置纹理大多是静态的,并不能满足我们在实际开发中的需求,这时就需要我们通过自定义材质来达到特定的纹理效果。
自定义材质可以通过现有的内置材质派生,也可以使用Fabric和GLSL来自定义。但是在实际开发中,为了减少代码冗余,我们通常将常用的自定义材质封装成一个个Material材质类以便复用,下面将介绍如何封装一个自定义流动线材质类。
(1)实现代码
  在这里插入图片描述

6_7_流动线.html
<!DOCTYPE html>
<html lang="en">  <head>  <meta charset="UTF-8">  <meta http-equiv="X-UA-Compatible" content="IE=edge">  <meta name="viewport" content="width=device-width, initial-scale=1.0">  <title>材质特效篇_流动线</title>  <script src="./Build/Cesium/Cesium.js"></script>  <link rel="stylesheet" href="./Build/Cesium/Widgets/widgets.css">  <script src="./Build/js/jquery.min.js"></script>  <style>  html,  body,  #cesiumContainer {  width: 100%;  height: 100%;  margin: 0;  padding: 0;  overflow: hidden;  }  </style>  
</head>  <body>  <div id="cesiumContainer">  </div>  <script>  Cesium.Ion.defaultAccessToken =  '你的token';  var viewer = new Cesium.Viewer("cesiumContainer", {  animation: true, //是否显示动画工具  timeline: true, //是否显示时间轴工具  fullscreenButton: false, //是否显示全屏按钮工具  });  /* console.log('selectionIndicator',viewer.selectionIndicator);  $(".cesium-viewer-selectionIndicatorContainer").css('display','none'); */  viewer.scene.fxaa = false  viewer.scene.postProcessStages.fxaa.enabled = false;  var supportsImageRenderingPixelated = viewer.cesiumWidget._supportsImageRenderingPixelated;  if (supportsImageRenderingPixelated) {  var vtxf_dpr = window.devicePixelRatio;  while (vtxf_dpr >= 2.0) {  vtxf_dpr /= 2.0;  }  viewer.resolutionScale = vtxf_dpr;  }  //创建构造函数  function PolylineTrailLinkMaterialProperty(color, duration) {  this._definitionChanged = new Cesium.Event();  this._color = undefined;  this._colorSubscription = undefined;  this.color = color;  this.duration = duration;  this._time = (new Date()).getTime();  }  //Object.defineProperties() 方法直接在一个对象上定义新的属性或修改现有属性,并返回该对象。  //Object.defineProperties(obj, props)  //obj:在其上定义或修改属性的对象   props:要定义其可枚举属性或修改的属性描述符的对象。  Object.defineProperties(PolylineTrailLinkMaterialProperty.prototype, {  isConstant: {  get: function () {  return false;  }  },  definitionChanged: {  get: function () {  return this._definitionChanged;  }  },  color: Cesium.createPropertyDescriptor('color')  });  PolylineTrailLinkMaterialProperty.prototype.getType = function (time) {  return 'PolylineTrailLink';  }  PolylineTrailLinkMaterialProperty.prototype.getValue = function (time, result) {  if (!Cesium.defined(result)) {  result = {};  }  result.color = Cesium.Property.getValueOrClonedDefault(this._color, time, Cesium.Color.WHITE, result.color);  result.image = Cesium.Material.PolylineTrailLinkImage;  result.time = (((new Date()).getTime() - this._time) % this.duration) / this.duration;  return result;  }  PolylineTrailLinkMaterialProperty.prototype.equals = function (other) {  return this === other || (other instanceof PolylineTrailLinkMaterialProperty &amp;&amp; Property.equals(this._color,  other._color))  };  Cesium.PolylineTrailLinkMaterialProperty = PolylineTrailLinkMaterialProperty;  //纹理类型  Cesium.Material.PolylineTrailLinkType = 'PolylineTrailLink';  //纹理图片  Cesium.Material.PolylineTrailLinkImage = "./RasterImage/图片/color.png";  //纹理资源  Cesium.Material.PolylineTrailLinkSource =  "czm_material czm_getMaterial(czm_materialInput materialInput)\n\  {\n\  float time = czm_frameNumber/100.0;\n\  czm_material material = czm_getDefaultMaterial(materialInput);\n\  vec2 st = materialInput.st;\n\  vec4 colorImage = texture2D(image, vec2(fract(3.0*st.s - time), st.s));\n\  material.alpha = colorImage.a * color.a;\n\  material.diffuse = (colorImage.rgb+color.rgb)/2.0;\n\  return material;\n\  }";  //time越小,速度越慢  //colorImage控制纹理  //fract中 3.0是纹理个数  -time是逆时针 +time是顺时针  //alpha 透明度  //diffuse 颜色  /* "czm_material czm_getMaterial(czm_materialInput materialInput)\n\  {\n\  czm_material material = czm_getDefaultMaterial(materialInput);\n\  vec2 st = materialInput.st;\n\  vec4 colorImage = texture2D(image, vec2(fract(st.s - time), st.t));\n\  material.alpha = colorImage.a * color.a;\n\  material.diffuse = (colorImage.rgb+color.rgb)/2.0;\n\  return material;\n\  }" */  //添加自定义材质  Cesium.Material._materialCache.addMaterial(Cesium.Material.PolylineTrailLinkType, {  fabric: {  //纹理类型  type: Cesium.Material.PolylineTrailLinkType,  //传递给着色器的外部属性  uniforms: {  color: new Cesium.Color(0.0, 0.0, 0.0, 1),  image: Cesium.Material.PolylineTrailLinkImage,  time: 0  },  //纹理资源  source: Cesium.Material.PolylineTrailLinkSource  },  //是否透明  translucent: function (material) {  return true;  }  })  var line = viewer.entities.add({  name: 'PolylineTrailLink',  polyline: {  positions: Cesium.Cartesian3.fromDegreesArray([  118.286419, 31.864436,  119.386419, 31.864436,  119.386419, 32.864436,  118.686419, 32.864436,  ]),  width: 10,  //设置材质为自定义材质  material: new Cesium.PolylineTrailLinkMaterialProperty(  Cesium.Color.fromBytes(255, 0, 0).withAlpha(0.8),  /* 1000 */  ),  }  });  viewer.flyTo(line)  </script>  
</body>  </html>

(2)结果显示
  在这里插入图片描述
   在这里插入图片描述

8.电子围栏

下面封装一个自定义电子围栏材质类,能够对Entity墙体贴动态材质,实现电子围栏效果。封装自定义电子围栏材质类的流程和封装自定义流动线材质类的流程一样。
(1)实现代码
  在这里插入图片描述

6_8_电子围栏.html
<!DOCTYPE html>
<html lang="en">  <head>  <meta charset="UTF-8">  <meta http-equiv="X-UA-Compatible" content="IE=edge">  <meta name="viewport" content="width=device-width, initial-scale=1.0">  <title>材质特效篇_电子围栏</title>  <script src="./Build/Cesium/Cesium.js"></script>  <link rel="stylesheet" href="./Build/Cesium/Widgets/widgets.css">  <style>  html,  body,  #cesiumContainer {  width: 100%;  height: 100%;  margin: 0;  padding: 0;  overflow: hidden;  }  </style>  
</head>  <body>  <div id="cesiumContainer">  </div>  <script>  Cesium.Ion.defaultAccessToken = '你的token';  var viewer = new Cesium.Viewer("cesiumContainer", {  animation: false, //是否显示动画工具  timeline: false,  //是否显示时间轴工具  fullscreenButton: false,  //是否显示全屏按钮工具  });  function DynamicWallMaterialProperty(color, duration) {  this._definitionChanged = new Cesium.Event();  this._color = undefined;  this._colorSubscription = undefined;  this.color = color;  this.duration = duration;  this._time = (new Date()).getTime();  }  Object.defineProperties(DynamicWallMaterialProperty.prototype, {  isConstant: {  get: function () {  return false;  }  },  definitionChanged: {  get: function () {  return this._definitionChanged;  }  },  color: Cesium.createPropertyDescriptor('color')  });  DynamicWallMaterialProperty.prototype.getType = function (time) {  return 'DynamicWall';  }  DynamicWallMaterialProperty.prototype.getValue = function (time, result) {  if (!Cesium.defined(result)) {  result = {};  }  result.color = Cesium.Property.getValueOrClonedDefault(this._color, time, Cesium.Color.WHITE, result.color);  result.image = Cesium.Material.DynamicWallImage;  result.time = (((new Date()).getTime() - this._time) % this.duration) / this.duration;  return result;  }  DynamicWallMaterialProperty.prototype.equals = function (other) {  return this === other || (other instanceof DynamicWallMaterialProperty &amp;&amp; Property.equals(this._color, other._color))  };  Cesium.DynamicWallMaterialProperty = DynamicWallMaterialProperty;  Cesium.Material.DynamicWallType = 'DynamicWall';  Cesium.Material.DynamicWallImage = "./RasterImage/图片/color.png";//图片  Cesium.Material.DynamicWallSource =  `czm_material czm_getMaterial(czm_materialInput materialInput)  {  float time = czm_frameNumber/100.0;  czm_material material = czm_getDefaultMaterial(materialInput);  vec2 st = materialInput.st;  vec4 colorImage = texture2D(image, vec2(fract(1.0*st.t - time), st.t));  material.alpha = colorImage.a * color.a;  material.diffuse = (colorImage.rgb+color.rgb)/2.0;  return material;  }`      //由上到下  //添加自定义材质  Cesium.Material._materialCache.addMaterial(Cesium.Material.DynamicWallType, {  fabric: {  //纹理类型  type: Cesium.Material.DynamicWallType,  //传递给着色器的外部属性  uniforms: {  color: new Cesium.Color(0.0, 0.0, 0.0, 1),  image: Cesium.Material.DynamicWallImage,  time: 0  },  //纹理资源  source: Cesium.Material.DynamicWallSource  },  //是否透明  translucent: function (material) {  return true;  }  })  var dynamicWall = viewer.entities.add({  wall: {  positions: Cesium.Cartesian3.fromDegreesArrayHeights([  118.286419, 31.864436, 20000.0,  119.386419, 31.864436, 20000.0,  119.386419, 32.864436, 20000.0,  118.286419, 32.864436, 20000.0,  118.286419, 31.864436, 20000.0,  ]),  material: new Cesium.DynamicWallMaterialProperty(Cesium.Color.fromBytes(255, 200, 10).withAlpha(0.8), 3000),  }  })  viewer.flyTo(dynamicWall)  </script>  
</body>  </html>

(2)结果显示
  在这里插入图片描述
   在这里插入图片描述

9.粒子烟花

粒子系统表示三维计算机图形学中用于模拟一些特定模糊现象的技术,而这些现象用其他传统的渲染技术难以实现其真实感的物理运动规律。经常使用粒子系统模拟的现象有烟花、火焰、雨水及雪花等。简而言之,粒子系统就是一种用于模拟真实现象的图形技术,是由一个个的小图像集合而成的,从远处看会形成一个“复杂”的场景来模拟一些现象。
Cesium粒子系统不仅是多个小图像的直接集合,而且允许控制单个粒子的寿命、速度、位置等属性,也正是由于粒子的各种属性可以控制,才能够模拟各种复杂的场景。粒子系统效果在电影和电子游戏中应用广泛。下面使用粒子系统模拟烟花爆炸效果。
(1)实现代码
  在这里插入图片描述

6_9_粒子烟花.html
<!DOCTYPE html>
<html lang="en">  <head>  <meta charset="utf-8" />  <meta http-equiv="X-UA-Compatible" content="IE=edge" />  <meta name="description" content="Particle system fireworks.">  <meta name="cesium-sandcastle-labels" content="Beginner, Showcases">  <title>材质特效篇_粒子烟花</title>  <link rel="stylesheet" href="./Build/Cesium/Widgets/widgets.css">  <script src="./Build/Cesium/Cesium.js"></script>  </head>  
<style>  html,  body,  #cesiumContainer {  width: 100%;  height: 100%;  margin: 0;  padding: 0;  overflow: hidden;  }  
</style>  <body>  <div id="cesiumContainer"></div>  <script>  Cesium.Ion.defaultAccessToken = '你的token';  var viewer = new Cesium.Viewer("cesiumContainer", {  animation: false, //是否显示动画工具  timeline: false,  //是否显示时间轴工具  fullscreenButton: false,  //是否显示全屏按钮工具  shouldAnimate: true,  //必须开启,自动播放动画  });  /* Cesium.Math.setRandomNumberSeed(315); */  //东北天到指定原点变换矩阵,将粒子系统从模型坐标转换为世界坐标  const modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(  Cesium.Cartesian3.fromDegrees(114.39664, 30.52052)  );  //粒子发射器高度  const emitterInitialLocation = new Cesium.Cartesian3(0.0, 0.0, 100.0);  //粒子贴图  var particleCanvas;  //绘制图形  function getImage() {  if (!Cesium.defined(particleCanvas)) {  particleCanvas = document.createElement("canvas");  particleCanvas.width = 20;  particleCanvas.height = 20;  const context2D = particleCanvas.getContext("2d");  context2D.beginPath();  //圆心x 圆心y 半径 起始角度 终止角度 逆时针  context2D.arc(10, 10, 8, 0, Cesium.Math.TWO_PI, true);  context2D.closePath();  context2D.fillStyle = "rgba(255, 255, 255, 1)";  context2D.fill();  }  return particleCanvas;  }  /* var radar = viewer.entities.add({  rectangle: {  coordinates: Cesium.Rectangle.fromDegrees(114.40072, 30.51952, 114.40572, 30.52452),  material: new Cesium.ImageMaterialProperty({  //image: new Cesium.CallbackProperty(drawCanvas, false),  image:getImage(),  //transparent: true  }),  }  }); */  /* const minimumExplosionSize = 30.0; //最小爆炸尺寸  const maximumExplosionSize = 100.0;  //最大爆炸尺寸 */  var particlePixelSize = new Cesium.Cartesian2(7.0, 7.0);  //粒子大小  var burstNum = 400.0;  //爆炸粒子个数  var lifetime = 10.0;    //粒子系统发射粒子的时间  var numberOfFireworks = 20.0;  //烟花个数  //创建烟花函数  function createFirework(offset, color, bursts) {  var position = Cesium.Cartesian3.add(  emitterInitialLocation,  offset,  new Cesium.Cartesian3()  );  //从发射位置创建表示转换的Matrix4  var emitterModelMatrix = Cesium.Matrix4.fromTranslation(position);  //随机设置烟花的生命周期  /* const size = Cesium.Math.randomBetween(  minimumExplosionSize,  maximumExplosionSize  );  const normalSize =  (size - minimumExplosionSize) /  (maximumExplosionSize - minimumExplosionSize);  const minLife = 0.3;  const maxLife = 1.0;  const life = normalSize * (maxLife - minLife) + minLife; */  viewer.scene.primitives.add(  new Cesium.ParticleSystem({  image: getImage(),  //粒子贴图  startColor: color,  //粒子在其生命初期的颜色  endColor: color.withAlpha(0.0),//粒子在其生命结束的颜色  //particleLife: life, //粒子生命周期  particleLife: 1, //粒子生命周期  speed: 100.0, //粒子扩散速度  imageSize: particlePixelSize, //粒子像素大小  emissionRate: 0,  //每秒要发射的粒子数  emitter: new Cesium.SphereEmitter(0.1), //系统粒子发射器  bursts: bursts, //粒子爆炸,ParticleBurst 的数组  lifetime: lifetime, //粒子系统发射粒子的时间  //updateCallback: force,  //每帧都要调用一次回调函数以更新粒子  modelMatrix: modelMatrix, //将粒子系统从模型转换为世界坐标的4x4转换矩阵。  emitterModelMatrix: emitterModelMatrix,//在粒子系统局部坐标系内转换粒子系统发射器的4x4转换矩阵  loop: true //粒子循环爆发  })  );  }  //粒子发射器偏移量范围  var xMin = -100.0;  var xMax = 100.0;  var yMin = -80.0;  var yMax = 100.0;  var zMin = -50.0;  var zMax = 50.0;  //设置随机颜色选项数组  var colorOptions = [  {  minimumRed: 0.75,  green: 0.0,  minimumBlue: 0.8,  alpha: 1.0,  },  {  red: 0.0,  minimumGreen: 0.75,  minimumBlue: 0.8,  alpha: 1.0,  },  {  red: 0.0,  green: 0.0,  minimumBlue: 0.8,  alpha: 1.0,  },  {  minimumRed: 0.75,  minimumGreen: 0.75,  blue: 0.0,  alpha: 1.0,  },  ];  //创建烟花  for (let i = 0; i < numberOfFireworks; ++i) {  var x = Cesium.Math.randomBetween(xMin, xMax);  var y = Cesium.Math.randomBetween(yMin, yMax);  var z = Cesium.Math.randomBetween(zMin, zMax);  var offset = new Cesium.Cartesian3(x, y, z);  //使用提供的选项创建随机颜色  var color = Cesium.Color.fromRandom(  colorOptions[i % colorOptions.length]  );  //粒子爆炸,ParticleBurst 的数组,在周期时间发射粒子爆发  var bursts = [];  for (let j = 0; j < 3; ++j) {  bursts.push(  new Cesium.ParticleBurst({  time: Cesium.Math.nextRandomNumber() * lifetime, //粒子系统生命周期开始后以秒为单位的时间,将发生爆发  minimum: burstNum, //爆发中发射的最小粒子数。  maximum: burstNum, //爆发中发射的最大粒子数。  })  );  }  //传参,创建烟花  createFirework(offset, color, bursts);  }  viewer.scene.camera.setView({  destination:  Cesium.Cartesian3.fromDegrees(114.39664, 30.52052, 2000)  })  </script>  
</body>  </html>

(2)结果显示
  在这里插入图片描述
   在这里插入图片描述

10.粒子火焰

下面使用Cesium粒子系统模拟火焰燃烧效果。
(1)实现代码
  在这里插入图片描述

6_10_粒子火焰.html
<!DOCTYPE html>
<html lang="en">  <head>  <meta charset="utf-8" />  <meta http-equiv="X-UA-Compatible" content="IE=edge" />  <meta name="description" content="Particle system fireworks.">  <meta name="cesium-sandcastle-labels" content="Beginner, Showcases">  <title>材质特效篇_粒子火焰</title>  <link rel="stylesheet" href="./Build/Cesium/Widgets/widgets.css">  <script src="./Build/Cesium/Cesium.js"></script>  </head>  
<style>  html,  body,  #cesiumContainer {  width: 100%;  height: 100%;  margin: 0;  padding: 0;  overflow: hidden;  }  
</style>  <body>  <div id="cesiumContainer"></div>  <script>  Cesium.Ion.defaultAccessToken = '你的token';  var viewer = new Cesium.Viewer("cesiumContainer", {  animation: false, //是否显示动画工具  timeline: false,  //是否显示时间轴工具  fullscreenButton: false,  //是否显示全屏按钮工具  shouldAnimate: true,  //必须开启 自动播放动画  });  // 加载飞机模型  var entity = viewer.entities.add({  model: {  uri: './3D格式数据/glb/Cesium_Air.glb',  minimumPixelSize: 64  },  position: Cesium.Cartesian3.fromDegrees(114.39264, 30.52252, 100)  });  //视角追踪模型  viewer.trackedEntity = entity;  //计算把粒子系统从模型坐标系转到世界坐标系指定原点的矩阵  const modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(  Cesium.Cartesian3.fromDegrees(114.39264, 30.52252, 100)  );  //计算模型坐标系的平移矩阵  function computeEmitterModelMatrix() {  //定义粒子发射器的方向、俯仰角以及翻滚角  var hpr = Cesium.HeadingPitchRoll.fromDegrees(0.0, 0.0, 0.0, new Cesium.HeadingPitchRoll());  //定义一个由平移,旋转和缩放定义的仿射变换  var trs = new Cesium.TranslationRotationScale();  //火焰位置  //平移  trs.translation = Cesium.Cartesian3.fromElements(2.5, 4.0, 1.0, new Cesium.Cartesian3());  //旋转  trs.rotation = Cesium.Quaternion.fromHeadingPitchRoll(hpr, new Cesium.Quaternion());  return Cesium.Matrix4.fromTranslationRotationScale(trs, new Cesium.Matrix4());  }  var particleSystem = new Cesium.ParticleSystem({  image: './RasterImage/图片/fire.png',  startScale: 1.0,  //开始比例  endScale: 4.0,  //结束比例  particleLife: 1.0,   //粒子生命周期  speed: 5.0, //粒子速度  imageSize: new Cesium.Cartesian2(20, 20),   //粒子图形尺寸  emissionRate: 5.0,  //每秒发射粒子个数  lifetime: 16.0,   //粒子系统发射粒子的时间  modelMatrix: modelMatrix,  //将粒子系统从模型转换为世界坐标的4x4转换矩阵  emitterModelMatrix: computeEmitterModelMatrix() //在粒子系统局部坐标系内转换粒子系统发射器的4x4转换矩阵  })  viewer.scene.primitives.add(particleSystem);  </script>  
</body>  </html>

(2)结果显示
  在这里插入图片描述
   在这里插入图片描述

11.粒子天气

常见的粒子特效还有雨、雪等粒子天气特效,下面使用Cesium粒子系统模拟天气特效,包括下雨天与下雪天两种情况。
(1)实现代码
  在这里插入图片描述

6_11_粒子天气.html
<!DOCTYPE html>
<html lang="en">  <head>  <meta charset="utf-8" />  <meta http-equiv="X-UA-Compatible" content="IE=edge" />  <meta name="description" content="Particle system fireworks.">  <meta name="cesium-sandcastle-labels" content="Beginner, Showcases">  <title>材质特效篇_粒子天气</title>  <link rel="stylesheet" href="./Build/Cesium/Widgets/widgets.css">  <script src="./Build/Cesium/Cesium.js"></script>  </head>  
<style>  html,  body,  #cesiumContainer {  width: 100%;  height: 100%;  margin: 0;  padding: 0;  overflow: hidden;  }  .toolbar {  position: absolute;  top: 10px;  left: 20px;  background-color: rgb(0, 0, 0, 0);  }  
</style>  <body>  <div id="cesiumContainer"></div>  <div class="toolbar">  <select id="dropdown" onchange="change()">  <option value="snow"></option>  <option value="rain"></option>  <option value="null">null</option>  </select>  </div>  <script>  Cesium.Ion.defaultAccessToken = '你的token';  var viewer = new Cesium.Viewer("cesiumContainer", {  animation: false, //是否显示动画工具  timeline: false,  //是否显示时间轴工具  fullscreenButton: false,  //是否显示全屏按钮工具  shouldAnimate: true,  //必须开启  terrainProvider: Cesium.createWorldTerrain(),  });  //粒子特效位置  var position = new Cesium.Cartesian3.fromDegrees(114.39664, 30.52052, 2000);  var modelMatrix = new Cesium.Matrix4.fromTranslation(position)  //模拟下雪天粒子特效常量定义  const snowRadius = 100000.0; //下雪的范围半径  const minimumSnowImageSize = new Cesium.Cartesian2(10, 10); //雪花最小尺寸  const maximumSnowImageSize = new Cesium.Cartesian2(20, 20); //雪花最大尺寸  //创建Cartesian3对象,用于在回调函数中实时更新粒子位置  var snowGravityScratch = new Cesium.Cartesian3();  //粒子更新回调函数  function snowUpdate (particle) {  //计算提供的笛卡尔坐标系的标准化形式  Cesium.Cartesian3.normalize(  particle.position,  //要标准化的笛卡尔坐标  snowGravityScratch  //结果存储对象  );  //将提供的笛卡尔分量乘以标准的标量  Cesium.Cartesian3.multiplyByScalar(  snowGravityScratch, //要缩放的笛卡尔坐标  //要与之相乘的标量,负值代表粒子位置下降即粒子从上往下落  Cesium.Math.randomBetween(-30.0, -300.0),  snowGravityScratch  //结果存储对象  );  //粒子位置根据snowGravityScratch变化  Cesium.Cartesian3.add(  particle.position,  snowGravityScratch,  particle.position  );  };  // 雨  const rainRadius = 100000.0; //下雨的范围半径  const rainImageSize = new Cesium.Cartesian2(20, 35); //15,30分别代表宽高  var rainGravityScratch = new Cesium.Cartesian3();  //粒子更新回调函数  function rainUpdate (particle) {  //计算提供的笛卡尔坐标系的标准化形式  Cesium.Cartesian3.normalize(  particle.position,  //要标准化的笛卡尔坐标  rainGravityScratch  //结果存储对象  );  //将提供的笛卡尔分量乘以标准的标量  Cesium.Cartesian3.multiplyByScalar(  rainGravityScratch,  //要缩放的笛卡尔坐标  -1000.0,             //要与之相乘的标量,雨比雪下落速度快的多 所以这个值负的多点  rainGravityScratch   //结果存储对象  );  //粒子位置根据rainGravityScratch变化  Cesium.Cartesian3.add(  particle.position,  rainGravityScratch,  particle.position  );  };  //粒子系统-雪配置项  var snowOption = {  modelMatrix: modelMatrix, //将粒子系统从模型转换为世界坐标的4x4转换矩阵。  lifetime: 15.0, //粒子系统发射粒子的时间(以秒为单位)  emitter: new Cesium.SphereEmitter(snowRadius),  //该系统的粒子发射器  startScale: 0.5,  //在粒子寿命开始时应用于粒子图像的初始比例  endScale: 1.0,  //在粒子寿命结束时应用于粒子图像的最终比例。  image: "./RasterImage/图片/snowflake_particle.png", //粒子贴图  emissionRate: 7000.0, //每秒要发射的粒子数  startColor: Cesium.Color.WHITE.withAlpha(0.0),  //粒子在其生命初期的颜色。  endColor: Cesium.Color.WHITE.withAlpha(1.0),  //粒子寿命结束时的颜色。  minimumImageSize: minimumSnowImageSize, //设置宽度的最小范围,以高度为单位,在该范围上可以随机缩放粒子图像的尺寸(以像素为单位)  maximumImageSize: maximumSnowImageSize, //设置最大宽度边界,以高度为单位,在该边界以下可以随机缩放粒子图像的尺寸(以像素为单位)  updateCallback: snowUpdate, //每帧都要调用一次回调函数以更新粒子  }  //粒子系统-雨配置项  var rainOption = {  modelMatrix: modelMatrix,//将粒子系统从模型转换为世界坐标的4x4转换矩阵。  lifetime: 15.0,//粒子系统发射粒子的时间(以秒为单位)  emitter: new Cesium.SphereEmitter(rainRadius),//该系统的粒子发射器  startScale: 1.0,//在粒子寿命开始时应用于粒子图像的初始比例  endScale: 0.0,//在粒子寿命结束时应用于粒子图像的最终比例。  image: "./RasterImage/图片/circular_particle.png",//粒子贴图  emissionRate: 9000.0,//每秒要发射的粒子数  startColor: new Cesium.Color(1, 1, 1, 0.0),//粒子在其生命初期的颜色。  endColor: new Cesium.Color(1.0, 1.0, 1.0, 0.98),//粒子寿命结束时的颜色。  imageSize: rainImageSize,//粒子贴图尺寸  updateCallback: rainUpdate,//每帧都要调用一次回调函数以更新粒子  }  //默认下雪天  viewer.scene.primitives.add(new Cesium.ParticleSystem(snowOption));  //下拉框回调函数  var dropdown = document.getElementById('dropdown');  function change() {  switch (dropdown.value) {  case 'snow':  viewer.scene.primitives.removeAll();  viewer.scene.primitives.add(new Cesium.ParticleSystem(snowOption));  break;  case 'rain':  viewer.scene.primitives.removeAll();  viewer.scene.primitives.add(new Cesium.ParticleSystem(rainOption));  break;  case 'null':  viewer.scene.primitives.removeAll();  break;  default:  break;  }  }  //设置相机视角  /* viewer.scene.camera.setView({  destination:  Cesium.Cartesian3.fromDegrees(114.39664, 30.40052, 10000),  orientation: {  heading: 4.731089976107251,  pitch: -0.32003481981370063,  },  }) */  //设置相机初始位置  viewer.scene.camera.setView({  destination: new Cesium.Cartesian3(-2318006.190591779, 5016113.738321363,3239729.8052793955),  orientation: {  heading: 5.0433812878480655,  pitch: -0.25943108890985744,  roll: 0.000002292722656171975  },  duration: 0.0  });  </script>  
</body>  </html>

(2)结果显示
  在这里插入图片描述
  在这里插入图片描述


cesium文章涉及数据

参考资料:
[1] 郭明强. 《WebGIS之Cesium三维软件开发》; 2023-04-01 [accessed 2024-01-27].
[2] WaqarLeaver. Cesium开源water材质和粒子效果示例代码研究; 2021-05-30 [accessed 2024-01-27].
[3] GIS兵墩墩. C2——cesium流动特效; 2020-11-04 [accessed 2024-01-27].
[4] 那那那那那么长的哲尘. Cesium实现流动线/动态纹理; 2024-01-11 [accessed 2024-01-27].

相关文章:

Cesium材质特效

文章目录 0.引言1.视频材质2.分辨率尺度3.云4.雾5.动态水面6.雷达扫描7.流动线8.电子围栏9.粒子烟花10.粒子火焰11.粒子天气 0.引言 现有的gis开发方向较流行的是webgis开发&#xff0c;其中Cesium是一款开源的WebGIS库&#xff0c;主要用于实时地球和空间数据的可视化和分析。…...

华为产业链之车载激光雷达

一、智能汽车 NOA 加快普及&#xff0c;L3 上路利好智能感知硬件 1、感知层是 ADAS 最重要的一环 先进驾驶辅助系统 &#xff08;ADAS&#xff0c; Advanced driver-assistance system&#xff09;分“感知层、决策层、执行层”三个层级&#xff0c;其中感知层是最重要的一环…...

java的Object类的hasCode()和ToString()

&#xff08;1&#xff09;hasCode解释 hashCode()是Object类中定义的方法&#xff0c;用于返回对象的哈希码值。哈希码值是一个整数&#xff0c;用于在哈希表等数据结构中快速定位对象。 在Java中&#xff0c;哈希码值的计算是基于对象的内存地址的。默认情况下&#xff0c;ha…...

php数组算法(1)判断一维数组和多元数组中的元素是否相等并输出键值key

在php中&#xff0c;如何判断[1,0,1]和[ [0, 0, 0],//体质正常 [1, 0, 0],//气虚体质 [0, 1, 0],//血瘀体质 [0, 0, 1],//阴虚体质 [1, 1, 0],//气虚兼血瘀体质 [1, 0, 1],//气虚兼阴虚体质 [0, 1, 1],//血瘀兼阴虚体质 [1, 1, 1],//气虚兼血瘀兼阴虚体质 ];中的第n项相等&…...

已解决Error:AttributeError: module ‘numpy‘ has no attribute ‘float‘.

成功解决Error&#xff1a;AttributeError: module ‘numpy‘ has no attribute ‘float‘. &#x1f335;文章目录&#x1f335; &#x1f333;引言&#x1f333;&#x1f333;报错分析&#x1f333;&#x1f333;解决方案1&#xff1a;降低NumPy版本&#x1f333;&#x1f33…...

WordPress块编辑器(Gutenberg古腾堡)中如何添加脚注?

WordPress默认自带的块编辑器​&#xff08;Gutenberg古腾堡编辑器&#xff09;本身就自带添加脚注功能&#xff0c;不过经典编辑器不行。如果想要在WordPress中添加更加专业的脚注&#xff0c;建议使用Modern Footnotes插件&#xff0c;具体介绍及使用请参考『WordPress站点如…...

burpsuite怎么进行本地抓包?ctfer测试自搭建靶场必须学会!

自己搭建靶场测试题目是ctfer不可避免的环节&#xff0c;怎么用burp对本地回环即localhost进行抓包&#xff1f;笔者在本篇分享一下自己的解决经验。 笔者用的是Chrome浏览器&#xff0c;如果是火狐浏览器可以参考本篇&#xff1a;Burp Suite抓不到本地包/localhost包问题解决…...

VSCode Python调试运行:json编写

对于需要在命令行传参运行的项目&#xff0c;如果想要调试运行&#xff0c;则需要编写对应的launch.json文件这里记录一下json文件的编写格式&#xff1a; {"version": "0.2.0","configurations": [{"python": "/data/xxx/minic…...

自动化Web页面性能测试介绍

随着越来越多的用户使用移动设备访问 Web 应用&#xff0c;使得 Web 应用需要支持一些性能并不是很好的移动设备。为了度量和测试 Web 应用是不是在高复杂度的情况下&#xff0c;页面性能能满足用户的需求。 同时&#xff0c;随着 Web 应用的空前发展&#xff0c;前端业务逐渐…...

可视化 | 【d3】力导向关系图优化(搜索+刷新)

文章目录 &#x1f4da;优化内容&#x1f4da;html和css优化&#x1f407;搜索框部分&#x1f407;刷新按钮部分 &#x1f4da;js&#x1f407;搜索框部分&#x1f407;刷新部分 前期回顾&#xff1a;【d3】力导图优化&#xff0c;本文主要是基于上篇代码&#xff0c;以代码段添…...

2024.1.26力扣每日一题——计算 K 置位下标对应元素的和

2024.1.26 题目来源我的题解方法一 位运算统计二进制数中1的个数方法二 官方的一种优化计算二进制中1的个数的方法 题目来源 力扣每日一题&#xff1b;题序&#xff1a;2859 我的题解 方法一 位运算统计二进制数中1的个数 对于每一个位置i都去计算i对应的二进制数中1的个数 …...

R语言【taxlist】——levels():获取或设置分类等级列表

Package taxlist version 0.2.4 Description 分类层次结构可以设置为 taxlist 对象中的级别&#xff0c;按从低到高的顺序排列。 在 taxlist 对象中为特定分类概念添加分类级别。此外&#xff0c;概念限制的变化可能涉及其分类层次结构的变化。 Usage levels(x)## S3 method…...

单元测试——题目十三

目录 题目要求: 定义类 测试类 题目要求: 根据输入的三条边值判断能组成何种三角形。三条边为变量a、b、c,范围为1≤边值≤10,不在范围内,提示“输入边值不在范围内”。不满足任意两边之和必须大于第三边,提示“输入边值不能组成三角形”。输入边值能组成三角形,只有…...

使用Linux SDK客户端向AWS Iot发送数据

参考链接&#xff1a; https://ap-southeast-1.console.aws.amazon.com/iot/home?regionap-southeast-1#/test 此篇文章用于测试&#xff0c;使用Linux SDK客户端向AWS Iot发送数据&#xff0c;准备环境如下&#xff1a; 1、客户端环境准备 1.1 客户端操作系统 虚拟机一台…...

1.27学习总结

今天做了些队列的题&#xff1a; 1.逛画展&#xff08;单调队列&#xff09; 2.打印队列 Printer Queue&#xff08;优先队列&#xff09; 3.[NOIP2010 提高组] 机器翻译(模拟队列) 4.求m区间内的最小值(单调队列板子题) 5.日志统计(滑动窗口&#xff0c;双指针) 总结一下&…...

【算法专题】二分查找(进阶)

&#x1f4d1;前言 本文主要是二分查找&#xff08;进阶&#xff09;的文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是青衿&#x1f947; ☁️博客首页&#xff1a;CSDN主页放风讲故事 &#x1f304;每日…...

开源项目对于新用户和初学者适合哪些工作

目录 一、阅读和理解文档 二、报告问题 三、测试和验证修复 四、编写和更新文档 五、简单的代码更改和修复 六、参与社区讨论 开源项目对于新用户和初学者来说&#xff0c;提供了宝贵的学习和实践机会。以下是一些适合新用户和初学者参与的工作&#xff1a; 一、阅读和理…...

linux中配置文件目录为什么用etc来命名

在早期的 Unix 系统中&#xff0c;/etc 目录的名称确实来源于单词 “etcetera” 的缩写&#xff0c;最初意味着 “其他”&#xff0c;用来存放杂项或者不属于其他特定目录的文件。然而&#xff0c;随着时间的推移&#xff0c;/etc 目录的用途逐渐演变并专门化。 在现代的 Linux…...

06.领域驱动设计:使用DDD分层架构,可以有效降低层与层之间的依赖

目录 1、概述 2、什么是DDD分层架构 1.用户接口层 2.应用层 3.领域层 4.基础层 3、DDD分层架构最重要的原则是什么 4、DDD分层架构如何推动架构演进 1.微服务架构的演进 2.微服务内服务的演进 5、三层架构如何演进到DDD分层架构 我们该怎样转向DDD分层架构 6、总结…...

HCIA-Datacom实验指导手册:3.2 实验二:生成树基础实验

HCIA-Datacom实验指导手册:3.2 实验二:生成树基础实验 一、实验介绍:二、实验拓扑:三、实验目的:四、配置步骤:步骤 1 掌握启用和禁用 STP/RSTP 的方法步骤 2 掌握修改交换机 STP 模式的方法步骤 3 掌握修改桥优先级,控制根桥选举的方法步骤 4 掌握修改端口优先级,控制…...

WPF的ViewBox控件

在WPF中&#xff0c;ViewBox是一个用于缩放和调整其子元素大小的容器控件。它可以根据可用空间自动调整子元素的大小&#xff0c;以使其适应ViewBox的边界。这使得在不同尺寸的窗口或布局中保持元素的比例和缩放变得更加容易。 ViewBox具有以下重要属性&#xff1a; Stretch&…...

论文精读--BERT

不像视觉领域&#xff0c;在Bert出现之前的nlp领域还没有一个深的网络&#xff0c;使得能在大数据集上训练一个深的神经网络&#xff0c;并应用到很多nlp的任务上 Abstract We introduce a new language representation model called BERT, which stands for Bidirectional En…...

LeetCode第468题 - 验证IP地址

题目 编写一个函数来验证输入的字符串是否是有效的 IPv4 或 IPv6 地址。 IPv4 地址由十进制数和点来表示&#xff0c;每个地址包含4个十进制数&#xff0c;其范围为 0 - 255&#xff0c; 用(“.”)分割。比如&#xff0c;172.16.254.1&#xff1b; 同时&#xff0c;IPv4 地址内…...

淘宝API接口调用:案例分析与最佳实践

在电子商务迅猛发展的今天&#xff0c;淘宝作为中国最大的在线购物平台之一&#xff0c;为商家们提供了强大的数据分析和市场洞察工具——淘宝API。有效的API调用不仅可以提升商家的运营效率&#xff0c;还可以帮助商家更好地理解消费者需求、优化商品布局、提高用户满意度等。…...

中仕教育:事业单位考试考什么?

事业单位考试分为两个阶段&#xff0c;分别是笔试和面试&#xff0c;考试科目包括公共科目和专业科目两部分。 公共科目内容是公共基础知识、职业能力测试或申论。一种形式为&#xff1a;公共基础知识职业能力测试或职业能力测试申论。另一种形式为&#xff1a;公共基础申论。…...

python-自动化篇-运维-监控-简单实例-道出如何使⽤Python进⾏系统监控?

如何使⽤Python进⾏系统监控&#xff1f; 使⽤Python进⾏系统监控涉及以下⼀般步骤&#xff1a; 选择监控指标&#xff1a; ⾸先&#xff0c;确定希望监控的系统指标&#xff0c;这可以包括 CPU 利⽤率、内存使⽤情况、磁盘空间、⽹络流量、服务可⽤性等。选择监控⼯具&#x…...

网络安全科普:SSL证书保护我们的网上冲浪安全

当我们在线上愉快冲浪时&#xff0c;各类网站数不胜数&#xff0c;但是如何判定该站点是安全还是有风险呢&#xff1f; 当当当&#xff0c;SSL数字证书登场&#xff01;&#xff01; SSL证书也称为数字证书&#xff0c;是一种用于保护网站和用户之间通信安全的加密协议。由权…...

AOP复习

AOP AOP静态代理动态代理ProxyCGLIB AOP 面向切面编程 优点: 提高代码的可重用性业务代码编码更简洁业务代码维护更高效业务功能扩展更便捷 Joinpoint(连接点)就是方法Pointcut(切入点)就是挖掉共性功能的方法Advice(通知)就是共性功能&#xff0c;最终以一个方法的形式呈现Asp…...

解决 Required Integer parameter ‘uid‘ is not present

1.原因分析 后端没接收到uid可能是前端没传递uid也可能是前端传递了uid&#xff0c;但是传递方式与后端接收方式不匹配&#xff0c;导致没接收到更大的可能是因为后端请求方式错了。比如&#xff1a; 2.解决方案 先确定前端传参方式与后端请求方式是匹配的后端get请求的话…...

Qt/QML编程之路:ListView实现横排图片列表的示例(40)

ListView列表,在QML中使用非常多,排列一个行,一个列或者一个表格,都会用到ListView。 ListView显示从内置QML类型(如ListModel和XmlListModel)创建的模型中的数据,或在C++中定义的从QAbstractItemModel或QAbstract ListModel继承的自定义模型类中的数据。 ListView有一…...