第二章:Cesium 视图控制与相机操作

发布于:2025-09-02 ⋅ 阅读:(16) ⋅ 点赞:(0)

效果图

上一章我们成功搭建了 Cesium 开发环境并显示了 3D 地球。本章将学习如何控制地球视图,包括相机操作、视角切换和交互控制等核心功能。

1 相机(Camera)基础

Cesium 中的相机相当于用户的 "眼睛",控制着我们看到的地球区域和角度。相机有几个关键参数:

  • 位置(position):相机在 3D 空间中的坐标
  • 方向(orientation):包含 heading(方位角)、pitch(俯仰角)、roll(翻滚角)
  • 视锥体(frustum):控制视野范围和透视效果

2 常用相机操作方法

下面通过示例展示常用的相机控制方法:

<template>
  <div class="cesium-container">
    <div id="cesiumContainer" class="cesium-viewer"></div>
    <!-- 相机控制按钮 -->
    <div class="control-panel">
      <button @click="flyToBeijing">飞往北京</button>
      <button @click="zoomIn">放大</button>
      <button @click="zoomOut">缩小</button>
      <button @click="rotateLeft">向左旋转</button>
      <button @click="toggleMode">切换视角模式</button>
      <button @click="resetView">重置视图</button>
    </div>
  </div>
</template>

<script>
// import Cesium from 'cesium/Cesium';
// import 'cesium/Widgets/widgets.css';

export default {
  name: 'CesiumCamera',
  data() {
    return {
      viewer: null,
      is3DMode: true, // 当前视角模式
    };
  },
  mounted() {
    // 设置 Token
    Cesium.Ion.defaultAccessToken =
      'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJjMGFkODljYy03NDI5LTQ0NDgtYmNmMC1lMjFlMTQ3NmExNjkiLCJpZCI6MzM2MDM0LCJpYXQiOjE3NTYzNDU1NTd9.AkhZoeBAIIPRhFnFDkTRpqERvJYxVpvAG67FJPlaOFI';

    // 初始化视图
    this.viewer = new Cesium.Viewer('cesiumContainer', {
      imageryProvider: new Cesium.ArcGisMapServerImageryProvider({
        url: 'https://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer',
      }),
      //   terrainProvider: Cesium.Terrain.fromWorldTerrain(),
      // 保留默认控件,便于对比
      homeButton: true,
      sceneModePicker: true,
    });

    // 初始定位到中国
    this.viewer.camera.setView({
      destination: Cesium.Cartesian3.fromDegrees(105, 35, 5000000),
    });
  },
  methods: {
    // 飞抵北京(带动画)
    flyToBeijing() {
      this.viewer.camera.flyTo({
        destination: Cesium.Cartesian3.fromDegrees(116.404, 39.915, 10000), // 经度、纬度、高度
        duration: 3, // 飞行时间(秒)
        orientation: {
          heading: Cesium.Math.toRadians(0), // 方向角(0表示向北)
          pitch: Cesium.Math.toRadians(-60), // 俯仰角(-90表示正视下方)
          roll: 0, // 翻滚角
        },
      });
    },
    // 放大
    zoomIn() {
      // 获取当前相机位置
      const currentPosition = this.viewer.camera.position;
      // 计算新位置(向地球方向移动)
      const newPosition = Cesium.Cartesian3.multiplyByScalar(
        currentPosition,
        0.5, // 距离减半(放大)
        new Cesium.Cartesian3()
      );
      // 移动相机(无动画)
      this.viewer.camera.setView({
        destination: newPosition,
      });
    },
    // 缩小
    zoomOut() {
      const currentPosition = this.viewer.camera.position;
      const newPosition = Cesium.Cartesian3.multiplyByScalar(
        currentPosition,
        2.0, // 距离加倍(缩小)
        new Cesium.Cartesian3()
      );
      this.viewer.camera.setView({
        destination: newPosition,
      });
    },
    // 向左旋转
    rotateLeft() {
      this.viewer.camera.rotate(
        Cesium.Cartesian3.UNIT_Y,
        Cesium.Math.toRadians(10)
      );
    },
    // 切换视角模式(3D/2D/哥伦布视图)
    toggleMode() {
      this.is3DMode = !this.is3DMode;
      if (this.is3DMode) {
        this.viewer.scene.mode = Cesium.SceneMode.SCENE3D;
      } else {
        this.viewer.scene.mode = Cesium.SceneMode.SCENE2D;
        // 切换到2D后调整视角
        this.viewer.camera.setView({
          destination: Cesium.Cartesian3.fromDegrees(105, 35, 5000000),
        });
      }
    },
    // 重置视图
    resetView() {
      this.viewer.camera.setView({
        destination: Cesium.Cartesian3.fromDegrees(105, 35, 5000000),
      });
      this.viewer.scene.mode = Cesium.SceneMode.SCENE3D;
      this.is3DMode = true;
    },
  },
  beforeDestroy() {
    if (this.viewer) {
      this.viewer.destroy();
    }
  },
};
</script>

<style scoped>
.cesium-container {
  width: 100vw;
  height: 100vh;
  margin: 0;
  padding: 0;
  position: relative;
}

.cesium-viewer {
  width: 100%;
  height: 100%;
}

/* 控制按钮样式 */
.control-panel {
  position: absolute;
  bottom: 20px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  gap: 10px;
  z-index: 10;
  padding: 10px;
  background: rgba(255, 255, 255, 0.8);
  border-radius: 5px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}

button {
  padding: 8px 12px;
  background: #007bff;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 14px;
}

button:hover {
  background: #0056b3;
}
</style>

Cesium 相机控制示例

3 代码解析

  1. 相机定位方法

    • flyTo():带动画的飞行定位,适合用户交互
    • setView():直接跳转定位,无动画,适合初始化
  2. 坐标转换

    • Cesium.Cartesian3.fromDegrees(longitude, latitude, height):将经纬度坐标转换为 Cesium 内部使用的笛卡尔坐标
  3. 视角模式

    • SCENE3D:3D 模式,可看到地形起伏
    • SCENE2D:2D 模式,类似传统平面地图
    • COLUMBUS_VIEW:哥伦布视图,介于 2D 和 3D 之间的透视模式
  4. 相机方向参数

    • heading:方位角,0 表示向北,增加为顺时针旋转
    • pitch:俯仰角,0 表示水平,负值表示向下看,正值表示向上看
    • roll:翻滚角,0 表示水平,正值表示向右翻滚

4 交互控制

Cesium 提供了默认的鼠标交互:

  • 左键拖动:旋转地球
  • 右键拖动:缩放
  • 中键拖动:平移
  • 滚轮:缩放
  • 双击:放大到点击位置

如果需要自定义交互,可以通过 ScreenSpaceEventHandler 实现:

// 示例:禁用默认的左键拖动旋转
this.viewer.scene.screenSpaceEventHandler.removeInputAction(
  Cesium.ScreenSpaceEventType.LEFT_DRAG
);

// 添加自定义左键点击事件
this.viewer.scene.screenSpaceEventHandler.setInputAction(
  (event) => {
    // 获取点击位置的经纬度
    const position = this.viewer.scene.pickPosition(event.position);
    if (position) {
      const cartographic = Cesium.Cartographic.fromCartesian(position);
      const longitude = Cesium.Math.toDegrees(cartographic.longitude);
      const latitude = Cesium.Math.toDegrees(cartographic.latitude);
      console.log(`点击位置: 经度 ${longitude.toFixed(2)}, 纬度 ${latitude.toFixed(2)}`);
    }
  },
  Cesium.ScreenSpaceEventType.LEFT_CLICK
);

小结

本文讲解了:

  • Cesium 相机的基本概念和参数
  • 常用的相机控制方法(定位、缩放、旋转)
  • 视角模式切换(3D/2D / 哥伦布视图)
  • 基础交互控制和自定义事件

网站公告

今日签到

点亮在社区的每一天
去签到