需求: 已知运动实体的位置信息,不同时刻相机视角更新
规划相机不同时间的视角
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)