视角切换 · Switch View · ▶ 在线运行案例

视角切换

你将学到什么

  • Cesium 相机定位 API 全家桶:fly / zoom / setView / lookAt
  • Entity、3D Tiles、经纬度 三类目标分别如何定位
  • trackedEntity 第三人称跟随与取消
  • HeadingPitchRange 控制观察角度

效果说明

场景加载成都附近 3D Tiles 白膜glb 园区模型,dat.GUI 提供十余个按钮,逐一演示不同相机 API 的视觉效果差异。

核心概念

Cesium 相机操作分三层:

层级 对象 典型方法
便捷 viewer flyTo / zoomTo / trackedEntity
相机 viewer.camera flyTo / setView / lookAt / viewBoundingSphere
动画 flyHome 回到初始视角

flyTo vs setView vs zoomTo

  • flyTo:带过渡动画,适合产品交互
  • setView:瞬间跳转,适合初始化或调试
  • zoomTo:框选目标,动画较短,常用于数据加载后定位

HeadingPitchRange

new Cesium.HeadingPitchRange(heading, pitch, range)
  • heading:绕 Z 轴旋转(正北为 0)
  • pitch:俯仰(负值俯视地面)
  • range:相机到目标距离

trackedEntity

viewer.trackedEntity = entity;   // 开启跟随
viewer.trackedEntity = undefined; // 取消

相机会锁定实体,地球在下方「自转」——适合车辆、飞机跟踪。

实现步骤

  1. 初始化 Viewer,ArcGIS 影像 + 天地图注记
  2. Cesium3DTileset.fromUrl 加载白膜,entities.add 加载 glb
  3. 用 dat.GUI 把各 API 封装成可点击函数
  4. 对比 Entity / tileset / 经纬度 三种 flyTo 写法

代码要点

import * as Cesium from 'cesium'
import { GUI } from 'dat.gui'

const box = document.getElementById('box')

const viewer = new Cesium.Viewer(box, {

    animation: false,//是否创建动画小器件,左下角仪表    

    baseLayerPicker: false,//是否显示图层选择器,右上角图层选择按钮

    baseLayer: Cesium.ImageryLayer.fromProviderAsync(Cesium.ArcGisMapServerImageryProvider.fromUrl('https://server.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer')),

    fullscreenButton: false,//是否显示全屏按钮,右下角全屏选择按钮

    timeline: false,//是否显示时间轴    

    infoBox: false,//是否显示信息框   

})

// 天地图注记图层
viewer.imageryLayers.addImageryProvider(

    new Cesium.WebMapTileServiceImageryProvider({

        url: "https://t0.tianditu.gov.cn/cva_w/wmts?tk=c4e3a9d54b4a79e885fff9da0fca712a&service=wmts&request=GetTile&version=1.0.0&LAYER=cva&tileMatrixSet=w&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}&style=default&format=tiles",

        layer: "tdtAnnoLayer",

        style: "default",

        format: "image/jpeg",

        tileMatrixSetID: "GoogleMapsCompatible"

    })

)

const tileset = await Cesium.Cesium3DTileset.fromUrl(FILE_HOST + '3dtiles/house/tileset.json')

viewer.scene.primitives.add(tileset)

const entity = viewer.entities.add({

    name: 'gltf',

    position: Cesium.Cartesian3.fromDegrees(104.0668, 30.5728, 0), // 设置位置

    model: {

        uri: FILE_HOST + '/models/glb/map_park.glb',

    }

})

const gui = new GUI()

// viewer.flyTo viewer.zoomTo viewer.trackedEntity view.camera.setView  viewer.camera.lookAt 

const obj = {

    '重置最初:setView': () => viewer.camera.flyHome(1),

    '经纬度定位:flyTo': () => viewer.camera.flyTo({ destination: Cesium.Cartesian3.fromDegrees(116.4074, 39.9042, 1000) }),

    '实体:flyTo': () => viewer.flyTo(entity),

    '实体:zoomTo': () => viewer.zoomTo(entity),

    '实体跟随:trackedEntity': () => viewer.trackedEntity = entity,

    '取消实体跟随:trackedEntity': () => viewer.trackedEntity = undefined,

    '实体:lookAt': () => viewer.camera.lookAt(entity.position.getValue(Cesium.JulianDate.now()), new Cesium.Cartesian3(0, 0, 1000)),

    '瓦片:viewBoundingSphere': () => viewer.camera.viewBoundingSphere(tileset.boundingSphere, new Cesium.HeadingPitchRange(0, -0.5, 0)),

    '瓦片:flyToBoundingSphere': () => viewer.camera.flyToBoundingSphere(tileset.boundingSphere, new Cesium.HeadingPitchRange(0, -0.5, 0)),

    '瓦片:zoomTo': () => viewer.zoomTo(tileset),

    '瓦片:flyTo': () => viewer.flyTo(tileset),

    '瓦片:setView': () => viewer.camera.setView({
        destination: tileset.boundingSphere.center,
        orientation: {
            heading: 0,
            pitch: -Math.PI / 4,
            roll: 0
        }
    }),

    '瓦片:lookAt': () => viewer.camera.lookAt(tileset.boundingSphere.center),

    '相机:zoomIn 1000': () => viewer.camera.zoomIn(1000),

    '相机:zoomOut 1000': () => viewer.camera.zoomOut(1000),

}

for (const key in obj) gui.add(obj, key)

    console.log(viewer.camera)

完整源码:GitHub

小结