Cesium保姆教程之镜头漫游效果
实现镜头漫游效果需要大量坐标点,将时间和坐标点联系在一起,czml格式的可以完美的将时间相对应的坐标点联系起来。 czml是基于JSON,可以准确的描述值随时间变化的属性,并且czml可以通过Cesium.czmlDataSource的形式,不断接收到从后端推送的数据,并且在cesium中动态展示,czml是一种json格式的文件,可简单理解为一个数组(实际上不能在czml中做注释,本文是为了对此格式做出解释,才进行简单的解释,实际上czml中不能包含任何注释),具体格式如下:
const czml = [
//packet1:id一定为document,否则会报错,这里定义的是整个显示场景的信息
{
id: "document",
//名称
name: "CZML Path",
version: "1.0",
//cesium时间轴的范围
clock: {
//动画间隔时间,开始时间/结束时间(ISO8601格式)
interval: "2012-08-04T10:00:00Z/2012-08-04T15:00:00Z",
//开始时间
currentTime: "2012-08-04T10:00:00Z",
运动速率
multiplier: 10,
},
},
//packet two id的value值随意(不能与其它id相同),若相同只显示最后一个entity
{
id: "path",
name: "path with GPS flight data",
//entity的描述信息
description:
"<p>Hang gliding flight log data from Daniel H. Friedman.<br>Icon created by Larisa Skosyrska from the Noun Project</p>",
//entity的有效可持续时间
availability: "2012-08-04T10:00:00Z/2012-08-04T15:00:00Z",
//添加的entity类型(path、billboard、model等实体),属性可根据entity的属性进行添加,
//最后是添加位置信息
path: {
},
billboard: {
},
position: {
epoch: "2012-08-04T10:00:00Z",
//前四行依次是时间、经度、纬度、高程,依次循环。
cartographicDegrees: [
0,
-122.93797,
39.50935,
1776,
10,
-122.93822,
39.50918,
1773,
20,
-122.9385,
39.50883,
1772,
30,
-122.93855,
39.50842,
1770,
],
},
},
]
一个czml中至少有一个packet(第一个是用来描述场景的packet),第二个packet主要用来描述场景中的entity实体以及位置信息等,czml中可添加的内容非常多,以上只是截取的一部分内容,具体内容可参照CZML Guide · AnalyticalGraphicsInc/czml-writer Wiki · GitHub。
注意:当有多个czml文件进行加载时,场景会以最后一个czml文件定义的为准。
这里只是对czml文件做一个简单的介绍,没有对其进行详细的介绍,以后有机会会对czml的格式做一个具体的解读。
czml文件的加载
czml文件是通过CzmlDataSource类进行加载。
const dataSource = await viewer.dataSources.add(
Cesium.CzmlDataSource.load(czml)
);
//通过czml文件中的第一个packet中的id属性进行跟踪
viewer.trackedEntity = dataSource.entities.getById("path");
实现过程及原理
飞行漫游,即让camera飞行,可通过flyTo()、setView(),并通过插值的方法不断调用setView(),但这样会造成试图卡顿,并且计算比较麻烦,所有比较好的方式就是借助entity,通过跟踪运动中的entity实现camera的飞行。
设置路径
利用官网案例中的[czml](CZML Path - Cesium Sandcastle)czml文件进行修改,将路径设置成自己的路径,并把一些无用的东西删掉即可。
[
{
"id": "document",
"name": "CZML Path",
"version": "1.0",
"clock": {
"interval": "2023-09-04T10:00:00Z/2023-09-04T10:03:00Z",
"currentTime": "2020-09-04T10:00:00Z",
"multiplier": 10
}
},
{
"id": "path",
"name": "path with GPS flight data",
"path": {
"width": 0,
"leadTime": 10,
"trailTime": 1000,
"resolution": 5
},
"position": {
"epoch": "2023-09-04T10:00:00Z",
"cartographicDegrees": [
0, 120.184679, 30.250211, 176,
10, 120.184507, 30.252099, 173,
20, 120.185151, 30.253816, 172,
30, 120.185795, 30.254631, 170,
40, 120.187125, 30.255704, 170,
50, 120.189099, 30.255704, 167,
60, 120.19176, 30.255103, 171,
70, 120.194249, 30.254331, 165,
80, 120.195236, 30.252442, 170,
90, 120.195365, 30.250211, 154,
100, 120.19455, 30.247808, 132,
110, 120.192575, 30.24579, 127,
120, 120.189614, 30.244761, 117,
130, 120.187297, 30.244803, 113,
140, 120.185795, 30.24549, 103,
150, 120.183864, 30.247035, 103,
160, 120.183907, 30.248795, 107,
170, 120.183679, 30.249211, 176,
180, 120.184679, 30.250211, 176
]
}
}
]
飞行漫游
const dataSource = await viewer.dataSources.add(
Cesium.CzmlDataSource.load(czml)
);
entitites = dataSource.entities.getById("path");
//采用插值,保证在拐弯处丝滑(本处是采用官方的插值算法,并不是很精确,可自行研究)
entitis.position.setInterpolationOptions({
interpolationDegree: 5,
interpolationAlgorithm: Cesium.LagrangePolynomialApproximation
})
//镜头跟踪
viewer.trackedEntity = entities
以上代码写完之后,我们看一看效果
从上图中的效果可得知,仅有白线的动态绘制效果。并没有出现镜头跟踪的效果,这是因为我们没有设置entities类,viewer.trackedEntity是跟踪entity所以才有镜头跟踪的效果,本文的czml中是没有entity的,所以是无法实现这种镜头漫游的效果,如果czml中有entity类的话,viewer.trackedEntity是可以实现镜头漫游效果,那该如何实现呢?我们实现跟踪坐标的变化,设置镜头参数,调整视角,进而实现镜头漫游的效果。
调整视角
接下来就是调整视角了,可通过viewer.scene.preUpdate.addEventListener(function () {})进行监听视角的变化,在此函数中通过调用viewer.camera.lookAt()方法改变视角。
这里是对camera每时每刻对准每一点
const target = new Cesium.Cartesian3.fromDegrees(120.189, 30.254, 300)
function setRoamView() {
if (entitites) {
const center = entitites.position.getValue(viewer.clock.currentTime)
if (center) {
const vector = new Cesium.Cartesian3(target.x - center.x, target.y - center.y, 300)
viewer.camera.lookAt(center, vector)
}
}
}
viewer.scene.preUpdate.addEventListener(() => {setRoamView})
现在再让我们看看效果,现在出现镜头漫游的效果,可以在不添加实体类的基础上出现镜头漫游的效果。
漫游效果
前端调用
<template>
<div>
<div id="cesiumContainer"></div>
</div>
</template>
<script setup>
import * as Cesium from "cesium"
import "cesium/Source/Widgets/widgets.css"
import initCesium from "@/cesiumUtils/initCesium"
import czml from "@/cesiumUtils/czml";
import { onMounted} from "vue";
let viewer = null;
let entity = null
//生命周期钩子
onMounted(async () => {
viewer = await initCesium("cesiumContainer");
viewer.dataSources.add(Cesium.CzmlDataSource.load(czml)).then(ds => {
entity = ds.entities.getById('path')
entity.position.setInterpolationOptions({
interpolationDegree: 5,
interpolationAlgorithm: Cesium.LagrangePolynomialApproximation
})
viewer.trackedEntity = entity
const target = new Cesium.Cartesian3.fromDegrees(-122.93797, 39.50935, 1776)
viewer.scene.preUpdate.addEventListener(() => {
setRoamView(entity, target, viewer)
})
})
})
const setRoamView = (entity, target, viewer) => {
if (entity) {
const center = entity.position.getValue(viewer.clock.currentTime)
console.log("center", center);
if (center) {
const vector = new Cesium.Cartesian3(target.x - center.x, target.y - center.y, 100)
viewer.camera.lookAt(center, vector)
}
}
}
</script>
<style lang="less" scoped>
#cesiumContainer {
width: 100vw;
height: 100vh;
margin: 0;
padding: 0;
overflow: hidden;
position: relative;
}
</style>
当然我们也可以停止漫游效果,需要进行两步:
1、取消camera追踪,viewer.trackedEntity = null;
2、取消事件绑定, viewer.scene.preUpdate.removeEventListener(()=> {setRoamView(entity, target, viewer)})。
如果对于本文有不明白的地方可以在评论区指出,只要有时间肯定会做出详细解释。欢迎各位同行批评指正。