- 一、Cesium前置知识:
- 二、Cesium开始开发:
- 三、Cesium开发基础:
- 四、Cesium开发进阶:
15 - Cesium视频总结
一、Cesium前置知识:
最新使用cesium的1.93版本。
1,Cesium支持的数据格式:
2,Cesium在项目中的定位:
3,Cesium学习路线:
Viewer类 ——> Camera类 ——> ImageryLayer类 ——> TerrainProvider类 ——> Entity类 ——> Cesium3DTileset类 ——> Primitive类 ——> Fabric类 ——> ParticleSystem类
4,Cesium进阶方向:
二、Cesium开始开发:
1,Vue3 + Cesium配置方案:
(1)安装依赖:
"dependencies": {
"cesium": "^1.93.0",
"sass": "^1.70.0",
"vue": "^3.3.11"
},
"devDependencies": {
"@vitejs/plugin-vue": "^4.5.2",
"vite": "^5.0.8",
"vite-plugin-cesium": "^1.2.22",
"vue-router": "^4.2.5"
}
(2)在vite.config.js中添加插件:
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import cesium from 'vite-plugin-cesium'
import path from 'path'
export default defineConfig({
plugins: [vue(), cesium()],
resolve: {
alias: {
'@': path.resolve(__dirname, 'src')
}
}
})
(3)添加Home.vue,并引入Cesium,同时去掉Cesium默认组件:
<script setup>
import * as Cesium from 'cesium'
import { onMounted } from 'vue'
onMounted(() => {
const viewer = new Cesium.Viewer('cesiumContainer', {
animation: false, // 动画小组件
baseLayerPicker: false, // 底图组件,选择三维数字地球的底图
fullscreenButton: false, // 全屏组件
vrButton: false, // VR模式
geocoder: false, // 地理编码搜索组件
homeButton: false, // 首页,点击之后将视图跳转到默认视角
infoBox: false, // 信息框
sceneModePicker: false, // 场景模式,切换2D、3D和Columbus Views(CV)模式
selectionIndicator: false, // 是否显示选取指示器组件
timeline: false, // 时间轴
navigationHelpButton: false, // 帮助提示,如何操作数字地球
navigationInstructionsInitiallyVisible: false,
// 添加地形效果
// terrain: new Cesium.Terrain.fromWorldTerrain({
// url: Cesium.IonResource.fromAssetId(3956),
// requestWaterMask: true, // 请求水体效果所需要的海水波浪数据
// requestVertexNormals: true // 请求地形照明数据
// })
// 添加Cesium官方图层
baseLayer: Cesium.ImageryLayer.fromProviderAsync(
Cesium.TileMapServiceImageryProvider.fromUrl(
// 给定 Cesium 基本 URL 下的相对 URL,返回绝对 URL。
// http://localhost:5173/cesium/Assets/Textures/NaturalEarthII
Cesium.buildModuleUrl("Assets/Textures/NaturalEarthII"),
)),
})
})
</script>
<template>
<div id="cesiumContainer"></div>
</template>
<style lang="scss">
#cesiumContainer {
width: 100vw;
height: 100vh;
.cesium-viewer-bottom {
visibility: hidden;
}
}
</style>
2,Cesium源码目录:
(1)前端打包方式整理:
1,gulp:Cesium源码打包方式,也用到了rollup。
2,webpack和vite:单页面应用程序(SPA)的打包方式,比如Vue、React工程打包。
3,rollup:SDK库文件打包方式,比如Vue、React库文件打包。
(2)Cesium源码目录:
(3)Cesium导航首页:
3,Cesium初始化:
把Cesium初始页面除了地球之外所有控件删除。
<script setup>
import * as Cesium from 'cesium'
import { onMounted } from 'vue'
onMounted(() => {
const viewer = new Cesium.Viewer('cesiumContainer', {
animation: false, // 动画小组件
baseLayerPicker: false, // 底图组件,选择三维数字地球的底图
fullscreenButton: false, // 全屏组件
vrButton: false, // VR模式
geocoder: false, // 地理编码搜索组件
homeButton: false, // 首页,点击之后将视图跳转到默认视角
infoBox: false, // 信息框
sceneModePicker: false, // 场景模式,切换2D、3D和Columbus Views(CV)模式
selectionIndicator: false, // 是否显示选取指示器组件
timeline: false, // 时间轴
navigationHelpButton: false, // 帮助提示,如何操作数字地球
navigationInstructionsInitiallyVisible: false
})
})
</script>
<template>
<div id="cesiumContainer"></div>
</template>
<style lang="scss">
#cesiumContainer {
width: 100vw;
height: 100vh;
.cesium-viewer-bottom {
visibility: hidden;
}
}
</style>
4,API目录:
5,Cesium添加天地图和MapBox底图:
以下这个小方法可以拿到所有默认图层的集合:
// 拿到所有默认图层配置的集合
console.log(Cesium.createDefaultImageryProviderViewModels())
Cesium通过WMTS或者XYZ的方式都可以添加天地图,其中,WMTS需要使用Cesium.WebMapTileServiceImageryProvider类,TMS需要使用Cesium.UrlTemplateImageryProvider类。
(1)通过WMTS方式添加天地图矢量图层:
OGC各项服务介绍:
viewer.imageryLayers.addImageryProvider(new Cesium.WebMapTileServiceImageryProvider({
url: "http://t0.tianditu.com/vec_w/wmts?service=wmts&request=GetTile&version=1.0.0&LAYER=vec&tileMatrixSet=w&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}&style=default&format=tiles&tk=" + tianditutk,
layer: "tdtVecBasicLayer",
style: "default",
format: "image/jpeg",
tileMatrixSetID: "GoogleMapsCompatible",
show: true
}))
或者是:
const viewer = new Cesium.Viewer('cesiumContainer', {
animation: false, // 动画小组件
baseLayerPicker: false, // 底图组件,选择三维数字地球的底图
fullscreenButton: false, // 全屏组件
vrButton: false, // VR模式
geocoder: false, // 地理编码搜索组件
homeButton: false, // 首页,点击之后将视图跳转到默认视角
infoBox: false, // 信息框
sceneModePicker: false, // 场景模式,切换2D、3D和Columbus Views(CV)模式
selectionIndicator: false, // 是否显示选取指示器组件
timeline: false, // 时间轴
navigationHelpButton: false, // 帮助提示,如何操作数字地球
navigationInstructionsInitiallyVisible: false,
mapProjection: new Cesium.WebMercatorProjection(),
baseLayer: new Cesium.ImageryLayer(new Cesium.WebMapTileServiceImageryProvider({
url: new Cesium.Resource({
url: `${tdtUrl}vec_w/wmts?tk=${token}`
}),
layer: "vec",
style: "default",
format: "tile",
tileMatrixSetID: "w",
show: true
}))
})
(2)通过TMS方式添加天地图影像图层:
viewer.imageryLayers.addImageryProvider(new Cesium.UrlTemplateImageryProvider({
url: 'http://t0.tianditu.gov.cn/DataServer?T=img_w&x={x}&y={y}&l={z}&tk=590447cdbdf97775b57588a69ebb903d',
})
或者是:
const viewer = new Cesium.Viewer('cesiumContainer', {
animation: false, // 动画小组件
baseLayerPicker: false, // 底图组件,选择三维数字地球的底图
fullscreenButton: false, // 全屏组件
vrButton: false, // VR模式
geocoder: false, // 地理编码搜索组件
homeButton: false, // 首页,点击之后将视图跳转到默认视角
infoBox: false, // 信息框
sceneModePicker: false, // 场景模式,切换2D、3D和Columbus Views(CV)模式
selectionIndicator: false, // 是否显示选取指示器组件
timeline: false, // 时间轴
navigationHelpButton: false, // 帮助提示,如何操作数字地球
navigationInstructionsInitiallyVisible: false,
mapProjection: new Cesium.WebMercatorProjection(),
// 添加影像底图
baseLayer: new Cesium.ImageryLayer(new Cesium.UrlTemplateImageryProvider({
url: 'http://t0.tianditu.gov.cn/DataServer?T=img_w&x={x}&y={y}&l={z}&tk=590447cdbdf97775b57588a69ebb903d',
}))
})
(3)添加MapBox底图:
// 添加mapbox地图,此token过期了
viewer.imageryLayers.addImageryProvider(
new Cesium.MapboxImageryProvider({
mapId: ''mapbox.satellite'',
accessToken: 'pk.eyJ1IjoiY2hlbmdiZW5jaGFvIiwiYSI6ImNsODU3aGRiODA0Y2UzcHBzZmFlcmdqZ2sifQ.8k59W_pB_Riwe6o-MneRlA'
})
)
三、Cesium开发基础:
1,Cesium坐标系:
屏幕坐标、地理坐标(弧度)、地理坐标(经纬度)和世界坐标之间的转换。
(1)屏幕坐标(经纬度):new Cesium.Cartesian2(x, y)
(2)笛卡尔空间直角坐标系(世界坐标):new Cesium.Cartesian3(x, y, z),通常用于平移、旋转和缩放
(3)地理坐标(弧度):new Cesium.Cartographic(lng, lat, height)
(4)经纬度坐标(经纬度):Cesium默认是WGS84地理坐标系
// 弧度转经纬度
Cesium.Math.toDegrees(degrees)
// 经纬度转弧度
Cesium.Math.toRadians(radians)
//1, 经纬度转笛卡尔坐标(世界坐标), cartesian是笛卡尔的意思
const catesian1 = Cesium.Cartesian3.fromDegrees(110, 20, 20)
const catesianArr = Cesium.Cartesian3.fromDegreesArray([
120, 20,
121, 23
])
console.log(catesian1)
// 弧度制转笛卡尔坐标(世界坐标)
const b = Cesium.Cartesian3.fromRadians(a.longitude, a.latitude, a.height)
console.log(b)
// 2,世界坐标转经纬度坐标
// 笛卡尔坐标转弧度地理坐标
const a = Cesium.Cartographic.fromCartesian(catesian1)
// const alat = 180 / Math.PI * a.latitude
// const alng = 180 / Math.PI * a.longitude
// 弧度地理坐标转角度坐标
console.log(b)
const alng = Cesium.Math.toDegrees(a.longitude)
const alat = Cesium.Math.toDegrees(a.latitude)
console.log(alng)
console.log(alat)
// 3,二维屏幕坐标转三维笛卡尔空间直角坐标系(世界坐标)
const cartesian3 = viewer.scene.globe.pick(
viewer.camera.getPickRay(windowPosition),
scene
)
// 4,三维笛卡尔空间直角坐标转为二维屏幕坐标,结果是Cartesian2对象,取出X,Y即为屏幕坐标。
const windowPosition = Cesium.SceneTransforms.wgs84ToWindowCoordinates(scene, cartesian3);
// 或者是:
const canvasPosition = viewer.scene.cartesianToCanvasCoordinates(cartesian1)
2,Cesium坐标转换工具:
3,Cesium加载影像数据:
主要接口:ImageryLayerCollection ——> ImageryLayer ——> ImageryProvider
其中,ImageryProvider分为九个大类,十一种类型,分别是:
(1)加载天地图矢量图层:
// viewer.scene.imageryLayers和viewer.imageryLayers是同一对象
console.log(viewer.scene.imageryLayers === viewer.imageryLayers) // 返回true
// 1,加载天地图图层
const layer = new Cesium.UrlTemplateImageryProvider({
url: 'http://t1.tianditu.com/vec_w/wmts?layer=vec&tilematrixset=w&Service=WMTS&Request=GetTile&Version=1.0.0&TileMatrix={z}&TileCol={x}&TileRow={y}&tk=590447cdbdf97775b57588a69ebb903d'
})
// 添加图层,并设置图层透明度
viewer.imageryLayers.addImageryProvider(layer).alpha = 0.5
(2)加载mapbox图层:
// 2,加载mapbox图层,下面加载的mapbox图层中,除了第一个卫星图之外都请求不到资源了,报410的状态码
const mapIds = [
'mapbox.satellite',
'mapbox.streets',
'mapbox.streets-basic',
'mapbox.light',
'mapbox.streets-satellite',
'mapbox.wheatpaste',
'mapbox.comic',
'mapbox.outdoors',
'mapbox.run-bike-hike',
'mapbox.pencil',
'mapbox.pirates',
'mapbox.emerald',
'mapbox.high-contrast'
]
viewer.imageryLayers.addImageryProvider(
new Cesium.MapboxImageryProvider({
mapId: mapIds[0],
accessToken: 'pk.eyJ1IjoiY2hlbmdiZW5jaGFvIiwiYSI6ImNsODU3aGRiODA0Y2UzcHBzZmFlcmdqZ2sifQ.8k59W_pB_Riwe6o-MneRlA'
})
)
4,Cesium加载地形数据:
主要接口:Cesium.CesiumProvider()
// cesium版本1.107.0之前的加载地形方式
viewer.terrainProvider = new Cesium.CesiumTerrainProvider({
url: 'https://assets.agi.com/stk-terrain/world'
});
cesium版本更新之后,删除了 viewer.terrainProvider 接口,其加载地形方式发生了改变:
第一种方式:调用Cesium.createWorldTerrainAsync()
// cesium版本1.107.0之后的加载地形方式
const addWorldTerrainAsync = async (viewer) => {
try {
const terrainProvider = await Cesium.createWorldTerrainAsync({
requestWaterMask: true,
requestVertexNormals: true,
});
viewer.terrainProvider = terrainProvider;
} catch (error) {
console.log(`Failed to add world imagery: ${error}`);
}
}
addWorldTerrainAsync(viewer)
viewer.scene.globe.enableLighting = true // 对大气和雾启用实时动态照明效果
// 启用深度测试,让地形后面的东西消失。为true实现高程遮挡(在没有地形时候也会有高程遮挡效果),为false则绘制与添加的图元均在地球顶部不会出现遮挡问题,按实际应用情况设置
viewer.scene.globe.depthTestAgainstTerrain = true
console.log(viewer.scene.imageryLayers === viewer.imageryLayers)
})
第二种方式:在创建Viewer时直接添加地形:
const viewer = new Cesium.Viewer('cesiumContainer', {
terrain: new Cesium.Terrain.fromWorldTerrain({
url: Cesium.IonResource.fromAssetId(3956),
requestWaterMask: true, // 请求水体效果所需要的海水波浪数据
requestVertexNormals: true // 请求地形照明数据
})
})
5,Cesium加载矢量数据:
(1)Cesium支持的矢量数据格式有:geojson、topojson、kml、具有时间特性的czml。
DataSourceCollection有:
CustomDataSource、CzmlDataSource、GeoJsonDataSource、KmlDataSource
Cesium添加CustomDataSource,是Cesium自定义的数据类型,比如entity:
const dataSource = new Cesium.CustomDataSource('myData');
const entity = dataSource.entities.add({
position : Cesium.Cartesian3.fromDegrees(1, 2, 0)
});
viewer.dataSources.add(dataSource);
(2)Topjson介绍:
在线生成TopoJSON和GeoJSON的网站:https://geojson.io/
topojson和geojson面数据示例:
{"type":"Topology","objects":{"collection":{"type":"GeometryCollection","geometries":[{"type":"Polygon","arcs":[[0]]}]}},"arcs":[[[115.22446921011499,33.607866983978],[115.22446921011499,29.852609554190323],[117.75358850351438,29.852609554190323],[117.75358850351438,33.607866983978],[115.22446921011499,33.607866983978]]],"bbox":[115.22446921011499,29.852609554190323,117.75358850351438,33.607866983978]}
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {},
"geometry": {
"coordinates": [
[
[
115.22446921011499,
33.607866983978
],
[
115.22446921011499,
29.852609554190323
],
[
117.75358850351438,
29.852609554190323
],
[
117.75358850351438,
33.607866983978
],
[
115.22446921011499,
33.607866983978
]
]
],
"type": "Polygon"
}
}
]
}
添加TopJSON或GeoJSON数据:
// 1,添加GeoJSON数据源,返回一个Promise
const dataSource = Cesium.GeoJsonDataSource.load('/polygon.topojson', {
stroke: Cesium.Color.RED,
strokeWidth: 3,
fill: Cesium.Color.PINK.withAlpha(0.5)
})
// 2,把数据源添加到viewer中
dataSource.then(res => {
viewer.dataSources.add(res)
viewer.flyTo(res)
})
(3)KML介绍:
(4)CZML介绍:
CZML格式的数据是一种时态数据,可以做Cesium轨迹动画。
CZML Structure · AnalyticalGraphicsInc/czml-writer Wiki (github.com)
CZML添加一个点简单示例:
const czml = [
{
id: "document",
name: "CZML Point",
version: "1.0",
},
{
id: "point 1",
name: "point",
position: {
cartographicDegrees: [-111.0, 40.0, 0],
},
point: {
color: {
rgba: [255, 255, 255, 255],
},
outlineColor: {
rgba: [255, 0, 0, 255],
},
outlineWidth: 4,
pixelSize: 20,
},
},
];
const viewer = new Cesium.Viewer("cesiumContainer");
const dataSourcePromise = Cesium.CzmlDataSource.load(czml);
viewer.dataSources.add(dataSourcePromise);
viewer.zoomTo(dataSourcePromise);
6,Cesium加载3D Tiles数据:
(1)3D Tiles数据介绍:
带有LOD(层次细节模型)的glTF,专门为流式传输和渲染海量3D地理空间数据设计,例如倾斜摄影、3D建模、BIM/CAD、实例化要素集的点云。
![](.\cesium基础知识\3D Tiles数据介绍.jpg)
![](.\cesium基础知识\3D Tiles数据结构介绍.jpg)
![](.\cesium基础知识\3D Tiles数据结构.jpg)
3D Tiles相关类介绍:
cesium更新版本后将Cesium3DTileFeature类的getPropertyNames()换成getPropertyIds()。
![](.\cesium基础知识\3D Tiles相关类.jpg)
(2)添加3D Tiles数据代码:
// 添加3D Tiles的数据源,需要使用异步函数加载
async function add3DTile() {
const tileset = await Cesium.Cesium3DTileset.fromUrl(
"/Tileset/tileset.json" // 瓦片索引
)
// 1,添加tileset
viewer.scene.primitives.add(tileset)
// 视图定位
viewer.zoomTo(tileset, new Cesium.HeadingPitchRange(
0.0, -0.5, tileset.boundingSphere.radius * 2.0
))
const boundingSphere = tileset.boundingSphere
console.log(boundingSphere.center)
// 2,设置样式
const properties = tileset.properties
if (Cesium.defined(properties) && Cesium.defined(properties.Height)) {
tileset.style = new Cesium.Cesium3DTileStyle({
color: {
conditions: [
["${Height} >= 83", "color('purple', 0.5)"],
["${Height} >= 80", "color('red')"],
["${Height} >= 70", "color('orange')"],
["${Height} >= 12", "color('yellow')"],
["${Height} >= 7", "color('lime')"],
["${Height} >= 1", "color('cyan')"],
["true", "color('blue')"]
]
}
})
}
// 3,添加鼠标拾取要素
const handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas)
// 绑定鼠标左点击事件
handler.setInputAction((e) => {
console.log(e)
let windowPosition = e.position // 屏幕坐标
// 屏幕坐标转世界坐标
const ray = viewer.camera.getPickRay(windowPosition)
const catesian = viewer.scene.globe.pick(ray, viewer.scene)
// 世界坐标转经纬度坐标
const lat = Cesium.Math.toDegrees(Cesium.Cartographic.fromCartesian(catesian).latitude)
const lng = Cesium.Math.toDegrees(Cesium.Cartographic.fromCartesian(catesian).longitude)
console.log('经度坐标是:' + lng + ';纬度坐标是:' + lat)
// 获取要素
const feature = viewer.scene.pick(windowPosition)
if (Cesium.defined(feature) && feature instanceof Cesium.Cesium3DTileFeature) {
const propertyIds = feature.getPropertyIds()
console.log(propertyIds)
const length = propertyIds.length
for (let i = 0; i < length; ++i) {
let propertyId = propertyIds[i]
console.log(propertyId + ': ' + feature.getProperty(propertyId))
}
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
}
add3DTile()
(3)3D Tiles制作平移动画:
![](.\cesium基础知识\3D Tiles平移动画.png)
// 4,3DTiles制作向上平移的动画
const adjustTilesetHeight = (tileset, height = 10) => {
// 计算出模型模型包围球的中心点,转弧度制
const cartography = Cesium.Cartographic.fromCartesian(tileset.boundingSphere.center)
// 计算与模型包围球中心点经纬度相同的地表点位
const surface = Cesium.Cartesian3.fromRadians(
cartography.longitude, cartography.latitude,
0
)
// 计算调整高度后的模型包围球的中心点
const offset = Cesium.Cartesian3.fromRadians(
cartography.longitude, cartography.latitude,
height
)
// 计算差向量
const diff = Cesium.Cartesian3.subtract(
offset, surface, new Cesium.Cartesian3()
)
console.log(diff);
// 修改模型的变换矩阵
tileset.modelMatrix = Cesium.Matrix4.fromTranslation(diff)
}
let h = 10
setInterval(() => {
adjustTilesetHeight(tileset, h++)
}, 1000)
7,Cesium加载GLTF数据:
(1)GLTF数据介绍:
1,scene: glTF格式的场景结构描述条目。它通过引用node来定义场景图;
2,node: 场景图层次中的一个节点。它可以包含一个变换(比如旋转或平移),并且可以引用其他(子)节点 。此外,它可以引用网格和相机,以及描述网格变换的蒙皮;
3,camera: 定义了用于渲染场景的视锥体配置;
4,mesh: 描述了出现在场景中几何对象实际的几何数据。它是指accessor用于访问实际几何数据material的对象,并且是指在渲染对象时定义其外观的 ;
5,skin: 定义了用于蒙皮的参数,参数的值通过一个accessor对象获得。
6,animation: 描述了一些结点如何随时间进行变换(比如旋转或平移);
7,accessor: 一个访问任意数据的抽象数据源。被mesh、skin和animation元素使用来提供几何数据、蒙皮参数和基于时间的动画值。它通过引用一个bufferView对象,来引用实际的二进制数据;
8,material: 包含了定义3D对象外观的参数。它通常引用了用于3D对象渲染的texture对象;
9,texture: 定义了一个sampler对象和一个image对象。sampler对象定义了image对象在3D对象上的张贴方式。
(2)添加GLTF数据代码:
GLTF加载可以使用两种方式:一种添加entity,一种添加primitive。
// 添加GLTF数据源
async function addGLTF() {
viewer.entities.removeAll()
const position = Cesium.Cartesian3.fromDegrees(
120, 45
)
const heading = Cesium.Math.toRadians(0)
const pitch = 0
const roll = 0
const hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll)
const orientation = Cesium.Transforms.headingPitchRollQuaternion(
position,
hpr
)
// 第一种方式:通过enitity方式
const entity = viewer.entities.add({
name: "ferrari.glb",
position: position,
orientation: orientation,
model: {
uri: "ferrari.glb",
minimumPixelSize: 128, // 最小像素大小
maximumScale: 20000, // 模型的最大比例尺大小
scale: 1, // 缩放比例
incrementallyLoadTextures: true, // 加载模型后的纹理是否可以继续流入
runAnimations: true, // 指定是否应运行 glTF 动画
clampAnimations: true, // 指定 glTF 动画是否应在不带关键帧的持续时间内保持最后一个姿势
shadows: Cesium.ShadowMode.ENABLED, // 指定模型是否 投射或接收来自光源的阴影
heightReference: Cesium.HeightReference.NONE // 表示相对于地形的位置。NONE表示绝对位置
}
})
viewer.trackedEntity = entity
// 第二种方式:通过primitive方式
// 加载调试primitive和地形的工具
viewer.extend(Cesium.viewerCesiumInspectorMixin)
const origin = Cesium.Cartesian3.fromDegrees(120, 46)
const modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(origin)
const model = await Cesium.Model.fromGltfAsync({
url: 'ferrari.gltf',
modelMatrix, // primitive只能通过模型矩阵方式加载位置
scale: 1, // 缩放比例
minimumPixelSize: 128, // 最小像素大小
maximumScale: 20000, // 模型的最大比例尺大小
incrementallyLoadTextures: true, // 加载模型后的纹理是否可以继续流入
clampAnimations: true, // 指定 glTF 动画是否应在不带关键帧的持续时间内保持最后一个姿势
shadows: Cesium.ShadowMode.ENABLED, // 指定模型是否 投射或接收来自光源的阴影
heightReference: Cesium.HeightReference.NONE // 表示相对于地形的位置。NONE表示绝对位置
})
viewer.scene.primitives.add(model)
}
addGLTF()
(3)添加有颜色的GLTF数据代码:
color:模型颜色。
colorBlendMode:颜色混合模式。HIGHLIGHT、MIX、REPLACE
colorBlendAmount:控制颜色混入的程度。
silhouetteColor:线框颜色。
silhouetteSize:模型边框大小。
// 添加有颜色的GLTF数据代码
const position = Cesium.Cartesian3.fromDegrees(
120, 45
)
const heading = Cesium.Math.toRadians(0)
const pitch = 0
const roll = 0
const hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll)
const orientation = Cesium.Transforms.headingPitchRollQuaternion(
position,
hpr
)
// 第一种方式:通过enitity方式
const entity = viewer.entities.add({
name: "ferrari.glb",
position: position,
orientation: orientation,
model: {
uri: "ferrari.glb",
minimumPixelSize: 128,
maximumScale: 20000,
scale: 1, // 缩放比例
incrementallyLoadTextures: true, // 加载模型后的纹理是否可以继续流入
runAnimations: true, // 指定是否应运行 glTF 动画
clampAnimations: true, // 指定 glTF 动画是否应在不带关键帧的持续时间内保持最后一个姿势
shadows: Cesium.ShadowMode.ENABLED, // 指定模型是否 投射或接收来自光源的阴影
heightReference: Cesium.HeightReference.NONE, // 表示相对于地形的位置。NONE表示绝对位置
color: Cesium.Color.RED, // 与模型的渲染颜色混合的颜色
colorBlendMode: Cesium.ColorBlendMode.MIX, // 颜色混合模式,HIGHLIGHT、MIX、REPLACE
colorBlendAmount: 0.3, // colorBlendMode是MIX时有效,控制颜色混入的程度
silhouetteColor: Cesium.Color.WHITE.withAlpha(0.5), // 白色线框,模型边框的颜色
silhouetteSize: 5 // 模型边框大小
}
})
viewer.trackedEntity = entity
8,Cesium添加Primitive:
(1)Entity和Primitive区别:
(2)Cesium添加Primitive并做定位效果:
Primitive不是Enitity,不能通过viewer.trackedEntity = entity定位到entity上,只能使用viewer.camera.flyTo(primitive)或viewer.zoomTo(primitive)的方式制作定位效果。
// 第二种方式:通过primitive方式
// 加载调试primitive和地形的工具
viewer.extend(Cesium.viewerCesiumInspectorMixin)
const origin = Cesium.Cartesian3.fromDegrees(120, 46)
const modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(origin)
const model = Cesium.Model.fromGltfAsync({
url: 'ferrari.gltf',
modelMatrix, // primitive只能通过模型矩阵方式加载位置
scale: 1, // 缩放比例
minimumPixelSize: 128, // 最小像素大小
maximumScale: 20000, // 模型的最大比例尺大小
incrementallyLoadTextures: true, // 加载模型后的纹理是否可以继续流入
clampAnimations: true, // 指定 glTF 动画是否应在不带关键帧的持续时间内保持最后一个姿势
shadows: Cesium.ShadowMode.ENABLED, // 指定模型是否 投射或接收来自光源的阴影
heightReference: Cesium.HeightReference.NONE // 表示相对于地形的位置。NONE表示绝对位置
})
model.then(res => {
viewer.scene.primitives.add(res)
// 定位到primitive
viewer.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees(120, 46, 100),
orientation: {//设置相机的Heading,Pitch,Roll,参照上图
heading: Cesium.Math.toRadians(90.0),
pitch: Cesium.Math.toRadians(-90),
roll: 0.0
},
duration: 3
})
})
(3)Cesium开启深度测试和不开启深度测试的效果:
首先,假设Cesium是添加了地形图层,因为这样才能看出添加3D Tiles在不在地下。
开启深度测试效果:
viewer.scene.globe.depthTestAgainstTerrain = true
关闭深度测试效果:
可见,关闭深度测试效果的时候,模型会陷到地面下去,造成模型显示不真实的效果。
viewer.scene.globe.depthTestAgainstTerrain = false
9,Cesium小工具:
(1)显示帧速度:
// 显示帧速度
viewer.scene.debugShowFramesPerSecond = true
(2)开启深度测试,控制视角不转到地下:
让地形后面的东西消失。为true实现高程遮挡(在没有地形时候也会有高程遮挡效果),为false则绘制与添加的图元均在地球顶部不会出现遮挡问题,按实际应用情况设置
viewer.scene.globe.depthTestAgainstTerrain = true
(3)开启阴影并添加光照:
viewer.shadows = true
viewer.scene.light = new Cesium.DirectionLight({
direction: window.Cesium.Cartesian3.fromElements(-0.2, -0.5, -0.8),
intensity: 1
})
(4)关闭光照:
viewer.scene.globe.enableLighting = false // 开启光照
(5)开启Primitive辅助工具:
viewer.extend(Cesium.viewerCesiumInspectorMixin)
(6)开启Cesium动画效果:
viewer.shouldAnimate = true
(7)显示星空、地球、太阳、月亮和背景颜色:
viewer.scene.skyBox.show = true; //是否显示星空
viewer.scene.sun.show = true; //是否显示太阳
viewer.scene.moon.show = true; //是否显示月亮
viewer.scene.globe.show = true; //是否显示地球
viewer.scene.backgroundColor = Cesium.Color.BLUE;//地球背景颜色
四、Cesium开发进阶:
Entity配置Graphic和Material,Primitive配置Geometry和Apparence。
1,Cesium开启雾和大气效果:
使用到的接口有全部是viewer.scene下的
Fog、Globe、skyAtmosphere、highDynamicRange
viewer.scene.globe.enableLighting = true // 开启光照
// 雾
viewer.scene.fog.enabled = true // 开启雾效果
viewer.scene.fog.minimumBrightness = 0.1 // 雾效果最小亮度
viewer.scene.fog.density = 0.0003 // 浓度
// 地表大气效果
viewer.scene.globe.showGroundAtmosphere = true // 开启地表大气效果
viewer.scene.globe.atmosphereLightIntensity = 10 // 设置地表大气亮度
// 天空大气效果
viewer.scene.skyAtmosphere.show = true
viewer.scene.skyAtmosphere.atmosphereLightIntensity = 50 // 天空大气效果亮度
// HDR效果
viewer.scene.highDynamicRange = true
2,Cesium卷帘分析:
思路:首先在scene中添加两个图层,设置其中一个图层或两个图层的分割方向,然后设置scene的分割距离。下面是核心代码:
// 添加图层方向
this.earthAtNightClip.splitDirection = Cesium.SplitDirection.LEFT
// 添加图层分割位置
this.scene.splitPosition = 0.5
// 添加卷帘分析
function addRollerShutterClip(RollerShutterClipChecked) {
const layers = this.imageryLayers
let moveAction = false
const move = (movement) => {
if (!moveAction) return
const relativeOffset = movement.endPosition.x
const splitPosition = (this.slider.offsetLeft + relativeOffset) / this.slider.parentElement.offsetWidth
this.slider.style.left = `${100.0 * splitPosition}%`
// 改变图层分割位置
this.scene.splitPosition = splitPosition
}
if (this.earthAtNightClip && this.slider && RollerShutterClipChecked) {
layers.remove(this.earthAtNightClip)
this.earthAtNightClip = null
document.getElementsByClassName('cesium-main')[0].removeChild(this.slider)
this.slider = null
} else {
this.earthAtNightClip = layers.addImageryProvider(new Cesium.UrlTemplateImageryProvider({
url: 'http://t1.tianditu.com/img_w/wmts?layer=img&tilematrixset=w&Service=WMTS&Request=GetTile&Version=1.0.0&TileMatrix={z}&TileCol={x}&TileRow={y}&tk=590447cdbdf97775b57588a69ebb903d'
}))
// 添加图层方向
this.earthAtNightClip.splitDirection = Cesium.SplitDirection.LEFT
// 添加图层分割位置
this.scene.splitPosition = 0.5
// 添加滑动控件slider
this.slider = document.createElement('div')
this.slider.style.width = 10 + 'px'
this.slider.style.height = 50 + 'px'
this.slider.style.position = 'absolute'
this.slider.style.top = '50%'
this.slider.style.left = '50%'
this.slider.style.backgroundColor = 'brown'
this.slider.style.cursor = 'pointer'
document.getElementsByClassName('cesium-main')[0].appendChild(this.slider)
const handler = new Cesium.ScreenSpaceEventHandler(this.slider)
handler.setInputAction(() => {
moveAction = true
}, Cesium.ScreenSpaceEventType.LEFT_DOWN)
handler.setInputAction(move, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
handler.setInputAction(() => {
moveAction = false
}, Cesium.ScreenSpaceEventType.LEFT_UP)
}
}
3,Cesium的四种pick的区别:
viewer.scene.pick(windowPosition):适用于3D Tiles、entity、primitive的选取。
viewer.scene.globe.pick(ray, viewer.scene):适用于拾取有地形高度的点的坐标,需要开启深度检测。
viewer.scene.camera.pickEllipsoid(movement.position, viewer.scene.globe.ellipsoid):适用于拾取没有地形高度的点的坐标。
viewer.scene.pickPosition(movement.position):适用于获取地球和各个实体点的坐标,需要开启深度检测。
cesium中的四种拾取pick - 一梦、 - 博客园 (cnblogs.com)
Cesium的拾取问题总结 - 知乎 (zhihu.com)
4,CZML制作动画:
(1)CZML制作动态点的动画:
注意:如果想要制作CZML动画,需要打开Cesium动画效果,viewer.shouldAnimate = true
// 添加一个czml动态点
const addDynamicPoint = (viewer) => {
const czml = [
{
id: 'document',
name: 'CZML Point',
version: '1.0',
clock: {
interval: '2012-03-15T10:00:00Z/2012-03-15T10:05:00Z',
currentTime: '2012-03-15T10:00:00Z',
// multiplier: 10
}
},
{
id: 'point', // 定义一个packet
position: {
epoch: '2012-03-15T10:00:00Z', // 定义初始时间
cartographicDegrees: [
// 时间,经度,纬度,高度
0, 100, 25, 150000,
100, 105, 30, 150000,
200, 110, 35, 150000,
300, 115, 40, 150000
], // 定义插值时间
interpolationAlgorithm: "LAGRANGE", // 拉格朗日插值
interpolationDegree: 5 // 插值多项式次数
},
point: {
color: {
rgba: [255, 255, 255, 128]
},
outlineColor: {
rgba: [255, 0, 0, 128]
},
outlineWidth: 3,
pixelSize: 15
}
}
]
Cesium.CzmlDataSource.load(czml).then(res => {
console.log(res)
viewer.dataSources.add(res)
// viewer.zoomTo(res)
console.log(Cesium.JulianDate.toDate(viewer.clock.tick())) // 输出当前时间
})
}
(2)CZML添加动态自定义属性:
czml可以使用两种方式制作自定义属性,一种是sample插值方式,另一种是interval方式。以下是它们的区别:
// CZML添加动态自定义属性
const addDynamicPoint = (viewer) => {
const czml = [
{
id: 'document',
name: 'CZML Point',
version: '1.0',
clock: {
interval: '2012-03-15T10:00:00Z/2012-03-15T10:05:00Z',
currentTime: '2012-03-15T10:00:00Z',
// multiplier: 10
}
},
{
id: 'point', // 定义一个packet
position: {
epoch: '2012-03-15T10:00:00Z', // 定义初始时间
cartographicDegrees: [
// 时间,经度,纬度,高度
0, 100, 25, 150000,
100, 105, 30, 150000,
200, 110, 35, 150000,
300, 115, 40, 150000
], // 定义插值时间
interpolationAlgorithm: "LAGRANGE", // 拉格朗日插值
interpolationDegree: 5 // 插值多项式次数
},
point: {
color: {
rgba: [255, 255, 255, 128]
},
outlineColor: {
rgba: [255, 0, 0, 128]
},
outlineWidth: 3,
pixelSize: 15
},
properties:{
// sample插值方式
height: {
number: [
'2012-03-15T10:00:00Z', 10,
'2012-03-15T10:05:00Z', 50
]
},
// interval分段多项式方式
testDGB: [
{
interval: '2012-03-15T10:00:00Z/2012-03-15T10:02:00Z',
rgba: [255, 255, 255, 255]
},
{
interval: '2012-03-15T10:02:00Z/2012-03-15T10:05:00Z',
rgba: [255, 255, 255, 254]
}
]
}
}
]
// 修改当前时间
// viewer.clock.currentTime = Cesium.JulianDate.fromIso8601('2012-03-15T10:00:00Z')
Cesium.CzmlDataSource.load(czml).then(res => {
console.log(res)
viewer.dataSources.add(res)
// viewer.zoomTo(res)
console.log(Cesium.JulianDate.toDate(viewer.clock.tick())) // 输出当前时间
let properties = res.entities.getById('point').properties
console.log(properties)
console.log(properties.height)
// 循环打印自定义属性
setInterval(() => { console.log(res.entities.getById('point').properties.height.getValue(viewer.clock.tick())) console.log(res.entities.getById('point').properties.testDGB.getValue(viewer.clock.tick()))
}, 1000)
})
}