Skip to content

概述

粒子系统可以与前面的运动轨迹相互结合。

javascript
<script setup>

import { onMounted } from 'vue'
import * as Cesium from 'cesium'
import smoke from './assets/smoke.png'

window.CESIUM_BASE_URL = '/Cesium'
Cesium.Ion.defaultAccessToken = ''

const GD_TOKEN = ''
const origin = '116.310003,39.991957'
const destination = '116.434446,39.90816'
const url = `https://restapi.amap.com/v5/direction/driving?key=${GD_TOKEN}&origin=${origin}&destination=${destination}&show_fields=polyline`
const drivingData = []

onMounted(async () => {

  const viewer = new Cesium.Viewer('cesiumContainer')

  const response = await fetch(url)
  const data = await response.json()

  data.route.paths[0].steps.forEach((step) => {
    const result = step.polyline.split(';').map((item) => {
      const [lng, lat] = item.split(',')
      return {
        longitude: Number(lng),
        latitude: Number(lat),
        height: 0
      }
    })
    drivingData.push(...result)
  })

  // console.log(drivingData)

  const timeStepInSeconds = 30
  const totalSeconds = timeStepInSeconds * (drivingData.length - 1)
  const start = Cesium.JulianDate.fromIso8601("2020-03-09T23:10:00Z")
  const stop = Cesium.JulianDate.addSeconds(start, totalSeconds, new Cesium.JulianDate())
  viewer.clock.startTime = start.clone()
  viewer.clock.stopTime = stop.clone()
  viewer.clock.currentTime = start.clone()
  viewer.timeline.zoomTo(start, stop)
  viewer.clock.multiplier = 20
  viewer.clock.shouldAnimate = true    // 也可以在配置中设置shouldAnimate

  const positionProperty = new Cesium.SampledPositionProperty()

  for (let i = 0; i < drivingData.length; i++) {
    const dataPoint = drivingData[i]
    const time = Cesium.JulianDate.addSeconds(start, i * timeStepInSeconds, new Cesium.JulianDate())
    const position = Cesium.Cartesian3.fromDegrees(dataPoint.longitude, dataPoint.latitude, dataPoint.height)
    positionProperty.addSample(time, position)
  }

  const airplaneEntity = viewer.entities.add({
    availability: new Cesium.TimeIntervalCollection([new Cesium.TimeInterval({ start: start, stop: stop })]),
    position: positionProperty,
    model: {
      uri: '/models/plane2.glb',
      scale: 1,
    },
    // 自动朝向前进方向
    orientation: new Cesium.VelocityOrientationProperty(positionProperty),
    path: new Cesium.PathGraphics({ width: 3 }),
    viewFrom: new Cesium.Cartesian3(0, -2000, 2000)
  })
  viewer.trackedEntity = airplaneEntity

  const emitterModelMatrix = new Cesium.Matrix4()
  const translation = new Cesium.Cartesian3()
  const rotation = new Cesium.Quaternion()
  let hpr = new Cesium.HeadingPitchRoll()
  const trs = new Cesium.TranslationRotationScale()
  function computeEmitterModelMatrix() {
    hpr = Cesium.HeadingPitchRoll.fromDegrees(0.0, 0.0, 0.0, hpr)
    trs.translation = Cesium.Cartesian3.fromElements(-10.0, 0.0, 1.4, translation)
    trs.rotation = Cesium.Quaternion.fromHeadingPitchRoll(hpr, rotation)
    return Cesium.Matrix4.fromTranslationRotationScale(trs, emitterModelMatrix)
  }

  const particleSystem = viewer.scene.primitives.add(
    new Cesium.ParticleSystem({
      image: smoke,
      imageSize: new Cesium.Cartesian2(5.0, 5.0),
      emissionRate: 5.0,
      minimumParticleLife: 3.2,
      maximumParticleLife: 8.2,
      minimumSpeed: 1,
      maximumSpeed: 4,
      startScale: 1.0,
      endScale: 5.0,
      emitter: new Cesium.CircleEmitter(2.0),
      emitterModelMatrix: computeEmitterModelMatrix(),
      lifetime: 16.0,
    })
  )

  viewer.scene.preUpdate.addEventListener(function (scene, time) {
    particleSystem.modelMatrix = airplaneEntity.computeModelMatrix(time, new Cesium.Matrix4())
    particleSystem.emitterModelMatrix = computeEmitterModelMatrix()
  })

})

</script>

<template>
  <div id="cesiumContainer"></div>
</template>

<style scoped>
#cesiumContainer {
  position: absolute;
  inset: 0;
}
</style>
/