先看效果:
在cesium中,我们有时需要倾斜相机视角去观察物体,如相机俯视45观察物体。
cesium的api提供了倾斜相机视角的配置,但是直接使用cesium的api不能达到我们想要的效果。
函数如下:
function flyToBox() {
let longitude = -114;
let latitude = 40;
let pitch = -45;
let height = 4000;
// 创建一个蓝色盒子
const blueBox = viewer.entities.add({
name: "Blue box",
position: Cesium.Cartesian3.fromDegrees(longitude, latitude, height / 2),
box: {
dimensions: new Cesium.Cartesian3(1000.0, 1000.0, 1000.0),
material: Cesium.Color.BLUE,
},
});
let center = Cesium.Cartesian3.fromDegrees(longitude, latitude, height);
// 相机飞行到指定位置
viewer.camera.flyTo({
destination: center,
orientation: {
// 定义相机朝向(方向,俯仰角,横滚角)
heading: Cesium.Math.toRadians(360),
pitch: Cesium.Math.toRadians(pitch),
roll: Cesium.Math.toRadians(0),
},
duration: 2,
});
}
效果如下
可以看到物体已经不在视口范围内了。
why?
原因很简单,我们看到了视野都是相机的视野。
cesium相机默认的角度(picth=-90)如下:
当配置了orientation
,将相机偏移了-45度,因此物体超出了相机的视野,我们也就看不到物体了。
想要看到物体也很简单,将相机平移x距离即可。回忆一下高中的知识,在直角三角形中,已知了一个角α和边h,可以求x。即:
x = tanα * h
接下来又是另一个难题。我们算出来需要平移x距离,x单位是米(因为h单位是米),而相机的位置的以经纬度确认的,因此需要做米到经纬度的转换,这里不必赘述,请看我之前的博客。完整代码如下:
function flyToBox() {
let longitude = -114;
let latitude = 40;
let pitch = -45;
let height = 4000;
// 创建一个蓝色盒子
const blueBox = viewer.entities.add({
name: "Blue box",
position: Cesium.Cartesian3.fromDegrees(longitude, latitude, 0),
box: {
dimensions: new Cesium.Cartesian3(1000.0, 1000.0, 1000.0),
material: Cesium.Color.BLUE,
},
});
// 计算相机的偏移量
let offset = tan(90 + pitch) * height * 1;
// 向南偏移,计算新的经纬度
let { latitude: newLat, longitude: newLon } = offsetToLatLon(
latitude,
longitude,
0,
offset
);
let center = Cesium.Cartesian3.fromDegrees(newLon, newLat, height);
// let center = Cesium.Cartesian3.fromDegrees(longitude, latitude, height);
// 相机飞行到指定位置
viewer.camera.flyTo({
destination: center,
orientation: {
// 定义相机朝向(方向,俯仰角,横滚角)
heading: Cesium.Math.toRadians(360),
pitch: Cesium.Math.toRadians(pitch),
roll: Cesium.Math.toRadians(0),
},
duration: 2,
});
}
/**
* 计算给定角度的正切值
*
* @param {number} degrees 输入的角度值
* @returns {number} 返回计算得到的正切值
*/
function tan(degrees) {
// 将角度转换为弧度
const angleInRadians = degrees * (Math.PI / 180);
return Math.tan(angleInRadians);
}