Cesium倾斜相机视角观察物体

先看效果:

在cesium中,我们有时需要倾斜相机视角去观察物体,如相机俯视45观察物体。

cesium的api提供了倾斜相机视角的配置,但是直接使用cesium的api不能达到我们想要的效果。

函数如下:

js 复制代码
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单位是米),而相机的位置的以经纬度确认的,因此需要做米到经纬度的转换,这里不必赘述,请看我之前的博客。完整代码如下:

js 复制代码
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);
}
相关推荐
葡萄城技术团队5 分钟前
给 SpreadJS 单元格装上自动完成
前端
恋猫de小郭20 分钟前
Flutter 多窗口重要优化合并,多窗口性能和实用性大幅提升
android·前端·flutter
StudyAndLife22 分钟前
开源一个 API 开放平台门户前端:本地 npm run dev 就能逛接口文档
前端
广州华水科技29 分钟前
GNSS变形监测一体机在大坝安全监测中的应用与优势分析
前端
hunteritself36 分钟前
夯爆了!Qoder 狂肝 2 小时,293 个测试全绿,Credits 一分没扣
前端·人工智能·chrome·深度学习·机器学习
Hilaku1 小时前
为什么前端应该主动去学数据库?
前端·javascript·程序员
涛涛ing1 小时前
2026年,你终于可以在 `<textarea>` 里定位任意字符了
前端
三8441 小时前
TLS + Web API 安全 · 05 · JWT 与 OAuth2 攻防
前端·安全
zhongwei2282 小时前
vba将一个文件夹的内容复制到另外一个文件夹的函数,若存在则是否覆盖的参数。复制前检查源文件夹是否存在。若目标文件夹不存在,则新建
前端·vba
怕浪猫3 小时前
分享一个做视频的skill,这条白板视频,每一笔都是代码画的
前端·javascript·面试