效果:
1. 规划航线:
let positionArr = [
{x: -2497416.6511379397, y: -4398264.4706970295, z: 3876875.3974358095},
{x: -2490587.749623715, y: -4402803.334849232, z: 3876348.784933778},
{x: -2484600.807545809, y: -4397341.415887679, z: 3886715.3400331396},
{x: -2486705.891473638, y: -4392077.3543862775, z: 3891215.8287224886},
{x: -2493470.9368140115, y: -4390936.265044111, z: 3887973.753169003},
{x: -2498100.4272179785, y: -4394412.2608769955, z: 3880791.628977629},
{x: -2497416.6511379397, y: -4398264.4706970295, z: 3876875.3974358095},
];
随意选取的几个点位,画线效果:
2. 设置时间:
Cesium中的运动都是依靠时钟来进行。
//设置模拟时间
const setTime = () => {
start = Cesium.JulianDate.fromDate(new Date(2023, 11, 17, 16)); //开始时间,可以随意设置
//结束时间,因为设置了 6 个点位,到达每个点位的时间为10s,所以这里结束时间设为 60s 后
let stop = Cesium.JulianDate.addSeconds(start, 60, new Cesium.JulianDate());
//确保查看器处于所需的时间
viewer.clock.startTime = start.clone();
viewer.clock.stopTime = stop.clone();
viewer.clock.currentTime = start.clone();
viewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP; // 到达结束时间后循环执行
viewer.clock.multiplier = 1; // 时间倍数
}
//每个位置对应相应的时间点
let positionProperty = null;
const computeCirclularFlight = () => {
const property = new Cesium.SampledPositionProperty();
for (let i = 0; i < positionArr.length; i++) {
// 每隔10s进行采样,记录点的位置
let time = Cesium.JulianDate.addSeconds(start, i * 10, new Cesium.JulianDate());
property.addSample(time, positionArr[i]);
}
positionProperty = property;
}
3. 加载glb模型:
//加载模型
const addModal = () => {
modelEntity = viewer.entities.add({
name: "飞机模型",
position: positionProperty,
// 根据位置移动自动计算方向
orientation: new Cesium.VelocityOrientationProperty(positionProperty),
model: {
uri: 'modals/fly.glb',
scale: 5,
minimumPixelSize: 128, // 最小的模型像素
maximumScale: 20000, // 最大的模型像素
clampAnimations: false, // 是否保持最后一针的动画
show: true,
},
});
}
此时效果:
4. 第三人称视角跟随:
// 监听场景渲染
viewer.scene.preUpdate.addEventListener(setView);
// 第三人称视角跟随
const setView = () => {
let center = modelEntity.position.getValue(viewer.clock.currentTime);
let orientation = modelEntity.orientation.getValue(viewer.clock.currentTime);
let transform = Cesium.Transforms.eastNorthUpToFixedFrame(center);
transform = Cesium.Matrix4.fromRotationTranslation(Cesium.Matrix3.fromQuaternion(orientation), center);
viewer.camera.lookAtTransform(transform, new Cesium.Cartesian3(-100, 0, 50))
}
5. 完整代码:
<template>
<div id="cesiumViewer"></div>
</template>
<script setup>
import * as Cesium from 'cesium';
import { onBeforeUnmount, onMounted } from 'vue';
let viewer, handler, start, positionProperty, modelEntity = null;
let positionArr = [
{x: -2497416.6511379397, y: -4398264.4706970295, z: 3876875.3974358095},
{x: -2490587.749623715, y: -4402803.334849232, z: 3876348.784933778},
{x: -2484600.807545809, y: -4397341.415887679, z: 3886715.3400331396},
{x: -2486705.891473638, y: -4392077.3543862775, z: 3891215.8287224886},
{x: -2493470.9368140115, y: -4390936.265044111, z: 3887973.753169003},
{x: -2498100.4272179785, y: -4394412.2608769955, z: 3880791.628977629},
{x: -2497416.6511379397, y: -4398264.4706970295, z: 3876875.3974358095},
];
onMounted(() => {
initCesium(); //初始化
setTime(); //设置模拟时间
computeCirclularFlight(); //航线范围
addModal(); // 加载模型
// drawLine(); //画线
})
//初始化
const initCesium = () => {
Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJhMzE5Mzk4YS01MzlkLTQzZTItOTMwOS02YTJjNmMxMzA2YmYiLCJpZCI6OTUyODEsImlhdCI6MTY4NTU3OTkxMn0.fBulnkkGPuGQEo6LrRIu-EO0S5DnPwwx5sLFnPPISDI';
viewer = new Cesium.Viewer('cesiumViewer',{
infoBox: false, // 禁用沙箱,解决控制台报错
animation: false, // 是否创建动画小器件,左下角仪表
baseLayerPicker: false, // 是否显示图层选择器
fullscreenButton: false, // 是否显示全屏按钮
geocoder: false, // 是否显示geocoder小器件,右上角查询按钮
homeButton: false, // 是否显示Home按钮
infoBox: false, // 是否显示信息框
sceneModePicker: false, // 是否显示3D/2D选择器
selectionIndicator: false, // 是否显示选取指示器组件
timeline: false, // 是否显示时间轴
navigationHelpButton: false, // 是否显示右上角的帮助按钮
navigationInstructionsInitiallyVisible: false, //是否显示帮助信息控件
showRenderLoopErrors: false, // 是否显示渲染错误
// 设置背景透明
orderIndependentTranslucency: false,
shouldAnimate: true, //执行模型动画
terrainProvider: Cesium.createWorldTerrain(), //地形
});
viewer._cesiumWidget._creditContainer.style.display = 'none' // 隐藏logo
viewer.scene.globe.enableLighting = true; //启用使用场景光源照亮地球
viewer.scene.globe.depthTestAgainstTerrain = true; //启用深度测试
}
// 画线
const drawLine = () => {
viewer.entities.add({
name: "line",
show: true,
polyline: {
positions: positionArr,
width: 3,
material: new Cesium.Color.fromCssColorString('#006EFF').withAlpha(.8),
}
})
}
//设置模拟时间
const setTime = () => {
start = Cesium.JulianDate.fromDate(new Date(2023, 11, 17, 16)); //开始时间,可以随意设置
//结束时间,因为设置了 6 个点位,到达每个点位的时间为10s,所以这里结束时间设为 60s 后
let stop = Cesium.JulianDate.addSeconds(start, 60, new Cesium.JulianDate());
//确保查看器处于所需的时间
viewer.clock.startTime = start.clone();
viewer.clock.stopTime = stop.clone();
viewer.clock.currentTime = start.clone();
viewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP; // 到达结束时间后循环执行
viewer.clock.multiplier = 1; // 时间倍数
}
//每个位置对应相应的时间点
const computeCirclularFlight = () => {
const property = new Cesium.SampledPositionProperty();
for (let i = 0; i < positionArr.length; i++) {
// 每隔10s进行采样,记录点的位置
let time = Cesium.JulianDate.addSeconds(start, i * 10, new Cesium.JulianDate());
property.addSample(time, positionArr[i]);
}
positionProperty = property;
}
//加载模型
const addModal = () => {
modelEntity = viewer.entities.add({
name: "飞机模型",
position: positionProperty,
orientation: new Cesium.VelocityOrientationProperty(positionProperty), // 根据位置移动自动计算方向
model: {
uri: 'modals/fly.glb',
scale: 5,
minimumPixelSize: 128, // 最小的模型像素
maximumScale: 20000, // 最大的模型像素
clampAnimations: false, // 是否保持最后一针的动画
show: true,
},
});
// 监听场景渲染
viewer.scene.preUpdate.addEventListener(setView);
}
// 第三人称视角跟随
const setView = () => {
let center = modelEntity.position.getValue(viewer.clock.currentTime);
let orientation = modelEntity.orientation.getValue(viewer.clock.currentTime);
let transform = Cesium.Transforms.eastNorthUpToFixedFrame(center);
transform = Cesium.Matrix4.fromRotationTranslation(Cesium.Matrix3.fromQuaternion(orientation), center);
viewer.camera.lookAtTransform(transform, new Cesium.Cartesian3(-100, 0, 50))
}
onBeforeUnmount(() => {
viewer.scene.preUpdate.removeEventListener(setView);
})
</script>
<style lang="less" scoped>
</style>