在 Cesium 开发中,相机是我们与三维地球交互的核心载体,它决定了我们观察三维场景的视角、范围和姿态。在前几篇文章中,我们已经了解了相机的基础配置、视角定位等核心功能,本篇将聚焦于相机的精细化初始配置、平滑飞行定位以及自定义键盘交互控制。
目录
[编辑一、Cesium 相机核心配置:初始视角与缩放限制](#编辑一、Cesium 相机核心配置:初始视角与缩放限制)

一、Cesium 相机核心配置:初始视角与缩放限制
1.相机缩放距离限制
通过camera.minimumZoomDistance和camera.maximumZoomDistance可以设置相机的最小 / 最大缩放距离(单位:米),防止用户缩放过近导致场景失真,或缩放过远超出业务所需范围:
// 获取场景对象与相机对象
const scene = viewer.scene
const camera = scene.camera
// 设置相机缩放距离限制
camera.minimumZoomDistance = 1000 // 最小缩放距离:1000米
camera.maximumZoomDistance = 5000000 // 最大缩放距离:500万米(5000公里)
2.两种初始视角定位方式
提供了两种常用的相机初始定位方式,分别适用于不同的业务场景。
关键参数说明:
Cartesian3.fromDegrees(lng, lat, height):将地理坐标系(经纬度 + 高度)转换为 Cesium 支持的笛卡尔直角坐标系,是相机定位的核心方法。
|---------|-----------------------------------------------------------------------|
| 参数 | 功能描述 |
| heading | 水平航向角,以正北为 0 度,顺时针旋转为正,范围 0~360 度(需通过Cesium.Math.toRadians()转换为弧度) |
| pitch | 俯仰角,控制相机的俯视 / 仰视角度,-90 度为垂直向下俯视,0 度为水平视角,90 度为垂直向上仰视 |
| roll | 翻滚角,控制相机的左右倾斜,一般保持 0 度即可,避免场景出现倾斜失真 |
方式一:直接设置视角(无过渡动画)
使用camera.setView()方法可以直接将相机定位到目标区域,无过渡效果,加载速度快,适用于需要快速渲染初始视角的场景:
// 以江苏省中心点(经度、纬度、高度)
const center = Cesium.Cartesian3.fromDegrees(119.8, 32.9, 20000)
// 直接设置相机视角聚焦江苏省
viewer.camera.setView({
destination: center, // 视角目标点(中心点+高度)
orientation: { // 相机姿态配置
heading: Cesium.Math.toRadians(0), // 水平方向角度(0为正北,顺时针递增)
pitch: Cesium.Math.toRadians(-40), // 俯视角度(-90为垂直向下,0为水平,90为垂直向上)
roll: Cesium.Math.toRadians(0) // 翻滚角度(一般保持0,避免场景倾斜)
}
})
方式二:平滑飞行定位(带过渡动画)
使用camera.flyTo()方法可以实现相机从当前视角平滑飞行到目标视角,带有过渡动画,用户体验更友好,还可以通过duration设置飞行时长(单位:秒):
// 以江苏省中心点(经度、纬度、高度)
const center = Cesium.Cartesian3.fromDegrees(119.8, 32.9, 20000)
// 平滑飞行定位到江苏省(推荐,用户体验更优)
viewer.camera.flyTo({
destination: center, // 视角目标点(中心点+高度)
orientation: { // 相机姿态配置
heading: Cesium.Math.toRadians(0), // 水平方向角度(正北)
pitch: Cesium.Math.toRadians(-10) // 俯视角度(轻微俯视,更清晰展示区域范围)
},
duration: 5 // 飞行过渡时间:5秒
})
二、自定义键盘交互:全方位控制相机姿态
Cesium 相机提供了丰富的姿态控制方法,我们可以通过监听键盘事件,实现自定义按键控制相机的移动、旋转、翻滚,让相机操作更符合用户的使用习惯,这也是三维场景交互的核心功能之一。
1.核心设计思路
(1)监听全局keydown事件,捕获用户按键操作;
(2)以相机当前离地高度为基准计算移动速度(moveRate = height/100),实现 "远快近慢" 的自适应移动效果,提升操作手感;
(3)映射不同按键到对应的相机方法,实现全方位交互控制。
2.核心相机方法说明
|----------------------------------------------|-------------|--------------|
| 相机方法 | 功能描述 | 适用场景 |
| moveForward(moveRate) | 相机沿当前视角向前平移 | 靠近目标物体 |
| moveBackward(moveRate) | 相机沿当前视角向后平移 | 远离目标物体 |
| moveLeft(moveRate) / moveRight(moveRate) | 相机左右平移 | 侧方观察场景 |
| moveUp(moveRate) / moveDown(moveRate) | 相机上下平移 | 调整相机离地高度 |
| lookLeft(rad) / lookRight(rad) | 相机左右旋转视角 | 水平方向环视场景 |
| lookUp(rad) / lookDown(rad) | 相机上下旋转视角 | 垂直方向观察场景 |
| twistLeft(rad) / twistRight(rad) | 相机左右翻滚 | 模拟飞行器倾斜等特殊场景 |
3.键盘交互逻辑
// 通过按键移动/旋转/翻滚相机
document.addEventListener('keydown', (event) => {
// 获取相机当前离地高度
var height = viewer.camera.positionCartographic.height
// 设置自适应移动速度(远快近慢)
var moveRate = height / 100
// 相机平移控制(前后左右上下)
if (event.key === 'w') {
viewer.camera.moveForward(moveRate) // 向前平移
} else if (event.key === 's') {
viewer.camera.moveBackward(moveRate) // 向后平移
} else if (event.key === 'a') {
viewer.camera.moveLeft(moveRate) // 向左平移
} else if (event.key === 'd') {
viewer.camera.moveRight(moveRate) // 向右平移
} else if (event.key === 'q') {
viewer.camera.moveUp(moveRate) // 向上平移
} else if (event.key === 'e') {
viewer.camera.moveDown(moveRate) // 向下平移
}
// 相机视角旋转控制(左右上下)
else if (event.key === 'z') {
viewer.camera.lookLeft(Cesium.Math.toRadians(0.1)) // 向左旋转视角
} else if (event.key === 'c') {
viewer.camera.lookRight(Cesium.Math.toRadians(0.1)) // 向右旋转视角
} else if (event.key === 'x') {
viewer.camera.lookUp(Cesium.Math.toRadians(0.1)) // 向上旋转视角
} else if (event.key === 'v') {
viewer.camera.lookDown(Cesium.Math.toRadians(0.1)) // 向下旋转视角
}
// 相机翻滚控制(左右倾斜)
else if (event.key === 'r') {
viewer.camera.twistLeft(Cesium.Math.toRadians(0.1)) // 向左逆时针翻滚
} else if (event.key === 'f') {
viewer.camera.twistRight(Cesium.Math.toRadians(0.1)) // 向右顺时针翻滚
}
})
三、完整代码展示
<template>
<div id="cesiumContainer"></div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import * as Cesium from 'cesium'
//设置cesiumtoken
Cesium.Ion.defaultAccessToken =
'你的token'
//设置cesium默认视角--该视角打开时地球中心点位置位于中国
Cesium.Camera.DEFAULT_VIEW_RECTANGLE = Cesium.Rectangle.fromDegrees(
//西边
89.5,
//南边
20.4,
//东边
110.4,
//北边
61.2
)
const initMapCesium = () => {
const viewer = new Cesium.Viewer('cesiumContainer', {
infoBox: false, //是否显示信息框
geocoder: false, //位置查找工具
homeButton: false, //是否显示首页位置工具
sceneModePicker: false, //是否显示视角模式切换工具
baseLayerPicker: false, //是否显示默认图层选择工具
navigationHelpButton: false, //是否显示导航帮助工具
animation: false, //是否显示动画工具
timeline: false, //是否显示时间轴工具
fullscreenButton: false //是否显示全屏按钮工具
})
viewer.cesiumWidget.creditContainer.style.display = 'none' //隐藏cesium版权信息
//设置地图的初始视角
const scene=viewer.scene//获取场景对象
const camera=scene.camera//获取相机对象
camera.minimumZoomDistance = 1000 //最小缩放距离
camera.maximumZoomDistance = 5000000 //最大缩放距离
//地图中心点位置--江苏省
const center=Cesium.Cartesian3.fromDegrees(119.8, 32.9, 20000) //设置初始视角的中心点--fromDegrees(经度,纬度,高度)
// 设置初始视角聚焦江苏省(高度500公里,俯视角度)--第一种方式
// viewer.camera.setView({
// destination: center,//设置视角的目标点
// orientation: {//设置视角的方向
// heading: Cesium.Math.toRadians(0), // 水平方向角度(0为正北)
// pitch: Cesium.Math.toRadians(-40), // 俯视角度(-90为垂直向下)
// roll: Cesium.Math.toRadians(0) // 翻滚角度
// }
// })
//第二种方式--用矩形范围精确框定江苏省
viewer.camera.flyTo({
destination: center,
orientation: {
heading: Cesium.Math.toRadians(0),
pitch: Cesium.Math.toRadians(-10)
},
duration: 5 // 飞行时间(秒)
})
//通过按键移动相机
document.addEventListener('keydown', (event) => {
//获取相机与地面的高度
var height = viewer.camera.positionCartographic.height
//设置移动速度
var moveRate=height/100
if (event.key === 'w') {
//设置相机向前移动
viewer.camera.moveForward(moveRate)
} else if (event.key === 's') {
//设置相机向后移动
viewer.camera.moveBackward(moveRate)
} else if (event.key === 'a') {
//设置相机向左移动
viewer.camera.moveLeft(moveRate)
} else if (event.key === 'd') {
//设置相机向右移动
viewer.camera.moveRight(moveRate)
} else if (event.key === 'q') {
//设置相机向上移动
viewer.camera.moveUp(moveRate)
} else if (event.key === 'e') {
//设置相机向下移动
viewer.camera.moveDown(moveRate)
} else if (event.key === 'z') {
//设置相机向左旋转
viewer.camera.lookLeft(Cesium.Math.toRadians(0.1))
} else if (event.key === 'c') {
//设置相机向右旋转
viewer.camera.lookRight(Cesium.Math.toRadians(0.1))
} else if (event.key === 'x') {
//设置相机向上旋转
viewer.camera.lookUp(Cesium.Math.toRadians(0.1))
} else if (event.key === 'v') {
//设置相机向下旋转
viewer.camera.lookDown(Cesium.Math.toRadians(0.1))
} else if (event.key === 'r') {
//向左逆时针翻滚
viewer.camera.twistLeft(Cesium.Math.toRadians(0.1))
}else if (event.key === 'f') {
//向右顺时针翻滚
viewer.camera.twistRight(Cesium.Math.toRadians(0.1))
}
})
// 监听相机位置变化,获取当前缩放等级(高度)
viewer.scene.postRender.addEventListener(() => {
// const currentHeight = Cesium.Cartographic.fromCartesian(camera.position).height
// console.log('当前缩放高度:', currentHeight, '米')
})
}
onMounted(() => {
initMapCesium()
})
</script>
<style lang="less" scoped>
#cesiumContainer {
overflow: hidden;
width: 100vw;
height: 100vh;
}
</style>
四、结果展示
