在上一篇文章中,對 Cesium 基本初始化有了了解。
在看了官網一些例子后,做了一個飛機根據指定路線飛行的 Demo。
飛機飛行
對於飛機飛行,主要分為以下幾個步驟。
1、模型創建
使用的飛機模型是 Cesium 官網上的,可以自行下載。
創建模型基本代碼:
const entity = this.cesiumViewer.entities.add({ name: 'air', // 放置點 position: '', // 模型的朝向等 orientation: orientation, // 綁定模型文件 model: { uri: './model/Cesium_Air.glb', minimumPixelSize: 128, maximumScale: 20000 }, // 路線樣式 path: { resolution: 1, material: new Cesium.PolylineGlowMaterialProperty({ glowPower: 0.1, color: Cesium.Color.YELLOW.withAlpha(1) }), width: 3 } })
2、計算路線和時間
Cesium 里面比較好的一個點就是,可以設置時間軸,設置好對應時間的坐標信息,就可以控制飛行了。
所以這里就是計算路線和時間,並把這兩信息做一一對應。
下面是寫的一個簡單的路徑計算函數:
computeFly() { // 位置參考和方向等信息的存儲 const property = new Cesium.SampledPositionProperty() // 起點:杭州城西 const startPoint = [119.966746, 30.270928] // 終點:錢江新城 const endPoint = [120.220684, 30.26294] this.height = 500 const length = 100 const lonAvg = (endPoint[0] - startPoint[0]) / length const latAvg = (endPoint[1] - startPoint[1]) / length for (let index = 0; index < length; index++) { const time = Cesium.JulianDate.addSeconds(this.startTime, 3.6 * index, new Cesium.JulianDate()) const position = Cesium.Cartesian3.fromDegrees(startPoint[0] + lonAvg * index, startPoint[1] + latAvg * index, this.height) property.addSample(time, position) } return property }
3、調整飛行視角
經過上面兩部,基本的工作已經完成了。
把對應的路線、方向信息綁定到模型。
此時雖然可以飛了,但是飛機的視角並不是很好。
主要是設置 entity 的 viewFrom 。
這里又兩個點:
a)賦值的是迪卡爾4系坐標(這里可以區路線中的第一個位置向量)
b)這個坐標系是相對的,相對於模型的中心點
4、全部代碼
下面是全部的代碼:
<template> <div id="cesiumContainer" class="cesium-box" /> </template> <script> import 'cesium/Build/Cesium/Widgets/widgets.css' import * as Cesium from 'cesium' const googleMap = 'https://mt0.google.com/vt/lyrs=s&x={x}&y={y}&z={z}' export default { name: 'App', data() { return { cesiumViewer: null, homeView: null, startTime: null, stopTime: null, height: 4000 } }, created() { this.homeView = { destination: Cesium.Cartesian3.fromDegrees(119.966746, 30.270528, this.height + 500), orientation: { // 航向 heading: Cesium.Math.toRadians(0), // 俯仰 pitch: Cesium.Math.toRadians(-60), // 滾轉 roll: 0.0 }, // camera 初始化后回調函數 complete: this.createModel } this.startTime = Cesium.JulianDate.fromDate(new Date('2021-11-08 16:00:00')) this.stopTime = Cesium.JulianDate.addSeconds(this.startTime, 360, new Cesium.JulianDate()) }, mounted() { this.cesiumViewer = new Cesium.Viewer('cesiumContainer', { infoBox: false, imageryProvider: new Cesium.UrlTemplateImageryProvider({ url: googleMap }) }) // 設置時間軸基本信息 this.cesiumViewer.clock.startTime = this.startTime.clone() this.cesiumViewer.clock.currentTime = this.startTime.clone() this.cesiumViewer.clock.stopTime = this.stopTime.clone() this.cesiumViewer.clock.multiplier = 10 this.cesiumViewer.timeline.zoomTo(this.startTime, this.stopTime) this.cesiumViewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP // 初始化視角(飛行模式) this.cesiumViewer.camera.flyTo(this.homeView) // 重寫 homeButton 事件 this.cesiumViewer.homeButton.viewModel.command.beforeExecute.addEventListener((e) => { // 阻止事件繼續傳遞 e.cancel = true this.cesiumViewer.camera.flyTo(this.homeView) }) }, methods: { createModel() { // 計算路線 const property = this.computeFly() // 取出其中的位置向量 const orientation = new Cesium.VelocityOrientationProperty(property) // 取第一個位置向量,並改變相對位置(自己 new 一個也可以) const viewFrom = orientation.getValue(this.startTime) // 相對 entity 的視角坐標(迪卡爾4系坐標,可根據 entity 大小設置) viewFrom.z = 20 // 相對上下 viewFrom.x = -80 // 相對前后 const entity = this.cesiumViewer.entities.add({ name: 'air', availability: new Cesium.TimeIntervalCollection([ new Cesium.TimeInterval({ start: this.startTime, stop: this.stopTime }) ]), position: property, orientation: orientation, viewFrom: viewFrom, model: { uri: './model/Cesium_Air.glb', minimumPixelSize: 128, maximumScale: 20000 }, path: { resolution: 1, material: new Cesium.PolylineGlowMaterialProperty({ glowPower: 0.1, color: Cesium.Color.YELLOW.withAlpha(1) }), width: 3 } }) // 設置 viewer 一直跟隨 entity this.cesiumViewer.trackedEntity = entity }, computeFly() { const property = new Cesium.SampledPositionProperty() // 起點:杭州城西 const startPoint = [119.966746, 30.270928] // 終點:錢江新城 const endPoint = [120.220684, 30.26294] this.height = 500 const length = 100 const lonAvg = (endPoint[0] - startPoint[0]) / length const latAvg = (endPoint[1] - startPoint[1]) / length for (let index = 0; index < length; index++) { const time = Cesium.JulianDate.addSeconds(this.startTime, 3.6 * index, new Cesium.JulianDate()) const position = Cesium.Cartesian3.fromDegrees(startPoint[0] + lonAvg * index, startPoint[1] + latAvg * index, this.height) property.addSample(time, position) } return property } } } </script>
最后的效果如下: