cesium 相机跟随

一场大的台风,路径通常很长,可能从靠近赤道的太平洋一直往北吹到东三省。跨度这么大,在三维GIS中,往往不容易看全。如果能够实现相机随动效果,即相机跟随台风步进、移动,就生动许多了。
cesium 相机跟随_第1张图片
cesium 相机跟随_第2张图片

感觉在cesium中,坐标和视角、相机、view是一个难点,我到现在都搞不清楚。方向(orientation)可以总结一下:

XYZ轴,由负到正,分别对应西东、南北、下上。(cesium是右手)
cesium 相机跟随_第3张图片

heading:视场角,观察者(相机?)与地球围绕Y轴转,可以想象为相机向左,地球就向右;反之。

pitch:俯仰角,观察者与地球围绕X轴转;观察者低头,看见地球南极,抬头,看见地球北极。

roll:旋转,观察者与地球围绕Z轴转;可以想象为地球就是一个平面的饼,在围绕圆心在转。

cesium 相机跟随_第4张图片

cesium 相机跟随_第5张图片

言归正传。一场台风在绘制过程中,每个步骤都有对应的一个坐标值。只要观察者能够跟随这个脚步,从空中俯视,就能观察到每一个步骤的细节。

问题是,如何才能跟随?

相机(camera)的话,有lookAt啦,setView啦,flyTo啦。前面2个在本场景中都用不上,相机不动,光调转角度不行。只有flyTo才会跟随。

但是,flyTo方法,既有viewer.flyTo,又有camera.flyTo。viewer.flyTo,飞向指定坐标点(也就是台风的某个步骤坐标点),该坐标点就会正正好出现在屏幕中央,最符合要求;而camera.flyTo,是相机飞到指定点,如果按照默认值,相机角度是正俯视地球,那么没有问题,指定点也会在屏幕中央;但问题是,相机往往设置了各种倾斜的角度,那么待观察的点就不会在屏幕中央,而是出现在一边,甚至根本看不见!

那我们还犹豫什么,就用viewer.flyTo就好了。不行啊,这个viewer.flyTo,如果当前有数据输出,画面在更新,它不会执行,只有等待一切平静后它才客客气气地执行。这就出现一场台风全部步骤绘制完毕以后,才执行这个viewer.flyTo,黄花菜都凉了。

所以,解决办法还是应该用camera.flyTo。飞到一个合适的坐标点,可以让被观察点(即台风步骤坐标点)出现在屏幕中央。现在的问题是,如何得到这个合适的坐标点,让相机飞过去?

可不可以根据相机的角度,和被观察点的坐标,倒推出这个坐标点,以至于相机来到这里,角度啥的不变,刚好让被观察点出现在屏幕中央?

这个不是方程式,我没有找到计算方法。但是也许可以间接计算。我是这么想的:

台风刚开始的时候,我们先viewer.flyTo台风起点,这时台风起点出现在屏幕中央;
台风前进一步,来到了一个新位置,这时,可以计算它与上一步的位移;
然后我用相机当前位置,加上这个位移,得到一个新的坐标点,这就是那个合适的坐标点
相机飞到这个该死的合适坐标点
以此类推。
cesium 相机跟随_第6张图片

代码如下:

//台风开始时,我们飞向起点p
let flyEntity = new Cesium.Entity({
     
	id : 'flyTmp',
	position : Cesium.Cartesian3.fromDegrees(p.x,p.y,0),
	point : {
     
		pixelSize : 1,
		color : Cesium.Color.WHITE.withAlpha(0.0),
	}
});
viewer.entities.add(flyEntity);

return viewer.flyTo(flyEntity, {
     
	offset : {
     //角度啥都不变
		heading : viewer.camera.heading,
		pitch : viewer.camera.pitch,
		range : HEIGHT
	}
});
//一个台风步骤
function step(){
     
	let p1 = ... //上一步骤
	let p2 = ... //当前步骤

	let cp = viewer.camera.positionCartographic;//当前相机世界坐标

	let offset = Cesium.Cartesian3.subtract(//两个台风步骤之间的位移
		Cesium.Cartesian3.fromDegrees(p1.x, p2.y,cp.height), //这个高度必不可少
		Cesium.Cartesian3.fromDegrees(p1.x, p2.y,cp.height), 								
		new Cesium.Cartesian3());
		
	let newCameraLoc = Cesium.Cartesian3.add(//新的相机坐标点
		viewer.camera.position,
		offset, 							
		new Cesium.Cartesian3());

	viewer.camera.flyTo({
     
		destination : newCameraLoc,
		duration:2,//飞行时间2秒
		orientation : {
     
			heading : viewer.camera.heading,
			pitch : viewer.camera.pitch,
			roll : 0.0
		},
		complete:function(){
     //完成后进入下一步;职责链模式
			step();
		}
	});							
}

当然啦,实际应用过程中,不会步步跟随,而是20步跟随一次,否则系统估计会卡死。

cesium中定位方法使用

你可能感兴趣的:(gis,cesium,flyTo,合适坐标点,观察坐标点)