Cesium实现第一人称漫游、飞行

为了方便用户能够直观的浏览三维模型上的所有位置点位,具体的实现思路是:

1、首先将所有的位置点按照一定的路线顺序排列好;

2、接着以第一人称视角开始漫游所设定的路线图;

3、设置飞行、继续、暂停及退出漫游飞行的状态。

具体参考可见:【Cesium开发实战】飞行漫游功能的实现,可设置漫游路径,漫游高度,暂停,继续,删除路径...-优快云博客

 实现代码如下:

var airplaneEntity = null
var timeStepInSeconds = 7
const positionProperty = new Cesium.SampledPositionProperty();
//开始飞行
startFly () {
//飞行的时候,飞行按钮、继续按钮置灰不可点击
      this.start = true
      this.pause = false
      this.keepup = true
      this.stop = false
      this.showSelect = true
      // 当下个飞行前清除上次的飞行对象和路径
      if (airplaneEntity != null) {
        viewer.entities.remove(airplaneEntity)
      }
      // 获取飞行的路径线路
      const positions = []
      for (let i = 0; i < this.options.length; i++) {
        const position = {
          longitude: this.options[i].longitude,
          latitude: this.options[i].ydbWeiDu,
          height: 1000
        }
        positions.push(position)
      }
      const flightData = positions;
      //timeStepInSeconds表示在每个位置点的停留时间
      const totalSeconds = (flightData.length) * timeStepInSeconds
      // 设置起点时间
      const time = new Date('2020-03-09T23:10:00Z')
      const start = Cesium.JulianDate.fromDate(time)
      // 设置终点时间
      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()

      for (let i = 0; i < flightData.length; i++) {
        const dataPoint = flightData[i]
        // 采样时间
        const time = Cesium.JulianDate.addSeconds(start, i * timeStepInSeconds, new Cesium.JulianDate())

        // 计算当前的3D坐标
        const position = Cesium.Cartesian3.fromDegrees(dataPoint.longitude, dataPoint.latitude, dataPoint.height)

        // 添加轨迹采样点
        positionProperty.addSample(time, position)
      }
      // 创建飞机模型
      airplaneEntity = viewer.entities.add({
        availability: new Cesium.TimeIntervalCollection([
          new Cesium.TimeInterval({
            start: start,
            stop: stop
          })
        ]),
        position: positionProperty,
        model: {
          uri: '/model/glb/Cesium_Air.glb',
          scale: 0.0 //由于我们以第一人称视角,此时可设置其飞机模型的大小为0,但是必须存在这个分级机模型
        },
        // 自动计算前进方向
        orientation: new Cesium.VelocityOrientationProperty(positionProperty)
      })

      // 设置相机追踪运动物体
      viewer.trackedEntity = airplaneEntity

      // 设置时间速率
      viewer.clock.multiplier = 1

      // 设置自动播放
      viewer.clock.shouldAnimate = true
      const that = this
      viewer.clock.onTick.addEventListener(function (clock) {
        // var endTime = Cesium.JulianDate.addSeconds(startTime, duration, new Cesium.JulianDate());
        if (Cesium.JulianDate.greaterThan(clock.currentTime, stop)) {
          // 退出界面操作
          // 例如:关闭Cesium Viewer
          that.finishFly()
        }
      })
    },

// 暂停飞行,设置暂停、飞行按钮置灰;继续和结束按钮可点击
    stopFly () {
      this.pause = true
      this.start = true
      this.keepup = false
      this.stop = false
      viewer.clock.shouldAnimate = false //是否尝试延长时间
    },
    // 继续飞行;设置继续、飞行按钮置灰;暂停和结束按钮可点击
    continueFly () {
      this.keepup = true
      this.start = true
      this.pause = false
      this.stop = false
      viewer.clock.shouldAnimate = true //尝试延长时间
    },

注意:为了以第一人称视角漫游,需要将飞机模型隐藏掉,但是不能去掉。

整体代码如下

<template>
  <div class="visualization">
    <div id="cesiumContainer"></div>
    <div class="infoDiv">
      <el-select v-model="pointInfo" placeholder="请选择" size="mini" popper-class="type-popper"
        :disabled="showSelect">
        <el-option v-for="item in options" :key="item.id" :label="item.name" :value="item.id">
        </el-option>
      </el-select>
      <div
        style="margin-top: 10px;display: flex;flex-direction: column;justify-content: flex-start;align-items: flex-start;">
        <el-button icon="el-icon-video-play" type="text" @click.native-type="startFly" :disabled="start">飞行</el-button>
        <el-button icon="el-icon-video-pause" type="text" @click.native-type="stopFly" style="margin-left: 0px;"
          :disabled="pause">暂停</el-button>
        <el-button icon="el-icon-video-play" type="text" @click.native-type="continueFly" style="margin-left: 0px;"
          :disabled="keepup">继续</el-button>
        <el-button icon="el-icon-video-play" type="text" @click.native-type="finishFly" style="margin-left: 0px;"
          :disabled="stop">退出</el-button>
      </div>

    </div>
</template>

<script>
var viewer = null
var tileset = null
var terrainProvider = null
var airplaneEntity = null
var timeStepInSeconds = 7
const positionProperty = new Cesium.SampledPositionProperty()
var entities = []
export default {
  components: {
  },
  data () {
    return {
      pointInfo: '',
      options: [
	  {
	      id:1,
	      name:'公园',
	      longitude:110.4565,
	      latitude:36.89797
	  },
	  ...
	  ],      
      start: false, //飞行按钮可否点击
      pause: true, //暂停按钮可否点击
      keepup: true, //继续按钮可否点击
      stop: true, //退出飞行按钮可否点击
      showSelect: false //下拉框可否选择
    }
  },
  mounted () {
   
  },
  methods: {   
    initCesium () {
      Cesium.Ion.defaultAccessToken = '申请自己的access token'
        viewer = new Cesium.Viewer('cesiumContainer', {
          animation: false, // 是否显示动画控件
          shouldAnimate: false,//是否自动播放
          homeButton: false, // 是否显示Home按钮
          fullscreenButton: false, // 是否显示全屏按钮
          baseLayerPicker: false, // 是否显示图层选择控件
          geocoder: false, // 是否显示地名查找控件
          timeline: false, // 是否显示时间线控件
          sceneModePicker: false, // 是否显示投影方式控件
          navigationHelpButton: false, // 是否显示帮助信息控件
          navigationInstructionsInitiallyVisible: false, // 是否显示导航提示,默认为true,
          infoBox: true, // 是否显示点击要素之后显示的信息
          requestRenderMode: true, // 启用请求渲染模式
          // scene3DOnly: false, //每个几何实例将只能以3D渲染以节省GPU内存
          sceneMode: 3, // 初始场景模式 1 2D模式 2 2D循环模式 3 3D模式  Cesium.SceneMode
          creditContainer: document.createElement('div'), // 创建一个空的div来包裹版权信息,类似隐藏掉默认的版权信息
          // baseLayerPicker: false,//如果设置为false,则不会创建BaseLayerPicker小部件
          // 指定Cesium的底图图层实例,默认为ImageryProvider
          imageryProvider: new Cesium.WebMapTileServiceImageryProvider({
            url: 'http://t0.tianditu.gov.cn/img_w/wmts?tk=申请自己的key',
            layer: 'vec',
            style: 'default',
            tileMatrixSetID: 'w',
            format: 'tiles',
            maximumLevel: 18
          })
        });
        //加载具有地形高度的数字模型或图像,即抬高三维模型所在区域的地形高度
        terrainProvider = new Cesium.CesiumTerrainProvider({
          url: 'http://127.0.0.1:10004' + this.detailInfo.terrainPath,
          requestVertexNormals: true,
          requestWaterMask: true,
          tilingScheme: new Cesium.GeographicTilingScheme(),
          requestVertexNormals: true
        })
        viewer.terrainProvider = terrainProvider
        var creditElement = document.createElement('div')
        creditElement.style.position = 'absolute'
        creditElement.style.bottom = '10px'
        creditElement.style.right = '10px'
        creditElement.style.color = 'white'
        creditElement.style.fontSize = '20px'
        creditElement.innerHTML = '2024.6'
  
        // 将DOM元素添加到Viewer的容器中
        viewer.container.appendChild(creditElement)
        tileset = new Cesium.Cesium3DTileset({
          url: 'http://127.0.0.1:10004' + this.detailInfo.filePath,
          maximumMemoryUsage: 5120//控制 3D Tiles 的最大内存使用量,从而在保证数据流畅的前提下尽可能减小内存占用。
        })
        viewer.scene.primitives.add(tileset)
        viewer.zoomTo(tileset)
        // this.addYdbPoints()//绘制自定义位置点广告牌,见Cesium实现位置点的自定义弹框显示内容

    },
   
    startFly () {
      this.start = true
      this.pause = false
      this.keepup = true
      this.stop = false
      this.showSelect = true
      // 当下个飞行前清除上次的飞行对象和路径
      if (airplaneEntity != null) {
        viewer.entities.remove(airplaneEntity)
      }
      // 获取条目经纬度数据集合
      const positions = []
      for (let i = 0; i < this.options.length; i++) {
        const position = {
          longitude: this.options[i].longitude,
          latitude: this.options[i].latitude,
          height: 1000
        }
        positions.push(position)
      }
      const flightData = positions
      const totalSeconds = (flightData.length) * timeStepInSeconds
      // 设置起点时间
      const time = new Date('2020-03-09T23:10:00Z')
      const start = Cesium.JulianDate.fromDate(time)
      // 设置终点时间
      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()

      for (let i = 0; i < flightData.length; i++) {
        const dataPoint = flightData[i]
        // 采样时间
        const time = Cesium.JulianDate.addSeconds(start, i * timeStepInSeconds, new Cesium.JulianDate())

        // 计算当前的3D坐标
        const position = Cesium.Cartesian3.fromDegrees(dataPoint.longitude, dataPoint.latitude, dataPoint.height)

        // 添加轨迹采样点
        positionProperty.addSample(time, position)
      }
      // 创建飞机模型
      airplaneEntity = viewer.entities.add({
        // id: item.id,
        availability: new Cesium.TimeIntervalCollection([
          new Cesium.TimeInterval({
            start: start,
            stop: stop
          })
        ]),
        position: positionProperty,
        model: {
          uri: '/model/glb/Cesium_Air.glb',
          scale: 0.0
        },
        // 自动计算前进方向
        orientation: new Cesium.VelocityOrientationProperty(positionProperty)
      })

      // 设置相机追踪运动物体
      viewer.trackedEntity = airplaneEntity

      // 设置时间速率
      viewer.clock.multiplier = 1

      // 设置自动播放
      viewer.clock.shouldAnimate = true
      const that = this
      viewer.clock.onTick.addEventListener(function (clock) {
        // var endTime = Cesium.JulianDate.addSeconds(startTime, duration, new Cesium.JulianDate());
        if (Cesium.JulianDate.greaterThan(clock.currentTime, stop)) {
          // 退出界面操作
          // 例如:关闭Cesium Viewer
          that.finishFly()
        }
      })
    },
    // 暂停飞行
    stopFly () {
      this.pause = true
      this.start = true
      this.keepup = false
      this.stop = false
      viewer.clock.shouldAnimate = false
    },
    // 继续飞行
    continueFly () {
      this.keepup = true
      this.start = true
      this.pause = false
      this.stop = false
      viewer.clock.shouldAnimate = true
    },
  
    finishFly () {
      this.stopFly()
      this.stop = true
      this.start = false
      this.keepup = true
      this.pause = true
      this.showSelect = false
      viewer.entities.remove(airplaneEntity)
    }
  },
  beforeDestroy () {
    if (viewer) {
      // 组件销毁时,确保Cesium资源被释放
      viewer.destroy()
    }
  }
}

</script>

<style scoped>
.visualization {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: 99999;
}


.infoDiv {
  padding: 10px;
  position: absolute;
  left: 10px;
  top: 70px;
  width: 10%;
  height: 180px;
  z-index: 999999;
}

#cesiumContainer {
  position: relative;
  top: 5px;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: 99999
}
</style>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值