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].

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/652943.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

动态规划算法题刷题笔记

首先看动态规划的三要素&#xff1a;重叠子问题、最优子结构和状态转移方程。 重叠子问题&#xff1a;存在大量的重复计算 最优子结构&#xff1a; 状态转移方程&#xff1a;当前状态转移成以前的状态 动态规划的解题步骤主要有&#xff1a; 确定 dp 数组以及下标的含义状…

苍穹外卖-前端部分(持续更新中)

d 第二种&#xff1a;cmd中输入 vue ui进入图形化界面选择npm,vue2进行创建 先将创建的Vue框架导入Vsocde开发工具 然后ctrshiftp 输入npm 点击serve将项目启动 下这种写法跨域会报错&#xff1a; 解决方法&#xff1a; \ 注意 这种用法&#xff1a;&#xff08;不是单引号…

Android Handler完全解读

一&#xff0c;概述 Handler在Android中比较基础&#xff0c;本文笔者将对此机制做一个完全解读。读者可简单参考上述类图与时序图&#xff0c;便于后续理解。 二&#xff0c;源码解读 1&#xff0c;主线程伊始 众所周知&#xff0c;通过Zygote的fork方式&#xff0c;新创建…

SSH客户端 Termius for Mac 中文激活版

Termius for Mac是一款强大的终端和SSH客户端&#xff0c;为开发人员、系统管理员和网络工程师提供了全面的远程访问和管理工具。 软件下载&#xff1a;Termius for Mac 中文激活版下载 无论您是在使用Mac、Windows还是Linux系统&#xff0c;Termius都能提供出色的功能和用户体…

静态代理IP该如何助力Facebook多账号注册运营?

在Facebook运营中&#xff0c;充分利用静态代理IP是多账号运营的关键一环。通过合理运用静态代理IP&#xff0c;不仅可以提高账号安全性&#xff0c;还能有效应对Facebook的算法和限制。以下是这些关键点&#xff0c;可以帮助你了解如何运用静态代理IP进行Facebook多账号运营&a…

基于springboo校园社团信息管理系统

摘要 随着高校规模的扩大和学生社团活动的日益丰富多彩&#xff0c;校园社团信息管理成为一个备受关注的问题。为了更有效地组织、管理和推动校园社团的发展&#xff0c;本文设计并实现了一套基于Spring Boot的校园社团信息管理系统。本系统以实现社团信息的集中管理和高效运营…

使用dockers-compose搭建开源监控和可视化工具

简介 Prometheus 和 Grafana 是两个常用的开源监控和可视化工具。 Prometheus 是一个用于存储和查询时间序列数据的系统。它提供了用于监控和报警的数据收集、存储、查询和图形化展示能力。Prometheus 使用拉模型&#xff08;pull model&#xff09;&#xff0c;通过 HTTP 协议…

工具学习——使用OpenSmile提取音频特征

文章目录 OpenSmile介绍下载和安装提取特征格式转换特征提取尝试一正常使用手段常见的特征 使用Gnuplot可视化特征安装使用 总结 OpenSmile介绍 openSMILE&#xff08;open-source Speech and Music Interpretation by Large-space Extraction&#xff09;是一个开源工具包&am…

直流电机驱动(马达)

文章目录 一、介绍直流电机介绍电机驱动电路大功率器件直接驱动H桥驱动集成电路线路图 PWM介绍产生PWM的方法 二、实例1.呼吸灯案例2.直流电机调速 一、介绍直流电机 介绍 电机驱动电路 点击的负载较大&#xff0c;直接接在单片机I/O口上无法驱动&#xff0c;所以需要驱动电路…

Vite学习指南

那本课程都适合哪些人群呢&#xff1f; 想要学习前端工程化&#xff0c;在新项目中投入使用 Vite 构建工具的朋友 Webpack 转战到 Vite 的小伙伴 前端架构师们&#xff0c;可以充实自己的工具箱 当然如果你没有项目相关开发经验&#xff0c;也可以从本课程中受益&#xff0…

支付宝开通GPT4.0,最新经验分享

ChatGPT是由OpenAI开发的一种生成式对话模型&#xff0c;具有生成对话响应的能力。它是以GPT&#xff08;Generative Pre-trained Transformer&#xff09;为基础进行训练的&#xff0c;GPT是一种基于Transformer架构的预训练语言模型&#xff0c;被广泛用于各种自然语言处理任…

vue 样式隔离原理

日常写单文件组件时&#xff0c;会在style添加scoped属性&#xff0c;如<style scoped>&#xff0c;目的是为了隔离组件与组件之间的样式&#xff0c;如下面的例子&#xff1a; <template><p class"foo">这是foo</p><p class"bar&q…

C#从网址上读取json数据

需求&#xff1a;从客户给的网址中读取json格式的数据。 找了好多资料&#xff0c;都不太好使&#xff0c;看到了一篇很有帮助的文章。以下大部分内容和这篇找到的文章近似。太不容易了&#xff0c;同时也感谢这篇文章的作者心所欲。 https://www.cnblogs.com/zoujinhua/p/10…

数字图像处理(实践篇)三十四 OpenCV-Python绘制椭圆

目录 一 涉及的函数 二 实践 一 涉及的函数 cv2.ellipse(img,center,axes,angle,start_angle,end_angle,color,thickness) 参数: ①<

Future模式先给您提货单

Future模式是一种设计模式&#xff0c;用于在处理耗时操作时提高程序的响应性。 角色介绍: Main类: 负责向Host发出请求并获取数据的类。 Host类: 负责向请求返回FutureData的实例的类&#xff0c;起到调度的作用。 Data接口: 表示访问数据的方法的接口&#xff0c;由FutureD…

openGauss学习笔记-209 openGauss 数据库运维-常见故障定位案例-共享内存泄露问题

文章目录 openGauss学习笔记-209 openGauss 数据库运维-常见故障定位案例-共享内存泄露问题209.1 共享内存泄露问题209.1.1 问题现象209.1.2 原因分析209.1.3 处理方法 openGauss学习笔记-209 openGauss 数据库运维-常见故障定位案例-共享内存泄露问题 209.1 共享内存泄露问题…

算法沉淀——滑动窗口(leetcode真题剖析)

算法沉淀——滑动窗口 01.长度最小的子数组02.无重复字符的最长子串03.最大连续1的个数 III04.将 x 减到 0 的最小操作数05.水果成篮06.找到字符串中所有字母异位词07.串联所有单词的子串08.最小覆盖子串 滑动窗口算法是一种用于解决数组或列表中子数组或子序列问题的有效技巧。…

重装Windows系统出现Windows无法安装到这个磁盘,选中的磁盘采用GPT分区

文章目录 1.问题描述2.问题解决 1.问题描述 重装Windows系统时&#xff0c;出现Windows无法安装到这个磁盘&#xff0c;选中的磁盘采用GPT分区这个提示 2.问题解决 1.shiftF10&#xff0c;打开命令行 2.输入&#xff1a;diskpart (打开分区工具) 3.输入&#xff1a;list di…

elementplus Dialog 对话框设置距离页面顶部的距离

默认为 15vh&#xff0c;当弹窗过于高的时候&#xff0c;这个距离其实是不合适的 <el-dialogv-model"dialogVisible"title"Tips"width"30%":before-close"handleClose"top"6vh"><span>This is a message</s…

IDEA搭建JDK源码学习环境(可添加注释、修改、debug)

工程详见&#xff1a;https://github.com/wenpanwenpan/study-source-jdk1.8.0_281 1、找到src.zip和javafx-src.zip 找到你想要调试的JDK&#xff0c;笔者本地电脑上装了两个版本的JDK&#xff0c;这里以jdk1.8.0_281为例将JDK目录下的javafx-src.zip和src.zip两个压缩包进行…