cesium入门笔记
- 一、下载源码,源码介绍
- 二、html案例体验
- 三、cesium中的类介绍
- 1.它们分别是:
- 2.四大类的完整演示代码:
 
- 四、cesium的坐标与转换
- 五、相机系统介绍
- 六、地图、地形的加载
- 七、建筑体添加和使用
- 八、空间数据加载
- 1、加载数据
- 2、对加载的空间数据进行管理
- 3、空间数据加载的整体代码如下:
 
- 九、鼠标交互,数据查询
- 1、鼠标左键点击图片后提示弹框
- 2、自定义弹框
 
- 十、三维数据3dtiles
- 十一、时间系统、粒子系统
- 1、时间系统
- 2、粒子系统
 
- 十二、动态数据格式CZML
学习视频参考: 1、Cesium.JS从入门到精通
一、下载源码,源码介绍
官网下载:cesium.js官方网站源码包下载
 如果下载较慢,可使用已经下好的:cesium1.89官网源码
下面所有案例的每一课的代码:cesium学习笔记代码
二、html案例体验
1、新建一个工程,下面包含libs和src两个目录,libs下面放cesium的源码build的整个cesium文件夹,如下图

 2、新建html,编写以下内容,用Live server 打开即可看到效果
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=s, initial-scale=1.0">
  <title>cesium第一课</title>
  //cesium.js引入
  <script src="../libs/Cesium/Cesium.js"></script>
  //cesium样式引入
  <link href="../libs/Cesium/Widgets/widgets.css" rel="stylesheet">
  //导入cesium的类型声明,有这个才会有快捷智能提示
  <script src="../libs/Cesium/Cesium.d.ts"></script>
  <style>
    html,
    body {
      margin: 0px;
      padding: 0px;
    }
  </style>
</head>
<body>
  <div id="puiedu-cesiumContainer"></div>
  <script>
    Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI5MWVkMjllNy03ZjY4LTQ3YmQtOTgxOC05NGQ5YTU0ZjM5ZGEiLCJpZCI6MzU5Nywic2NvcGVzIjpbImFzciIsImdjIl0sImlhdCI6MTUzODE5MTUyM30.dtS2F3-q2fGoA93N7cFl-LCikK-Rjk7v01WWA-RqCxg'
    const viewer = new Cesium.Viewer('puiedu-cesiumContainer');
  </script>
</body>
</html>
3、运行后如下图:
 
三、cesium中的类介绍
1.它们分别是:
1、Viewer查看器类
 (1)、它是cesium展示三维要素内容的主要窗口,它不仅仅是包含三维地球的视窗,还包含了一些基础控件,在定义Viewer对象的同时需要设定基础部件、图层等的初始化状态
 (2)、Viewer创建代码:new Cesium.Viewer(cesiumContainer,options); 。
 参数说明:第一个参数cesiumContainer我们用于指定地图主窗口diy的id,第二个参数options是Viewer的可选设置参数,我们可以对基础地理环境进行设置。
Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI5MWVkMjllNy03ZjY4LTQ3YmQtOTgxOC05NGQ5YTU0ZjM5ZGEiLCJpZCI6MzU5Nywic2NvcGVzIjpbImFzciIsImdjIl0sImlhdCI6MTUzODE5MTUyM30.dtS2F3-q2fGoA93N7cFl-LCikK-Rjk7v01WWA-RqCxg';
const viewer = new Cesium.Viewer('puiedu-cesiumContainer', {
   animation: false,//动画小组件
   timeline: false,//左下角仪表
 });
 viewer.scene.globe.show = true//地图显示,默认是true
2、Scene场景类
 (1)、它是Cesium中Scene是非常重要的类,是所有3D图形对象的容器,是在viewer内部隐式创建的,也可以对基础地理环境进行设置,包括地图、地形等。
 (2)、需要注意的是在viewer中设置图层等价于在scene中设置图层,代码验证:console.log(viewer.imgerLaters == viewer.scene.imgerLaters);//输出true
 (3)、还可以对场景数据进行设置,cesium底层空间数据绘制方法是依赖Primitive API,可以根据图形学原理绘制灵活的高级图形
 (4)、还可以对场景进行交互,比如鼠标事件对场景的控制、相机事件,可以修改场景环境,比如修改地图显示隐藏、光照强度、图层样式、地形数据、在图层上绘制点、线、面、体
viewer.scene.camera.setView({//通过scene控制相机对视口进行切换
  destination: Cesium.Cartesian3.fromDegrees(116.39, 39.9, 1000)//设置经纬度和高度
})
3、Entity实体类
 (1)、Entity是由Primitive封装而来的,Entity不是属于Scene,它封装程度高、构造简单、使用便捷使得开发者专注于数据的呈现,不必关心底层的可视化机制,还提供了用于构建复杂的、时间动态可视化的结构,与静态数据自然的结合在一起;EntityAPI 能够提供灵活的、高性能的可视化,同时提供一致性的、易于学习、易于使用的接口。
 (2)、代码示例了解Entity
const entity = viewer.entities.add({//创建一个Entity点对象
position: Cesium.Cartesian3.fromDegrees(116.39, 39.9, 400),//设置经纬度和高度
point: {
  pixelSize: 100,//设置点大小
  color: new Cesium.Color(0, 1, 0, 1)//设定点颜色      
}
})
viewer.trackedEntity = entity;//将摄像头设置在圆点处(track跟踪)
4、DataSourceCollection数据源集合类
 (1)、它是cesium中加载矢量数据的最主要方式之一,最大的特点是支持矢量数据集和外部文件的调用,主要有三种调用方法,分别为CzmlDataSource加载Czml、KmlDataSource加载Kml、GeoJsonDataSource加载GeoJson格式数据,在gis开发中加载矢量数据是必不可少的功能。将矢量数据转化为以上任何一种方式,便可以在cesium中实现矢量数据的加载和存取。
 (2)、示例演示:geojson数据获取:geojson数据获取
//DataSource用于将任意数据转换为EntityCollection,这里调用的是geojson数据
viewer.dataSources.add(
  Cesium.GeoJsonDataSource.load(
    "./data/hubei.json"
  )
)
2.四大类的完整演示代码:
<!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>cesium第一课</title>
  <!-- cesium.js引入 -->
  <script src="../libs/Cesium/Cesium.js"></script>
  <!-- cesium样式引入 -->
  <link href="../libs/Cesium/Widgets/widgets.css" rel="stylesheet">
  <!-- 导入cesium的类型声明,有这个才会有快捷智能提示(已屏蔽,无效) -->
  <!-- <script src="../libs/Cesium/Cesium.d.ts"></script> -->
  <!-- <reference path="../libs/Cesium/Cesium.d.ts" /> -->
  <style>
    html,
    body {
      margin: 0px;
      padding: 0px;
    }
  </style>
</head>
<body>
  <div id="puiedu-cesiumContainer"></div>
  <script>
    Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI5MWVkMjllNy03ZjY4LTQ3YmQtOTgxOC05NGQ5YTU0ZjM5ZGEiLCJpZCI6MzU5Nywic2NvcGVzIjpbImFzciIsImdjIl0sImlhdCI6MTUzODE5MTUyM30.dtS2F3-q2fGoA93N7cFl-LCikK-Rjk7v01WWA-RqCxg';
    const viewer = new Cesium.Viewer('puiedu-cesiumContainer', {
      animation: false,//动画小组件
      timeline: false,//左下角仪表
    });
    viewer.scene.globe.show = true//地图显示,默认是true
    console.log(viewer.imgerLaters == viewer.scene.imgerLaters);//输出true
    viewer.scene.camera.setView({//通过scene控制相机对视口进行切换
      destination: Cesium.Cartesian3.fromDegrees(113.37377, 31.717497, 1000000)//设置经纬度和高度
    })
    const entity = viewer.entities.add({//创建一个Entity点对象
      position: Cesium.Cartesian3.fromDegrees(113.37377, 31.717497, 1000000),//设置经纬度和高度
      point: {
        pixelSize: 100,//设置点大小
        color: new Cesium.Color(0, 1, 0, 1)//设定点颜色      
      }
    })
    viewer.trackedEntity = entity;//将摄像头设置在圆点处(track跟踪)
    //DataSource用于将任意数据转换为EntityCollection,这里调用的是geojson数据
    viewer.dataSources.add(
      Cesium.GeoJsonDataSource.load(
        "./data/hubei.json"
      )
    )
  </script>
</body>
</html>
代码运行效果如下:
 
四、cesium的坐标与转换
1、cesium具用真实地理坐标的三维球体,用户通过二维屏幕与cesium进行操作,我们要把三维模型绘制到三维球体上,就需要在地理坐标和屏幕坐标之间做转换,下面介绍下cesium的主要坐标系:
 (1)、WGS84经纬度坐标系 (没有实际的对象)。
 (2)、WGS84弧度坐标系 (Cartographic)
 (3)、笛卡尔空间直角坐标系 (Cartesian3)
 (4)、平面坐标系,也叫屏幕坐标系 (Cartesian2)
 (5)、4D笛卡尔坐标系 (Cartesian4)
2、坐标系详解:
 (1)、首先前两个都是WGS84坐标系,WGS84:World Geodetic System 1984,是为GPS全球定位系统使用而建立的坐标系统。坐标原点为地球质心
 
 在cesium中没有实际的对象来描述WGS84经纬度坐标系的,都是以弧度的方式进行运用的,也就是当前的这个对象类new Cesium.Cartographic(longitude, latitude, height),这个类有三个构造参数,经度、纬度、高度,这个函数内部的弧度计算采用:弧度=Π/180*经纬度
 (2)、笛卡尔空间直角坐标系,以空间中O点为原点,建立三条两两垂直的数轴X、Y、Z
 
 笛卡尔直角坐标系的原点就是椭球的中心,我们通过new Cesium.Cartesian3(x,y,z)来构建Cartesian3的类对象,三个参数xyz分别代表三根数轴上的值
 (3)、平面坐标系,也叫屏幕坐标系。它是一个二维的笛卡尔坐标系。屏幕左上角为原点水平方向为x,垂直方向为y,向下为正。
 
 构造对象new Cesium.Cartesian2(x,y)
3、坐标转换
 (1)、经纬度和WGS84弧度的相互转换:弧度= Π/180*经纬度角度、经纬度角度=180/Π*弧度。在cesium中可以用两种方式实现转换:
- 构造函数法生成WGS84弧度坐标对象new Cesium.Cartographic(longitude弧度,latitude弧度,height米),
- 静态函数法构建WGS84弧度坐标对象var cartographic= Cesium.Cartographic.fromDegrees(longitude经度,latitude纬度,height米)、var cartographic= Cesium.Cartographic.fromRadians(longitude弧度, latitude弧度,height米)
(2)、笛卡尔空间直角坐标系转换为WGS84坐标系:在cesium中可以使用var cartographic= Cesium.Cartographic.fromCartesian(cartesian3)、var cartographic= Cesium.Ellipsoid.WGS84.cartesianToCartographic(cartesian3)、或者批量传入数组转 var cartographics=Cesium.Elipsoid.WGS84.cartesianArrayToCartographicArray([cartesian1,cartesian2,cartesian3])
 (3)、平面坐标系转笛卡尔空间直角坐标系、屏幕坐标转WGS84坐标,这里的场景坐标是包含了地形、倾斜、模型的坐标var cartesian3= viewer.scene.pickPosition(Cartesian2)
 (4)、屏幕坐标转地表坐标var cartesian3=viewer.scene.globe.pick(viewer.camera.getPickRay(Cartesian2),viewer.scene);这里是地球表面的WGS84坐标,包含地形,不包括模型、倾斜摄影表面
 (5)、平面坐标转椭球面坐标var cartesian3=viewer.scene.camera.pickEllipsoid(Cartesian2),这里的椭球面坐标是参考椭球的WGS84坐标,不包含地形、模型、倾斜摄影表面
 (6)、笛卡尔空间直角坐标系转平面坐标系var cartesian2=Cesium.SceneTransforms.wgs84ToWindowCoordinates(viewer.scene,cartesian3),这个静态函数需要传入场景与笛卡尔空间坐标2个参数,执行成功后返回平面坐标的数值
五、相机系统介绍
官方文档api参考:Cesium.Camera
 在二维地图中,如果我们要查看某个地方,只需要定位经纬度即可,但是三维地图不仅仅需要经纬度确定视点位置,还需要视线方向,例如观察某物体找到了物体位置,但是视线方向反了,那么在视域中是看不到物体的,所以相机的存在就是为了控制场景中的视域。
 1、相机系统方法介绍
 (1)、setView():setView通过定义相机飞行目的地的三维坐标和视线方向,将视角直接切换到所设定的视域范围内,设置一个常量,用于存储飞行的目的地的坐标
 (2)、flyTo():视角跳转,过渡跳转,有过程
 (3)、lookAt():lookAt将视角设置到跳转的设置的目的地上,但是用鼠标任意旋转视角方向,是不会改变其位置的,一般用于锁定某个场景的视角
 (4)、viewBoundingSphere() 视角切换效果和setView一样,没有飞行过渡,直接切换,但是它可以给一个指定的目标点,从多个角度更好的观测物体样式和状态,也就是说相机围绕目标点旋转而不是地球,比如加载glb
六、地图、地形的加载
代码有详细注释
<!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>cesium第二课,加载自定义地图</title>
  <!-- cesium.js引入 -->
  <script src="../libs/Cesium/Cesium.js"></script>
  <!-- cesium样式引入 -->
  <link href="../libs/Cesium/Widgets/widgets.css" rel="stylesheet">
  <!-- 导入cesium的类型声明,有这个才会有快捷智能提示(已屏蔽,无效) -->
  <!-- <script src="../libs/Cesium/Cesium.d.ts"></script> -->
  <!-- <reference path="../libs/Cesium/Cesium.d.ts" /> -->
  <style>
    html,
    body {
      margin: 0px;
      padding: 0px;
    }
  </style>
</head>
<body>
  <div id="puiedu-cesiumContainer"></div>
  <script>
    Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI5MWVkMjllNy03ZjY4LTQ3YmQtOTgxOC05NGQ5YTU0ZjM5ZGEiLCJpZCI6MzU5Nywic2NvcGVzIjpbImFzciIsImdjIl0sImlhdCI6MTUzODE5MTUyM30.dtS2F3-q2fGoA93N7cFl-LCikK-Rjk7v01WWA-RqCxg';
    let esri = new Cesium.ArcGisMapServerImageryProvider({
      url: "https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer"
    })//用一个变量存储新地图的信息,这里我们使用的是arcgis地图服务
    const viewer = new Cesium.Viewer('puiedu-cesiumContainer', {
      animation: false,//动画小组件
      timeline: false,//左下角仪表,
      baseLayerPicker: false,//默认的地图按钮设置为隐藏
      imageryProvider: esri,//viewer内的imageryProvider属性用于设置地图,这里加载arcgis的地图
      terrainProvider: new Cesium.CesiumTerrainProvider({//此时地球表面是没有比如山脉3d地形的,所以下面加载地形数据放入引入的地形;CesiumTerrainProvider方法是将地形数据,转换为Cesium可以访问的格式
        url:Cesium.IonResource.fromAssetId(1),//url 属性用于放入地形服务器的地址
        requestVertexNormals:true,//requestVertexNormals属性设置为true,可以增加法线,用于提高光照效果
        requestWaterMask:true,//可以增加水面特效
      }),
    });
    viewer.scene.globe.show = true//地图显示,默认是true
    
    // var layer=viewer.imageryLayers.addImageryProvider(
    //   new Cesium.IonImageryProvider({assetId:3812})
    // )//测试夜晚地图
  </script>
</body>
</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>cesium第二课,加载自定义地图</title>
  <!-- cesium.js引入 -->
  <script src="../libs/Cesium/Cesium.js"></script>
  <!-- cesium样式引入 -->
  <link href="../libs/Cesium/Widgets/widgets.css" rel="stylesheet">
  <!-- 导入cesium的类型声明,有这个才会有快捷智能提示(已屏蔽,无效) -->
  <!-- <script src="../libs/Cesium/Cesium.d.ts"></script> -->
  <!-- <reference path="../libs/Cesium/Cesium.d.ts" /> -->
  <style>
    html,
    body {
      margin: 0px;
      padding: 0px;
    }
  </style>
</head>
<body>
  <div id="puiedu-cesiumContainer"></div>
  <script>
    Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI5MWVkMjllNy03ZjY4LTQ3YmQtOTgxOC05NGQ5YTU0ZjM5ZGEiLCJpZCI6MzU5Nywic2NvcGVzIjpbImFzciIsImdjIl0sImlhdCI6MTUzODE5MTUyM30.dtS2F3-q2fGoA93N7cFl-LCikK-Rjk7v01WWA-RqCxg';
    //----------------------- 地图、地形的添加--------------------------
    let esri = new Cesium.ArcGisMapServerImageryProvider({
      url: "https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer"
    })//用一个变量存储新地图的信息,这里我们使用的是arcgis地图服务
    const viewer = new Cesium.Viewer('puiedu-cesiumContainer', {
      animation: false,//动画小组件
      timeline: false,//左下角仪表,
      baseLayerPicker: false,//默认的地图按钮设置为隐藏
      imageryProvider: esri,//viewer内的imageryProvider属性用于设置地图
      terrainProvider: new Cesium.CesiumTerrainProvider({//此时地球表面是没有比如山脉3d地形的,所以下面加载地形数据放入引入的地形;CesiumTerrainProvider方法是将地形数据,转换为Cesium可以访问的格式
        url:Cesium.IonResource.fromAssetId(1),//url 属性用于放入地形服务器的地址
        requestVertexNormals:true,//requestVertexNormals属性设置为true,可以增加法线,用于提高光照效果
        requestWaterMask:true,//可以增加水面特效
      }),
    });
    viewer.scene.globe.show = true//地图显示,默认是true
    
    // var layer=viewer.imageryLayers.addImageryProvider(
    //   new Cesium.IonImageryProvider({assetId:3812})
    // )//测试夜晚地图
//----------------------- 地图、地形的添加结束--------------------------
//----------------------- 建筑物的添加使用--------------------------
    let tileset=viewer.scene.primitives.add(//Viewer中的scene是Cesium虚拟场景中所有3D图形对象和状态的容器,它的primitives属性用于获取大量的基元集合,add方法用于加载数据
      new Cesium.Cesium3DTileset({//这里使用的CesiumBDTileset方法,是Cesium用于传输海量异构3D地理空间数据集
        url:Cesium.IonResource.fromAssetId(96188)//添加建筑物
      })
    )
    viewer.camera.setView({//添加相机信息
      destination:Cesium.Cartesian3.fromDegrees(121.49,31.23,3000),
      orientation:{
        heading:0,
        pitch:-90,
        roll:0
      }
    })
    //模型加样式,这里先添加一个单一样式
    tileset.style= new Cesium.Cesium3DTileStyle({//需要使用Cesium的Cesium3DTileStyle方法
      color:"color('pink',0.5)",//color属性用于设定模型的颜色和透明度,可以设置颜色根据楼层高度进行变化
      show:true
    })//因为3d模型的样式过于单调,这里我们对一个模型数据样式进行修改,就是修改它的style
    // //模型加样式,根据高度添加不同样式
    // tileset.style = new Cesium.Cesium3DTileStyle({//需要使用Cesium的Cesium3DTileStyle方法
    //   color: {//给不同的高度的建筑物体设置不同的颜色
    //     conditions:[
    //       ["${Height} >= 300", "rgba(45,0,75,0.5)"],
    //       ["${Height} >= 200", "rgb(102,0,75)"],
    //       ["${Height} >= 100", "rgb(170,0,75)"],
    //       ["${Height} >= 50", "rgb(224,0,75)"],
    //       ["${Height} >= 20", "rgb(1,0,75)"],
    //       ["${Height} >= 10", "rgb(100,0,75)"],
    //       ["${Height} >= 5", "rgb(200,0,75)"],
    //       ["true", "rgb(127,59,8)"]
    //     ]
    //   },//color属性用于设定模型的颜色和透明度,可以设置颜色根据楼层高度进行变化
    //   show: '${Height} >= 0'//show属性设置的是高度大于等于0的建筑物才可以显示出来
    // })//因为3d模型的样式过于单调,这里我们对一个模型数据样式进行修改,就是修改它的style
//----------------------- 建筑物的添加使用结束--------------------------
  </script>
</body>
</html>
执行效果如下:
 
 
八、空间数据加载
1、加载数据
在cesium中一般使用到的空间数据分为矢量数据和栅格数据,前几课我们学习的地形和地图数据的加载,就属于栅格数据。矢量数据则包括几何体的加载,模型、标签等
(1)、加载点线面示例代码
   //地球加载一个圆点
    const entity_point = viewer.entities.add({//创建一个Entity点对象
      position:new Cesium.Cartesian3.fromDegrees(113.37377, 31.717497, 1000),//设置经纬度和高度
      point: {
        pixelSize: 50,//设置点大小
        color: new Cesium.Color(0, 1, 0, 1)//设定点颜色      
      }
    })
    //地球加载一条线
    const entity_line = viewer.entities.add({//创建一个Entity点对象
      polyline: {
        show:true,
        positions:new Cesium.Cartesian3.fromDegreesArray([113.37377, 31.717497, 113.37577, 31.717597]),//线经纬度
        width:5,//线宽
        material:new Cesium.Color(0,0,1,1),//设置颜色
      }
    })
    //地球加载一个面
    const entity_plane = viewer.entities.add({//创建一个Entity点对象
      position: Cesium.Cartesian3.fromDegrees(113.37377, 31.717497, 1000),//设置经纬度和高度
      plane: {//用于绘制一个面
        plane:new Cesium.Plane(Cesium.Cartesian3.UNIT_Z,0),//确认面的朝向,这里我们设置它朝Z轴平铺
        dimensions:new Cesium.Cartesian2(400,300),//设置面的长度和宽度
        color: new Cesium.Color(0, 1, 0, 1),//设定点颜色  
        material: Cesium.Color.RED.withAlpha(0.5),//颜色为红色,透明度0.5
        outline:true,//是否显示边框
        outlineColor:Cesium.Color.BLACK//边框线为黑色
      }
    })
效果展示:
 
 (2)、加载模型,代码如下:
 const position = Cesium.Cartesian3.fromDegrees(113.37377, 31.717497, 10000) //定义常量,用于存储飞行目的地的坐标
    const orientation= Cesium.Transforms.headingPitchRollQuaternion(position,new Cesium.HeadingPitchRoll(-90,0,0))//定义模型朝向变量:参数一:位置信息,参数二:旋转角度
    const entity=viewer.entities.add({//使用Entities加载一个glb模型用于观察
      position:position,//模型位置
      orientation:orientation,//模型朝向
      model:{//模型信息
        uri:"./data/car.glb",//模型路径
        minimumPixelSize:100,//模型最小的大小
        maxmumScale:10000,//模型缩放最大比例
        show:true,//模型的显示
      }
    })
执行效果:
 
 (3)、加载文字说明(标签的加载),代码如下:
//地球加载一个文本标签 
const entity_txt = viewer.entities.add({//使用Entities加载一个glb模型用于观察
  position: position,//文字位置
  label:{
    text:"我是一段文字",//设置文字内容
    font:"50px Helvetica",//字体
    fillColor:Cesium.Color.YELLOW//字体颜色
  }
})
效果如下:
 
 (4)、总结:要建立起一个概念,在Cesium中无论载入几何体还是文字都是基于空间位置的。
2、对加载的空间数据进行管理
空间数据管理是三维场景开发的主要内容,其包含对数据的创建、增加、修改、删除等。这里主要学习cesium api的Entity方法,它让开发者专注于数据的呈现,而不必担心底层的可视化机制。
 (1)、用Entity方法创建一个多边形,代码如下:
//地球加载一个多边形
const entity_polygon = viewer.entities.add({//创建一个Entity对象
  polygon: {//用于绘制一个多边形,一个多边形由多个点连接组成的
    hierarchy: Cesium.Cartesian3.fromDegreesArray([113.3777, 31.717497, 113.9007, 31.717797, 113.3007, 31.617797]),//fromDegreesArray方法就是让我们录入多个点的位置信息,Cesium则在底层将各个点连接起来,组成一个多边形,这里通过录入三个经纬度坐标位置,绘制一个三角形
    material:Cesium.Color.PINK,//设置颜色
  }
})
效果如下:
 
 (2)、加载一个图片,这里把图片的朝向指向x轴,可以立起来,代码如下:
  //地球加载一个图片
  const entity_image = viewer.entities.add({//创建一个Entity点对象
    position: Cesium.Cartesian3.fromDegrees(113.37377, 31.717497, 100),//设置经纬度和高度
    plane: {//用于绘制一个面
      plane: new Cesium.Plane(Cesium.Cartesian3.UNIT_X, 0),//确认面的朝向,这里我们设置它朝X轴平铺
      dimensions: new Cesium.Cartesian2(200, 150),//设置面的长度和宽度
      material: "./data/a.png",//引入图片
      outline: true,//是否显示边框
      outlineColor: Cesium.Color.GREEN//边框线为黑色
    }
  })
效果如下:
 
 (3)、将绘制好的多边形在垂直方向拉伸,代码如下:
//地球加载一个多边形并拉伸
const entity_polygon_stretch = viewer.entities.add({//创建一个Entity对象
  polygon: {//用于绘制一个多边形,一个多边形由多个点连接组成的
    hierarchy: Cesium.Cartesian3.fromDegreesArray([113.3777, 31.7174, 113.9007, 31.7177, 113.3007, 31.6177]),//fromDegreesArray方法就是让我们录入多个点的位置信息,Cesium则在底层将各个点连接起来,组成一个多边形,这里通过录入三个经纬度坐标位置,绘制一个三角形
    material: Cesium.Color.YELLOW,//设置颜色
    extrudedHeight: 200,//将绘制好的多边形在垂直方向进行拉升,此属性在绘制多边形的时候可以使用,如果绘制的本身是平面则不可以使用
  }
})
效果如下:
 
 (4)、除了修改样式以外,还常需对它们进行增、删、改 ,比如 :五秒后将上面的多面体颜色设置为白色,十秒后删除拉伸模型,代码如下:
/** 除了修改样式以外,还常需对它们进行增、删、改 **/
//五秒后颜色设置为白色
setTimeout(() => {
 viewer.entities.getById("polygon_stretch_id").polygon.material = Cesium.Color.WHITE
}, 5000);
setTimeout(() => {//十秒后删除拉伸模型
  viewer.entities.remove(entity_polygon_stretch)
}, 10000);
效果如下:
 
 移除场景内的所有实体,使用removeAll()方法,代码如下:viewer.entities.removeAll(),效果如下:
 
3、空间数据加载的整体代码如下:
<!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>cesium第三课,空间实体</title>
  <!-- cesium.js引入 -->
  <script src="../libs/Cesium/Cesium.js"></script>
  <!-- cesium样式引入 -->
  <link href="../libs/Cesium/Widgets/widgets.css" rel="stylesheet">
  <!-- 导入cesium的类型声明,有这个才会有快捷智能提示(已屏蔽,无效) -->
  <!-- <script src="../libs/Cesium/Cesium.d.ts"></script> -->
  <!-- <reference path="../libs/Cesium/Cesium.d.ts" /> -->
  <style>
    html,
    body {
      margin: 0px;
      padding: 0px;
    }
  </style>
</head>
<body>
  <div id="puiedu-cesiumContainer"></div>
  <script>
    Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI5MWVkMjllNy03ZjY4LTQ3YmQtOTgxOC05NGQ5YTU0ZjM5ZGEiLCJpZCI6MzU5Nywic2NvcGVzIjpbImFzciIsImdjIl0sImlhdCI6MTUzODE5MTUyM30.dtS2F3-q2fGoA93N7cFl-LCikK-Rjk7v01WWA-RqCxg';
    const viewer = new Cesium.Viewer('puiedu-cesiumContainer', {
      animation: false,//动画小组件
      timeline: false,//左下角仪表
    });
    //----------------------------空间数据加载,---------------------------
    const position=Cesium.Cartesian3.fromDegrees(113.37377, 31.717497, 1000) //定义常量,用于存储飞行目的地的坐标
    //setView 直接跳转,没有过程
    viewer.camera.setView({//通过相机系统设置视角
      destination:position,//设置相机目的地
      orientation:{//设置相机视口的方向
        heading:Cesium.Math.toRadians(0),//控制视口的水平旋转,也就是沿着y轴旋转,当数值为0时,代表正北方向
        pitch:Cesium.Math.toRadians(-90),//控制视口的上下旋转,即沿x轴进行旋转,当数值为-90,代表俯视地面
        roll:0,//控制视口的反转角度,即沿着z轴进行旋转,数值为0表示不翻转
      },
    })
    //地球加载一个圆点
    const entity_point = viewer.entities.add({//创建一个Entity点对象
      position:new Cesium.Cartesian3.fromDegrees(113.37377, 31.717497, 1000),//设置经纬度和高度
      point: {
        pixelSize: 50,//设置点大小
        color: new Cesium.Color(0, 1, 0, 1)//设定点颜色      
      }
    })
    //地球加载一条线
    const entity_line = viewer.entities.add({//创建一个Entity点对象
      polyline: {
        show:true,
        positions:new Cesium.Cartesian3.fromDegreesArray([113.37377, 31.717497, 113.37577, 31.717597]),//线经纬度
        width:5,//线宽
        material:new Cesium.Color(0,0,1,1),//设置颜色
      }
    })
    //地球加载一个面
    const entity_plane = viewer.entities.add({//创建一个Entity点对象
      position: Cesium.Cartesian3.fromDegrees(113.37377, 31.717497, 1000),//设置经纬度和高度
      plane: {//用于绘制一个面
        plane:new Cesium.Plane(Cesium.Cartesian3.UNIT_Z,0),//确认面的朝向,这里我们设置它朝Z轴平铺
        dimensions:new Cesium.Cartesian2(400,300),//设置面的长度和宽度
        color: new Cesium.Color(0, 1, 0, 1),//设定点颜色  
        material: Cesium.Color.RED.withAlpha(0.5),//颜色为红色,透明度0.5
        outline:true,//是否显示边框
        outlineColor:Cesium.Color.BLACK//边框线为黑色
      }
    })
    //地球加载一个多边形
    const entity_polygon = viewer.entities.add({//创建一个Entity对象
      polygon: {//用于绘制一个多边形,一个多边形由多个点连接组成的
        hierarchy: Cesium.Cartesian3.fromDegreesArray([113.3777, 31.717497, 113.9007, 31.717797, 113.3007, 31.617797]),//fromDegreesArray方法就是让我们录入多个点的位置信息,Cesium则在底层将各个点连接起来,组成一个多边形,这里通过录入三个经纬度坐标位置,绘制一个三角形
        material:Cesium.Color.PINK,//设置颜色
        //通常除了简单的图形、颜色加载以外,更多时候需要定制化的样式,通过代码看下他的可选配置项
      }
    })
    /** 通常除了简单的图形、颜色加载以外,更多时候需要定制化的样式,通过代码看下他的可选配置项 **/
    //地球加载一个图片
    const entity_image = viewer.entities.add({//创建一个Entity点对象
      position: Cesium.Cartesian3.fromDegrees(113.37377, 31.717497, 100),//设置经纬度和高度
      plane: {//用于绘制一个面
        plane: new Cesium.Plane(Cesium.Cartesian3.UNIT_X, 0),//确认面的朝向,这里我们设置它朝X轴平铺
        dimensions: new Cesium.Cartesian2(200, 150),//设置面的长度和宽度
        material: "./data/a.png",//引入图片
        outline: true,//是否显示边框
        outlineColor: Cesium.Color.GREEN//边框线为黑色
      }
    })
    //地球加载一个多边形并拉伸
    const entity_polygon_stretch = viewer.entities.add({//创建一个Entity对象
      id:"polygon_stretch_id",//给几何体加一个id号
      polygon: {//用于绘制一个多边形,一个多边形由多个点连接组成的
        hierarchy: Cesium.Cartesian3.fromDegreesArray([113.3777, 31.7174, 113.9007, 31.7177, 113.3007, 31.6177]),//fromDegreesArray方法就是让我们录入多个点的位置信息,Cesium则在底层将各个点连接起来,组成一个多边形,这里通过录入三个经纬度坐标位置,绘制一个三角形
        material: Cesium.Color.YELLOW,//设置颜色
        extrudedHeight: 200,//将绘制好的多边形在垂直方向进行拉升,此属性在绘制多边形的时候可以使用,如果绘制的本身是平面则不可以使用
      }
    })
    /** 除了修改样式以外,还常需对它们进行增、删、改 **/
    //五秒后颜色设置为白色
    // setTimeout(() => {
    //   viewer.entities.getById("polygon_stretch_id").polygon.material = Cesium.Color.WHITE
    // }, 5000);
    // setTimeout(() => {//十秒后删除拉伸模型
    //   viewer.entities.remove(entity_polygon_stretch)
    // }, 10000);
    //移除场景内的所有实体,使用removeAll()方法
    setTimeout(() => {//五秒后清除所有实体
      viewer.entities.removeAll()
    }, 5000);
    //地球加载一个glb模型
    const orientation = Cesium.Transforms.headingPitchRollQuaternion(position, new Cesium.HeadingPitchRoll(-90, 0, 0))//定义模型朝向变量:参数一:位置信
    const entity_glb = viewer.entities.add({//使用Entities加载一个glb模型用于观察
      position: position,//模型位置
      orientation: orientation,//模型朝向
      model: {//模型信息
        uri: "./data/car.glb",//模型路径
        minimumPixelSize: 100,//模型最小的大小
        maxmumScale: 10000,//模型缩放最大比例
        show: true,//模型的显示
      }
    })
    //地球加载一个文本标签 
    const entity_txt = viewer.entities.add({//使用Entities加载一个glb模型用于观察
      position: position,//文字位置
      label:{
        text:"我是一段文字",//设置文字大小和样式
        font:"50px Helvetica",//字体
        fillColor:Cesium.Color.YELLOW//字体颜色
      }
    })
    // viewer.trackedEntity = entity;//将摄像头设置在圆点处(track跟踪)
    //------------------------------空间数据加载演示结束------------------------------
  </script>
</body>
</html>
九、鼠标交互,数据查询
1、鼠标左键点击图片后提示弹框
代码如下:
var handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)//使用Cesium的ScreenSpaceEventHandler方法,创建了一个屏幕控制实例,其中viewer.scene.canvas获取scene下的所有canvas创建的元素
handler.setInputAction(function (movement){//再使用setInputAction方法进行监听,可以监听鼠标相关事件,第一个参数放入回调函数,第二个参数是监听的具体是鼠标的哪个事件
  var pick = viewer.scene.pick(movement.position);//创建一个变量,通过viewer.scene.pick可以获取到点击的对象的位置信息
  if(Cesium.defined(pick) && pick.id.id==="image_id"){
    alert("点击了图片!")
  } //并对其判断,并要同时满足,当前获取对象的id号是否和之前绑定的image_id一致
},Cesium.ScreenSpaceEventType.LEFT_CLICK)
/**
 补充说明:Cesium给我们提供了好几种获取不同对象的方法
//scene.pick返回的是包含给定窗口位置基元的对象,
//scene.drillpick返回的是给定窗口位置所有对象的列表,
//Globe.pick返回的是给定光线和地形的交点,
//际此以外 Cesium还提供了多种鼠标监听可供我们选择:
//鼠标中键点击事件: Cesium.ScreenSpaceEventType.MIDDLE_CLICK
//鼠标移入事件: Cesium.ScreenSpaceEventType.MOUSE_MOVE
//鼠标右击事件: Cesium.ScreenSpaceEventType.RIGHT_CLICK
**/
效果如下:
 
2、自定义弹框
代码如下:
<!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>cesium第四课,鼠标交互,数据查询</title>
  <!-- cesium.js引入 -->
  <script src="../libs/Cesium/Cesium.js"></script>
  <!-- cesium样式引入 -->
  <link href="../libs/Cesium/Widgets/widgets.css" rel="stylesheet">
  <!-- 导入cesium的类型声明,有这个才会有快捷智能提示(已屏蔽,无效) -->
  <!-- <script src="../libs/Cesium/Cesium.d.ts"></script> -->
  <!-- <reference path="../libs/Cesium/Cesium.d.ts" /> -->
  <style>
    html,
    body {
      margin: 0px;
      padding: 0px;
    }
  </style>
</head>
<body>
  <div id="puiedu-cesiumContainer"></div>
  <script>
    Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI5MWVkMjllNy03ZjY4LTQ3YmQtOTgxOC05NGQ5YTU0ZjM5ZGEiLCJpZCI6MzU5Nywic2NvcGVzIjpbImFzciIsImdjIl0sImlhdCI6MTUzODE5MTUyM30.dtS2F3-q2fGoA93N7cFl-LCikK-Rjk7v01WWA-RqCxg';
    const viewer = new Cesium.Viewer('puiedu-cesiumContainer', {
      animation: false,//动画小组件
      timeline: false,//左下角仪表
    });
    //----------------------------空间数据加载,---------------------------
    const position=Cesium.Cartesian3.fromDegrees(113.37377, 31.717497, 1000) //定义常量,用于存储飞行目的地的坐标
    //setView 直接跳转,没有过程
    viewer.camera.setView({//通过相机系统设置视角
      destination:position,//设置相机目的地
      orientation:{//设置相机视口的方向
        heading:Cesium.Math.toRadians(0),//控制视口的水平旋转,也就是沿着y轴旋转,当数值为0时,代表正北方向
        pitch:Cesium.Math.toRadians(-90),//控制视口的上下旋转,即沿x轴进行旋转,当数值为-90,代表俯视地面
        roll:0,//控制视口的反转角度,即沿着z轴进行旋转,数值为0表示不翻转
      },
    })
    /** 通常除了简单的图形、颜色加载以外,更多时候需要定制化的样式,通过代码看下他的可选配置项 **/
    //地球加载一个图片
    const entity_image = viewer.entities.add({//创建一个Entity点对象
      id:"image_id",//id标识
      position: Cesium.Cartesian3.fromDegrees(113.37377, 31.717497, 100),//设置经纬度和高度
      plane: {//用于绘制一个面
        plane: new Cesium.Plane(Cesium.Cartesian3.UNIT_X, 0),//确认面的朝向,这里我们设置它朝X轴平铺
        dimensions: new Cesium.Cartesian2(200, 150),//设置面的长度和宽度
        material: "./data/a.png",//引入图片
        outline: true,//是否显示边框
        outlineColor: Cesium.Color.GREEN//边框线为黑色
      },
      description:`<div>
        <img width="100%" height:"300px" src="./data/a.png" />
        <h3>自定义点击弹框</h3>
        </div>`,//description属性用于设置选定对象的显示信息,在其中我们可以直接用HTML标签,将其包裹后,可以直接传到页面中,不需要额外设定样式,封装事件
    })
    
    var handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)//使用Cesium的ScreenSpaceEventHandler方法,创建了一个屏幕控制实例,其中viewer.scene.canvas获取scene下的所有canvas创建的元素
    handler.setInputAction(function (movement){//再使用setInputAction方法进行监听,可以监听鼠标相关事件,第一个参数放入回调函数,第二个参数是监听的具体是鼠标的哪个事件
      var pick = viewer.scene.pick(movement.position);//创建一个变量,通过viewer.scene.pick可以获取到点击的对象的位置信息
      if(Cesium.defined(pick) && pick.id.id==="image_id"){
        alert("点击了图片!")
      } //并对其判断,并要同时满足,当前获取对象的id号是否和之前绑定的image_id一致
    },Cesium.ScreenSpaceEventType.LEFT_CLICK)
    /**
     补充说明:Cesium给我们提供了好几种获取不同对象的方法
    //scene.pick返回的是包含给定窗口位置基元的对象,
    //scene.drillpick返回的是给定窗口位置所有对象的列表,
    //Globe.pick返回的是给定光线和地形的交点,
    //际此以外 Cesium还提供了多种鼠标监听可供我们选择:
    //鼠标中键点击事件: Cesium.ScreenSpaceEventType.MIDDLE_CLICK
    //鼠标移入事件: Cesium.ScreenSpaceEventType.MOUSE_MOVE
    //鼠标右击事件: Cesium.ScreenSpaceEventType.RIGHT_CLICK
    **/
    //------------------------------空间数据加载演示结束------------------------------
  </script>
</body>
</html>
效果如下:
 
总结:其实弹窗显示数据,本质上就是一种空间信息数据的查询,是用户与客户端信息交互的最典型功能
十、三维数据3dtiles
(1)、它是Cesium于2016年3月定义的一种三维模型瓦片数据结构。它将海量的三维数据用分块、分层的形式组织起来,这样就很大程度上减轻了浏览器的负担,除此以外还提供了细节层次的LOD功能。在远观时,降低模型的面数和精度,拉近后再将细节加载出来,大大增强了页面的加载速度,更可以用于跨桌面使用,使得Web端和移动应用程序共享。
 
(2)、那么3D Tiles与其他数据对比叉有什么特点呢?
其一,它是一个开放式的数据规范,我们可以根据实际需求设定三维模型的大小和范围,此外还能适配多种空间分区方案,如普通网格、四叉树、八叉树等;
 这里简单了解一下四叉树和八又树的数据结构:
 四叉树是一种树形数据结构,它的每个节点可以有四个子节点,通常把二维空间细分为四个区域,并把该区域里的相关信息存入到四叉树节点中,四叉树的每一个节点代表一个矩形区域,每一个矩形区域叉可划分为四个小矩形区域
 
 较之四叉树,八又树将场景从二维空间延伸到了三维空间
 
 树中的子节点只会有八个或者零个,每一个节点同样用于存储数据。
 其二,它的异质性支持,可以将不同类型的号维模型数据,如普通模型数据加倾斜摄影数据加自绘几何数据放在一起,转化为同一标准的数据集,让它们可以在同一场景下显示出来。
 其三,它是专门为三维可视化设计的,并在其中引入了图形领域的技术,在不满足特定条件的情况下,并不会对场景内的模型做整个渲染,而是只会渲染个轮廓,大大降低了计算量,使得浏览器请求到数据以后,渲染的流程也更加的简单。同时。因为三维模型预先处理成了分块的三维瓦片格式,所以也减少了WebGL绘制请求的数量。
 其四,它的可交互性,其支持对加载模型的拾取,和样式的修改,大量加载以后,可以对其中的单独模型进行交互。如高亮显示鼠标悬停处的模型、或进行删除等;也可根据建筑模型的高度和年代,设置不同的显示效果而不需要重新更新代码。
(3)、接下来我们来了解一下,3DTiles的代码究竟是如何构成的
一个简单的3dtiles文件夹结构如下:
 
 可以看到除了json文件以外,还有三个b3dm格式的文件,它就是我们用于渲染数据的文件。
 如上图:3DTiles的格式是由两个部分组成的,其一就是现在看到的tileset.json格式的数据,我们先来了解一下它的格式。
 
 这里的asset是一个包含整体tileset元素属性的对象,其中的version属性是定义3DTiles版本的字符串,此外这里还可以选填一个
tilesetVersion属性,它可以用于定义特定应用中的版本号。
geometricError:其定义了一个非误差单位,低于这个误差值,瓦片集不会被渲染,这里设定的500,它的单位是米。
root属性用于定义根瓦片,它的子项transform也是一个可选项,它的作用是在加载大量模型或者建筑物的情况下,单个模型的点云瓦片集能在它自己的坐标系中定义,其内的数据是一个4X4的仿射变换矩阵,以列主序存储,用来实现从瓦片局部坐标系到父瓦片或根瓦片坐标系的变换。
root内部也有一个同样的属性,前者是整个瓦片集不被渲染的误差,后者只是当前瓦片集被渲染的误差。content属性通过ur引入文件,这里引入的文件就是瓦片的内容,它的数据是二进制的,其支持的二进制文件格式有:.b3dm、.i3dm、.pnts等。甚至可以在其中再放入一个3DTiles文件,前提是不可以自己引用给自己,content上方的refine属性定义的是LOD细化的方法,简单来说就是瓦片是如何切换的。
下方的children属性比较好理解,因为3DTiles是分级别的,所以每个Tile还会有子Tile、子子Tile。构成3D Tiles的第二个部分就是其引用的瓦片数据文件了。
(4)、来通过代码看一下3dtiles是如何引用的:此模型使用的是b3dm格式的瓦片集,主要用于加载批量的模型,除此以外还有pnts格式瓦片集,用于加载点云数据模型;cmpt格式瓦片集,允许一个cmpt文件内嵌多个其他类型的瓦片
<!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>cesium第五课,加载3dtiles</title>
  <!-- cesium.js引入 -->
  <script src="../libs/Cesium/Cesium.js"></script>
  <!-- cesium样式引入 -->
  <link href="../libs/Cesium/Widgets/widgets.css" rel="stylesheet">
  <!-- 导入cesium的类型声明,有这个才会有快捷智能提示(已屏蔽,无效) -->
  <!-- <script src="../libs/Cesium/Cesium.d.ts"></script> -->
  <!-- <reference path="../libs/Cesium/Cesium.d.ts" /> -->
  <style>
    html,
    body {
      margin: 0px;
      padding: 0px;
    }
  </style>
</head>
<body>
  <div id="puiedu-cesiumContainer"></div>
  <script>
    Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI5MWVkMjllNy03ZjY4LTQ3YmQtOTgxOC05NGQ5YTU0ZjM5ZGEiLCJpZCI6MzU5Nywic2NvcGVzIjpbImFzciIsImdjIl0sImlhdCI6MTUzODE5MTUyM30.dtS2F3-q2fGoA93N7cFl-LCikK-Rjk7v01WWA-RqCxg';
    const viewer = new Cesium.Viewer('puiedu-cesiumContainer', {
      animation: false,//动画小组件
      timeline: false,//左下角仪表
    });
    //----------------------------加载3dtiles,---------------------------
  var tileset=viewer.scene.primitives.add(//发现这里的加载方法并不是之前常用的entities,这是因为3DTiles并不是Entity的一部分,而是属于更加底层的primitives
    new Cesium.Cesium3DTileset({
      url:"./data/dtiles/tileset.json",//模型地址
      maximumScreenSpaceError:2,//最大的屏幕空间误差,数字越低,视觉效果越好
      maximumNumberOfLoadedTiles:1000,//最大加载瓦片个数,用于给定一定的限制,防止数据量过大,占用内存过高
    })
  )
  
  tileset.readyPromise.then((tileset) => {//模型加载完毕后的回调
    viewer.zoomTo(tileset);
  });
    //------------------------------加载3dtiles------------------------------
  </script>
</body>
</html>
十一、时间系统、粒子系统
1、时间系统
其在动态数据可视化中发挥了重要的作用,在三维场景的基础上增加了时间维度信息,Cesium初始化是自带时间控件的,默认是会显示当前的时间;Cesium的时间控件Clock由两部分构成,第一部分是Animation控件,控制时间的启动和暂停,第二部分是Timeline控件,控制时间线,如果我们不想显示两个控件,可以在Viewer初始化中将其都设置成false{animation: false,//动画小组件timeline: false,//左下角仪表};我们知道操控时间的Animation控件默认是暂停状态;下面来看一下,如何使用代码修改它们的状态:
viewer.clock.shouldAnimate=true;//设置其clock属性下的shouldAnimate为true,实现初始化页面自动循环播放的效果
viewer.clock.multiplier=1000;//使用它的multiplier属性,设定时间速率为1000,默认时间线是当前时间的24小时
let start=Cesium.JulianDate.fromIso8601('2022-01-05')//给他们设置一个新的时间线,用一个变量存储起始时间,使用JulianDate计算时间差,再通过fromIso8601转换成对应的格式
let end = Cesium.JulianDate.fromIso8601('2022-01-20')//同样的方法设置结束时间
viewer.timeline.zoomTo(start,end)//最后使用timeline的zoomTo方法将时间设置上去
效果如下:时间在自动播放
 
2、粒子系统
除了动效以外,Cesium为了实现更加逼真的学维仿真模拟,还加入了粒子系统,用于实现各种特效,如烟花燃放特效、天气效果车辆尾气的特效。Cesium的粒子系统是一种模拟复杂物理效应的图形技术,是由很多的小图像组成的集合,形成一个模糊对象,从而产生特效。
如果我们加载的是粒子类的数据,就需要使用primitives用于加载数据,因为其更接近底层的图形开发,Cesium为我们提供了这个对象用于创建粒子系统,代码如下:
<!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>cesium第六课,粒子系统的演示</title>
  <!-- cesium.js引入 -->
  <script src="../libs/Cesium/Cesium.js"></script>
  <!-- cesium样式引入 -->
  <link href="../libs/Cesium/Widgets/widgets.css" rel="stylesheet">
  <!-- 导入cesium的类型声明,有这个才会有快捷智能提示(已屏蔽,无效) -->
  <!-- <script src="../libs/Cesium/Cesium.d.ts"></script> -->
  <!-- <reference path="../libs/Cesium/Cesium.d.ts" /> -->
  <style>
    html,
    body {
      margin: 0px;
      padding: 0px;
    }
  </style>
</head>
<body>
  <div id="puiedu-cesiumContainer"></div>
  <script>
    Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI5MWVkMjllNy03ZjY4LTQ3YmQtOTgxOC05NGQ5YTU0ZjM5ZGEiLCJpZCI6MzU5Nywic2NvcGVzIjpbImFzciIsImdjIl0sImlhdCI6MTUzODE5MTUyM30.dtS2F3-q2fGoA93N7cFl-LCikK-Rjk7v01WWA-RqCxg';
    let esri = new Cesium.ArcGisMapServerImageryProvider({
      url: "https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer"
    })//用一个变量存储新地图的信息,这里我们使用的是arcgis地图服务
    const viewer = new Cesium.Viewer('puiedu-cesiumContainer', {
        animation: true,//动画小组件
        timeline: true,//左下角仪表,
        baseLayerPicker: false,//默认的地图按钮设置为隐藏
        imageryProvider: esri,//viewer内的imageryProvider属性用于设置地图
        terrainProvider: new Cesium.CesiumTerrainProvider({//此时地球表面是没有比如山脉3d地形的,所以下面加载地形数据放入引入的地形;CesiumTerrainProvider方法是将地形数据,转换为Cesium可以访问的格式
          url: Cesium.IonResource.fromAssetId(1),//url 属性用于放入地形服务器的地址
          requestVertexNormals: true,//requestVertexNormals属性设置为true,可以增加法线,用于提高光照效果
          requestWaterMask: true,//可以增加水面特效
        }),
      });
    //注意:粒子系统是依赖于时间系统的,是根据时间来变换的,所以这里设置下自动播放时间
    viewer.clock.shouldAnimate = true;//设置其clock属性下的shouldAnimate为true,实现初始化页面自动循环播放的效果
    viewer.clock.multiplier = 1000;//使用它的multiplier属性,设定时间速率为1000,默认时间线是当前时间的24小时
    let start = Cesium.JulianDate.fromIso8601('2022-01-05')//给他们设置一个新的时间线,用一个变量存储起始时间,使用JulianDate计算时间差,再通过fromIso8601转换成对应的格式
    let end = Cesium.JulianDate.fromIso8601('2022-01-20')//同样的方法设置结束时间
    viewer.timeline.zoomTo(start, end)//最后使用timeline的zoomTo方法将时间设置上去
    //----------------------------粒子特效,---------------------------
   //地球加载一个glb模型
    const position = Cesium.Cartesian3.fromDegrees(113.37377, 31.717497, 100) //定义常量,用于存储飞行目的地的坐标
    const orientation = Cesium.Transforms.headingPitchRollQuaternion(position, new Cesium.HeadingPitchRoll(-90, 0, 0))//定义模型朝向变量:参数一:位置信
    const entity_glb = viewer.entities.add({//使用Entities加载一个glb模型用于观察
      position: position,//模型位置
      orientation: orientation,//模型朝向
      model: {//模型信息
        uri: "./data/car.glb",//模型路径
        minimumPixelSize: 100,//模型最小的大小
        maxmumScale: 10000,//模型缩放最大比例
        show: true,//模型的显示
      }
    })
    viewer.camera.viewBoundingSphere(new Cesium.BoundingSphere(position, 20), new Cesium.HeadingPitchRange(0, 0, 0)) //视角绑定实体,参数一:设置视点位置BoundingSphere,参数二,相机的朝向HeadingPitchRange。其中new Cesium.BoundingSphere参数一:位置,参数二,和物体的距离
    viewer.scene.primitives.add(
      new Cesium.ParticleSystem({
        image: "./data/fire.png", //这里的image中放置的就是粒子的样式,通常使用路径的方式引用
        imageSize: new Cesium.Cartesian2(20,20),//imageSize用于设置粒子图片的大小
        startScale: 1.0,//startScale设置的是初始大小的倍数,它是与endScale相关联的
        endScale: 4.0,//这两个属性控制的是,粒子从生成到消亡整个周期,从初始大小,逐渐变化到原来尺寸的四倍,也可以根据需求设置初始很大,然后逐渐缩小
        particleLife: 1.0,//这里设置的是每一个粒子存在的时间,使得粒子随机生成生命周期
        speed:3.0,//粒子速度
        emitter: new Cesium.CircleEmitter(1),//粒子系统发射器,这里设置的是圆形发射器,0.5设置的是圆的半径,粒子将会在圆的范围内随机向上发射粒子,在半径以内随机生成
        // emitter: new Cesium.BoxEmitter(new Cesium.Cartesian3(10,10,10)),//粒子系统发射器,这里设置的是盒体发射器,并在其中设置了盒子的大小,粒子在盒子范围内随机生成
        emissionRate: 5.0,//每秒钟发射粒子的数量,数值越大,性能消耗越大
        lifetime: 16.0,//使用lifetime指定持续时间,这里设置为16秒
        modelMatrix: entity_glb.computeModelMatrix(viewer.clock.startTime, new Cesium.Matrix4()),//设置粒子系统的位置,它将粒子系统从模型转换为世界坐标的 4x4 转换矩阵,这里需要绑定到glb模型上,并用它的这个方法,在指定时间计算实体变换的模型矩阵,其中clock.startTime获取的就是时间控件中的起始时间
      })
    );
    //------------------------------粒子特效结束------------------------------
  </script>
</body>
</html>
效果如下:
 
十二、动态数据格式CZML
未完待续…



















