Cesium视角插值跟踪

需求: 已知运动实体的位置信息,不同时刻相机视角更新

规划相机不同时间的视角

js 复制代码
const geoView = {
    time: [0, 30, 158.915, 168.195, 342.995, 352.995, 600, 620, 2400, 2450, 999999999],
    heading: [86.74122015872331, 6.220334273461615, 6.220334273461615, 6.220334273461615, 6.220334273461615, 6.220334273461615, 6.220334273461615, 193.1884462729906, 193.1884462729906, 194.86485717230025, 194.86485717230025],
    pitch: [1.6260532613189567, -17.780826762364974, -17.780826762364974, -17.780826762364974, -17.780826762364974, -17.780826762364974, -17.780826762364974, -17.57337362151895, -17.57337362151895, -23.795953470748834, -23.795953470748834],
    up: [60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    range: [300, 200, 200, 150, 150, 100, 100, 100, 100, 100, 100]
}
变量 含义
time 时间
heading 偏航
pitch 俯仰
up 向上偏移量
range 距离目标点的距离

相机视角的插值处理

js 复制代码
for(let i = 0; i < geoView.time.length; i++){
    const time = Cesium.JulianDate.addSeconds(this.TakeoffZero, geoView.time[i], new Cesium.JulianDate())
    this.headingProperty.addSample(time, Cesium.Math.toRadians(geoView.heading[i]))
    this.pitchProperty.addSample(time, Cesium.Math.toRadians(geoView.pitch[i]))
    this.upProperty.addSample(time, geoView.up[i])
    this.rangeProperty.addSample(time, geoView.range[i])
    this.headingPropertyBack.addSample(time, Cesium.Math.toRadians(geoView.heading[i]))
    this.pitchPropertyBack.addSample(time, Cesium.Math.toRadians(geoView.pitch[i]))
    this.rangePropertyBack.addSample(time, geoView.range[i])
}

需求要求可以中途四周转向缩放,所以将偏航、俯仰、距离备份

相机按时间跟踪

有了前面两个条件,就可以开始跟踪了,注意!!! 这里监听使用postRender场景渲染后再设置相机视角,否则监控的运动对象会跟不上

js 复制代码
this.viewerListen = (scene, time) => {
    if(this.headingProperty.getValue(time) && this.pitchProperty.getValue(time) && this.rangeProperty.getValue(time)){
        const heading = this.headingProperty.getValue(time)
        const pitch = this.pitchProperty.getValue(time)
        const range = this.rangeProperty.getValue(time)
        const up = this.upProperty.getValue(time)
        const position = this.position.getValue(time)
        const ellipsoid = this.viewer.scene.globe.ellipsoid
        const cartographic = ellipsoid.cartesianToCartographic(position)
        const lon = Cesium.Math.toDegrees(cartographic.longitude)
        const lat = Cesium.Math.toDegrees(cartographic.latitude)
        const height = cartographic.height
        this.viewer.camera.lookAt(Cesium.Cartesian3.fromDegrees(lon,lat,height+up), new Cesium.HeadingPitchRange(heading, pitch, range))
    }
}
this.viewer.scene.postRender.addEventListener(this.viewerListen)

相机视角改变与复原

相机跟踪过程中更改相机,并在几秒后恢复。Cesium默认控制视角按住鼠标左键可以自由进行视角旋转,所以按下鼠标左键移除监听,抬起鼠标左键记录当前的heading和pitch,并添加指定时间后原本的视角,最后启动监听即可.

js 复制代码
this.handler.setInputAction((e) => {
    this.viewer.scene.postRender.removeEventListener(this.viewerListen)
    this.viewerListen = null
},Cesium.ScreenSpaceEventType.LEFT_DOWN)
js 复制代码
this.handler.setInputAction((e) => {
    const time = Cesium.JulianDate.addSeconds(this.viewer.clock.currentTime, 5, new Cesium.JulianDate())
    const timeInterval = new Cesium.TimeInterval({
        start: this.viewer.clock.currentTime,
        stop: time,
        isStartIncluded: false
    })
    const h0 = this.viewer.camera.heading
    const p0 = this.viewer.camera.pitch
    const h1 = this.headingPropertyBack.getValue(time)
    const p1 = this.pitchPropertyBack.getValue(time)
    this.headingProperty.removeSamples(timeInterval)
    this.pitchProperty.removeSamples(timeInterval)
    this.headingProperty.addSample(this.viewer.clock.currentTime, h0)
    this.pitchProperty.addSample(this.viewer.clock.currentTime, p0)
    this.headingProperty.addSample(time, h1)
    this.pitchProperty.addSample(time, p1)
    this.viewerListen = (scene, time) => {
        if(this.headingProperty.getValue(time) && this.pitchProperty.getValue(time) && this.rangeProperty.getValue(time)){
            const heading = this.headingProperty.getValue(time)
            const pitch = this.pitchProperty.getValue(time)
            const range = this.rangeProperty.getValue(time)
            const up = this.upProperty.getValue(time)
            const position = this.position.getValue(time)
            const ellipsoid = this.viewer.scene.globe.ellipsoid
            const cartographic = ellipsoid.cartesianToCartographic(position)
            const lon = Cesium.Math.toDegrees(cartographic.longitude)
            const lat = Cesium.Math.toDegrees(cartographic.latitude)
            const height = cartographic.height
            this.viewer.camera.lookAt(Cesium.Cartesian3.fromDegrees(lon,lat,height+up), new Cesium.HeadingPitchRange(heading, pitch, range))
        }
    }
    this.viewer.scene.postRender.addEventListener(this.viewerListen)
    this.postRenderListensArr.push(this.viewerListen)
},Cesium.ScreenSpaceEventType.LEFT_UP)

这里移除指定时间段的插值防止再未恢复时再次调整

鼠标滚动处理

鼠标滚动只需调整相机距离

js 复制代码
this.handler.setInputAction(e => {
    const time0 = Cesium.JulianDate.addSeconds(this.viewer.clock.currentTime, 5, new Cesium.JulianDate())
    const time1 = Cesium.JulianDate.addSeconds(this.viewer.clock.currentTime, 10, new Cesium.JulianDate())
    const timeInterval = new Cesium.TimeInterval({
        start: this.viewer.clock.currentTime,
        stop: time1,
        isStartIncluded: false
    })
    this.rangeProperty.removeSamples(timeInterval)
    const time = this.viewer.clock.currentTime
    const range = this.rangeProperty.getValue(time)
    this.rangeProperty.addSample(time, (range - e)>=10?(range - e):10)
    this.rangeProperty.addSample(time0, (range - e)>=10?(range - e):10)
    this.rangeProperty.addSample(time1, this.rangePropertyBack.getValue(time1))
},Cesium.ScreenSpaceEventType.WHEEL)

最小为10防止穿模型,根据实际情况调整

最后完善

当我们鼠标按下时,这时相机也是在运动过程中,因此我们还需要继续跟踪 鼠标按下和抬起完整代码如下

js 复制代码
this.handler.setInputAction((e) => {
    this.viewer.scene.postRender.removeEventListener(this.viewerListen)
    this.viewerListen = null
    this.cameraPositionListen = (scene, time) => {
        const h0 = this.viewer.camera.heading
        const p0 = this.viewer.camera.pitch
        const position = entity.position.getValue(time)
        const ellipsoid = this.viewer.scene.globe.ellipsoid
        const cartographic = ellipsoid.cartesianToCartographic(position)
        const lon = Cesium.Math.toDegrees(cartographic.longitude)
        const lat = Cesium.Math.toDegrees(cartographic.latitude)
        const height = cartographic.height
        this.viewer.camera.lookAt(Cesium.Cartesian3.fromDegrees(lon,lat,height+up), new Cesium.HeadingPitchRange(h0, p0, range))
    }
    this.viewer.scene.postRender.addEventListener(this.cameraPositionListen)
},Cesium.ScreenSpaceEventType.LEFT_DOWN)
js 复制代码
this.handler.setInputAction((e) => {
    this.viewer.scene.postRender.removeEventListener(this.cameraPositionListen)
    this.cameraPositionListen = null
    const time = Cesium.JulianDate.addSeconds(this.viewer.clock.currentTime, 5, new Cesium.JulianDate())
    const timeInterval = new Cesium.TimeInterval({
        start: this.viewer.clock.currentTime,
        stop: time,
        isStartIncluded: false
    })
    const h0 = this.viewer.camera.heading
    const p0 = this.viewer.camera.pitch
    const h1 = this.headingPropertyBack.getValue(time)
    const p1 = this.pitchPropertyBack.getValue(time)
    this.headingProperty.removeSamples(timeInterval)
    this.pitchProperty.removeSamples(timeInterval)
    this.headingProperty.addSample(this.viewer.clock.currentTime, h0)
    this.pitchProperty.addSample(this.viewer.clock.currentTime, p0)
    this.headingProperty.addSample(time, h1)
    this.pitchProperty.addSample(time, p1)
    this.viewerListen = (scene, time) => {
        if(this.headingProperty.getValue(time) && this.pitchProperty.getValue(time) && this.rangeProperty.getValue(time)){
            const heading = this.headingProperty.getValue(time)
            const pitch = this.pitchProperty.getValue(time)
            const range = this.rangeProperty.getValue(time)
            const up = this.upProperty.getValue(time)
            const position = this.position.getValue(time)
            const ellipsoid = this.viewer.scene.globe.ellipsoid
            const cartographic = ellipsoid.cartesianToCartographic(position)
            const lon = Cesium.Math.toDegrees(cartographic.longitude)
            const lat = Cesium.Math.toDegrees(cartographic.latitude)
            const height = cartographic.height
            this.viewer.camera.lookAt(Cesium.Cartesian3.fromDegrees(lon,lat,height+up), new Cesium.HeadingPitchRange(heading, pitch, range))
        }
    }
    this.viewer.scene.postRender.addEventListener(this.viewerListen)
    this.postRenderListensArr.push(this.viewerListen)
},Cesium.ScreenSpaceEventType.LEFT_UP)
相关推荐
青年夏日科技工作者14 分钟前
虚幻浏览器插件 UE与JS通信
前端·javascript·html
雷神乐乐1 小时前
创建前端项目的方法
前端·javascript·vue.js
prince_zxill1 小时前
JavaScript面向对象编程:Prototype与Class的对比详解
前端·javascript·ecmascript·原型模式
D.eL2 小时前
Vue 2 项目中 Mock.js 的完整集成与使用教程
前端·javascript·vue.js
brzhang2 小时前
墙裂推荐一个在 Apple Silicon 上创建和管理虚拟机的轻量级开源工具:lume
前端·后端
Along丶WG3 小时前
解决国内服务器 npm install 卡住的问题
前端·npm·node.js
prince_zxill3 小时前
Node.js 和 npm 安装教程
前端·javascript·vue.js·npm·node.js
弄不死的强仔3 小时前
可被electron等调用的Qt截图-录屏工具【源码开放】
前端·javascript·qt·electron·贴图·qt5
霸王蟹4 小时前
el-table组件样式如何二次修改?
前端·javascript·vue.js·笔记·学习·前端框架
star010-5 小时前
一文学会HTML编程之视频+图文详解详析
前端·网络·网络安全·html·html5