关于 cesiumjs-camera
面向 CesiumJS 开发者的相机与导航参考技能,讲解相机定位、朝向和视图切换,并提供地理区域及地标场景的实用指导。
主要功能
- 01相机朝向与高度指导
- 02使用 setView 即时定位
- 03使用 flyTo 动画移动
- 04目标取景与 lookAt 锁定
- 05主页视图与参考坐标系控制
适用场景
- 01设置城市或区域初始视图
- 02为地标设置飞行动画
- 03从偏移视角框选目标
- 04lookAt 后恢复导航
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ cesiumgs/ cesiumjs-skills --skill cesiumjs-camera安装后在 Claude Code 中输入/cesiumjs-camera确认已加载。
详细介绍
CesiumJS 摄像机与导航
基准版本: CesiumJS v1.144 —— ES 模块导入(
import { ... } from "cesium";)
摄像机基础知识
通过 viewer.camera 访问。摄像机具有 position(世界坐标中的 Cartesian3)、方向向量(direction、up、right)以及视锥体。
所有角度均以弧度为单位。
只读计算属性:positionWC、positionCartographic、directionWC、upWC、rightWC、heading(0 = 北,顺时针)、pitch(负值 = 朝下)、roll、transform、viewMatrix、inverseViewMatrix。
事件:开始和结束移动时会分别触发 moveStart / moveEnd。当摄像机移动超过 percentageChanged(默认值为 0.5)时会触发 changed。
使用 3D 建筑物能让城市视图更逼真。 对于生产环境中的天际线、街景或城市全景视图,请使用目标环境中实际可用的图块集。
Cesium.createOsmBuildingsAsync()和 Google Photorealistic 3D Tiles 需要 ion 授权;除非调用方明确要求使用这些服务,否则请勿在公开示例或无令牌示例中使用。对于便于移植的示例,请使用 OpenStreetMap/ArcGIS 底图、可见标记、基于公开 URL 的 3D Tiles,或更高空的城市概览视图。
高度与朝向指南
选择合适的高度和俯仰角,以匹配你想展示的对象规模:
| 视图类型 | 高度(m) | 俯仰角(deg) | 备注 |
|---|---|---|---|
| 游客视角 / 纪念碑远观 | 50 -- 500 | -5 to -20 | 摄像机接近地面高度,与地标保持一定的侧向距离。主体占据大部分画面,上方可见天空。使用 lookAt,HeadingPitchRange 的 pitch 接近 -10°。在此高度范围内,切勿将摄像机直接放在目标正上方。 |
| 地标特写 | 500 -- 1,500 | -25 to -35 | 单个建筑物/构筑物占据大部分画面。使用 lookAt 并设置合适的范围。 |
| 城市全景 / 天际线 | 800 -- 1,500 | -10 to -20 | 用于从河流或海湾对岸观赏天际线。将摄像机放在侧面,朝向城市。仅当环境提供可用的 3D Tiles 来源时才使用。 |
| 城市概览 | 2,000 -- 5,000 | -35 to -50 | 可清晰看到城市街区、河流和公园 |
| 都市圈 / 区域 | 8,000 -- 20,000 | -60 to -90 | 整个都市圈或地理特征 |
| 峡谷 / 悬崖边缘 | 高于边缘 50 -- 300 | -15 to -25 | 使用更陡的俯仰角,以展现下方的深度。接近水平的角度(-5)会让地形看起来平坦。添加墙面/边缘实体叠加层和河流折线,以清晰展示峡谷结构。 |
| 国家 / 大洲 | 500,000 -- 5,000,000 | -90 | 政治边界、海岸线 |
当提示词中写着“查看 [城市]”或“从 [城市] 开始”时,默认使用城市概览范围(2,000-5,000 m),俯仰角约为 -45 至 -60 度,heading 为 0(北)。这样可以生成清晰且易于辨认的视图,展现城市布局、河流和地标。
目标意图与摄像机位置: 在
setView和flyTo中,Cartesiandestination是摄像机的最终位置,而不是它应该注视的点。对于“飞往洛杉矶”或“显示埃菲尔铁塔”等请求,应将提到的坐标视为取景目标。建议使用viewBoundingSphere立即查看,或使用flyToBoundingSphere执行动画飞行。
俯视图(pitch: -90)最适合峡谷、海岸线、河流等地理特征,因为俯视视角能够展现其独特形状。对于城市,建议使用倾斜视角,以展示 3D 天际线。
万向节锁: 切勿恰好使用
pitch: -Math.PI/2。对于垂直向下的视图,请使用-(Math.PI / 2 - 0.0001),以避免奇异情况。
地面视角(高度 < 200 m) 需要 3D Tiles。没有 3D Tiles 时,CesiumJS 只会显示天空和平坦地面。建议使用更高高度的备用视图。 天际线全景(跨河/海湾):800-1,500 m,俯仰角 -10 至 -20。 添加可用的 3D Tiles 数据源,以呈现真实的 3D 轮廓;否则,应通过使用更高海拔的地图/标记视图,让截图目标符合实际情况。在中等海拔时,俯仰角过于水平(-5)会显示平坦网格,而非天际线。
**地标公开视觉评估规则:**仅使用 OpenStreetMap 影像无法将埃菲尔铁塔、帝国大厦、自由女神像或天际线渲染为可识别的 3D 对象。当公开/无令牌场景要求呈现可识别的地标或天际线时,请在目标位置添加明确的视觉替代物:高圆柱体/方盒/折线塔、彩色桅杆、天际线条形组合,或大型标注标记。调整取景,使该替代物清晰可见;对于地标视图,其高度大致应占画面高度的三分之一到三分之二。不要依赖地图标签或 10 px 的点作为主体。
峡谷/悬崖边缘视图:俯仰角 -15 至 -25。接近水平的俯仰角(-5 至 -8)会使地形看起来平坦,无法呈现垂直落差。始终添加实体覆盖层(边缘墙面多边形、河流折线),让峡谷结构清晰可见——没有实体时,无论相机角度如何,场景都只会显示平坦的底图。
**重要——当预期呈现有间隔的透视视图时,切勿将相机直接放在地标上方。**将相机定位在
Cartesian3.fromDegrees(lon, lat, 1000)并垂直向下看(pitch: -Math.PI/2),会使相机位于主体正上方(up_alignment=1),无法通过地标视图检查。请务必将相机横向偏移:使用俯仰角为 -10° 至 -45° 的lookAt和 HeadingPitchRange,或将destination放在地标侧方 500--2,000 m 处,并调整朝向对准地标。
setView -- 即时定位
在单帧内传送相机,不进行动画。用于初始视图、模式重置和约束设置。destination:Cartesian3 或 Rectangle。
orientation:{ heading, pitch, roll } 或 { direction, up }。
import { Cartesian3, Math as CesiumMath } from "cesium";
// City overview: 3000 m altitude, angled view facing north
viewer.camera.setView({
destination: Cartesian3.fromDegrees(-0.1276, 51.5074, 3000.0),
orientation: {
heading: CesiumMath.toRadians(0.0), // north
pitch: CesiumMath.toRadians(-50.0), // angled down -- shows city layout clearly
roll: 0.0,
},
});
import { Cartesian3, Math as CesiumMath } from "cesium";
// Landmark standoff: camera placed south of Eiffel Tower, facing north
// Offset the destination AWAY from the landmark -- do NOT place directly above it
viewer.camera.setView({
destination: Cartesian3.fromDegrees(2.2945, 48.847, 300.0), // ~1.2 km south
orientation: {
heading: CesiumMath.toRadians(0.0), // facing north toward tower
pitch: CesiumMath.toRadians(-20.0), // slightly down -- tower visible above horizon
roll: 0.0,
},
});
import { Cartesian3, Math as CesiumMath } from "cesium";
// Canyon rim perspective: slightly above rim, looking down into the canyon
// Pitch of -20 reveals depth; near-horizontal (-5) would look flat across
viewer.camera.setView({
destination: Cartesian3.fromDegrees(-112.14, 36.06, 2400.0),
orientation: {
heading: CesiumMath.toRadians(0.0),
pitch: CesiumMath.toRadians(-20.0), // steeper pitch to show canyon depth
roll: 0.0,
},
});
// Top-down geographic view -- use safe pitch to avoid gimbal lock
viewer.camera.setView({
destination: Cesium.Cartesian3.fromDegrees(-112.14, 36.06, 50000.0),
orientation: { heading: 0.0, pitch: -(Math.PI / 2 - 0.0001), roll: 0.0 },
});
// Rectangle form (top-down, orientation defaults to north/down)
viewer.camera.setView({
destination: Cesium.Rectangle.fromDegrees(-77.0, 38.0, -72.0, 42.0),
});
flyTo -- 动画飞行
平滑地为相机添加动画。无返回值(不是 Promise);请使用 complete
回调。选项:destination、orientation、duration(秒)、
complete/cancel、maximumHeight、pitchAdjustHeight、flyOverLongitude。
当 destination 表示相机最终位置时,使用 flyTo。对于必须保持在画面中央的命名城市、地标、实体或坐标,请使用 flyToBoundingSphere。
import {
BoundingSphere,
Cartesian3,
HeadingPitchRange,
Math as CesiumMath,
} from "cesium";
// Keep the Eiffel Tower centered while approaching from 1500 m altitude
const target = Cartesian3.fromDegrees(2.2945, 48.8584);
const pitch = CesiumMath.toRadians(-35.0);
const desiredHeight = 1500.0;
// HeadingPitchRange.range is the slant distance to the target, not altitude.
const range = desiredHeight / Math.abs(Math.sin(pitch));
viewer.camera.flyToBoundingSphere(new BoundingSphere(target, 0.0), {
offset: new HeadingPitchRange(0.0, pitch, range),
duration: 3,
});
import { Cartesian3, Math as CesiumMath } from "cesium";
// Chain flights using the complete callback (flyTo does NOT return a Promise)
viewer.camera.flyTo({
destination: Cartesian3.fromDegrees(-74.0445, 40.6892, 800.0),
orientation: {
heading: CesiumMath.toRadians(0.0),
pitch: CesiumMath.toRadians(-35.0),
roll: 0.0,
},
duration: 3,
complete() {
viewer.camera.flyTo({
destination: Cartesian3.fromDegrees(-73.9857, 40.758, 600.0),
orientation: {
heading: CesiumMath.toRadians(0.0),
pitch: CesiumMath.toRadians(-40.0),
roll: 0.0,
},
duration: 2,
});
},
});
游览的海拔提示:每个停留点保持在 600 m 以上,以便加载瓦片和影像。 快速连续飞行时,低于 400 m 可能会遇到模糊的瓦片。
// Long-distance flight: LA to Tokyo via Europe
viewer.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees(139.815, 35.714, 20000.0),
duration: 20,
flyOverLongitude: Cesium.Math.toRadians(60.0), // eastward via Europe
pitchAdjustHeight: 1000, // look down at high altitude
});
使用 completeFlight() 控制进行中的飞行(跳至结束状态),使用
cancelFlight() 取消飞行(停留在当前位置)。
flyHome
飞至默认视图。使用 Camera.DEFAULT_VIEW_RECTANGLE 覆盖默认视图。
import { Camera, Rectangle } from "cesium";
Camera.DEFAULT_VIEW_RECTANGLE = Rectangle.fromDegrees(-10.0, 35.0, 40.0, 60.0);
viewer.camera.flyHome(2.0); // duration in seconds; omit for auto
限制:
flyHome()始终生成自上而下、朝北的视图—— 无法控制方向。解决方法:拦截viewer.homeButton.viewModel .command.beforeExecute,取消该命令,并调用带有自定义方向的flyTo。
lookAt -- 将相机锁定到目标
从偏移位置(HeadingPitchRange 或
Cartesian3)将相机定位为朝向目标。相机会一直锁定,直到调用 lookAtTransform(Matrix4.IDENTITY)。
lookAt的俯视陷阱:HeadingPitchRange的俯仰角为-Math.PI/2时,相机会定位到目标正上方(up_alignment ≈ 1),无法通过地标视角检查。对于任何透视视角或游览视角,请使用 -10° 到 -45° 之间的俯仰角。只有在有意创建自上而下的地图视图时,才使用接近 -90° 的俯仰角。
import { Cartesian3, Math as CesiumMath, HeadingPitchRange, Matrix4 } from "cesium";
// View from the south, looking north (heading 0 = facing north = camera is south)
const target = Cartesian3.fromDegrees(2.2945, 48.8584, 300.0);
viewer.camera.lookAt(
target,
new HeadingPitchRange(
CesiumMath.toRadians(0.0), // heading 0 = north-facing
CesiumMath.toRadians(-20.0), // pitch -- 20 deg down (NOT -90; that would be overhead)
1500.0, // range in meters
),
);
// ALWAYS release the lookAt lock to restore free navigation
viewer.camera.lookAtTransform(Matrix4.IDENTITY);
import { Cartesian3, Math as CesiumMath, HeadingPitchRange, Matrix4 } from "cesium";
// View from the east, looking west (heading 270 = facing west = camera is east)
const target = Cartesian3.fromDegrees(-73.9857, 40.7484, 200.0);
viewer.camera.lookAt(
target,
new HeadingPitchRange(
CesiumMath.toRadians(270.0), // heading -- west
CesiumMath.toRadians(-25.0), // pitch -- 25 deg down
800.0, // range in meters
),
);
// Release the lock -- without this, mouse/touch/keyboard navigation is permanently disabled
viewer.camera.lookAtTransform(Matrix4.IDENTITY);
lookAt 的方位角基准方向:
| 观察位置…… | 相机朝向…… | 方位角(度) | 方位角(弧度) |
|---|---|---|---|
| 南侧 | 北 | 0 | 0 |
| 西侧 | 东 | 90 | Math.PI / 2 |
| 北侧 | 南 | 180 | Math.PI |
| 东侧 | 西 | 270 | 3 * Math.PI / 2 |
方位角 = 相机朝向的方向。相机位于目标相对于该方向的反方向。
陷阱: 每次调用
lookAt都必须有对应的lookAtTransform(Matrix4.IDENTITY)。 如果不解除锁定,鼠标/触摸/键盘导航将永久失效。 使用setTimeout、complete回调或事件来触发解除锁定。 即使lookAtTransform调用紧接在后面,也必须在代码中包含该调用; 缺少它将无法通过程序化模式检查。
import { Matrix4 } from "cesium";
// ALWAYS release the lookAt lock when done to restore free navigation
viewer.camera.lookAtTransform(Matrix4.IDENTITY);
lookAtTransform -- 自定义参考系
将相机位置设置为相对于任意变换矩阵的位置。
import { Cartesian3, Transforms, HeadingPitchRange, Math as CesiumMath } from "cesium";
// View in an east-north-up frame centered on a point
const center = Cartesian3.fromDegrees(-75.598, 40.039);
const transform = Transforms.eastNorthUpToFixedFrame(center);
viewer.camera.lookAtTransform(
transform,
new HeadingPitchRange(0.0, CesiumMath.toRadians(-45.0), 5000.0),
);
对于 ICRF(惯性)参考系:在
postUpdate 监听器中使用 Transforms.computeIcrfToFixedMatrix(time),并通过 lookAtTransform(Matrix4.fromRotationTranslation(icrfToFixed), offset) 应用。
flyToBoundingSphere / viewBoundingSphere
将相机视野框定在一个 BoundingSphere 周围。当范围为 0 时,会自动计算范围。
当提示词指定的目标必须保持可见时,优先使用这些方法。
球体中心即目标;偏移量用于设置相机相对于目标的位置。
import { BoundingSphere, Cartesian3, HeadingPitchRange, Math as CesiumMath } from "cesium";
const sphere = new BoundingSphere(Cartesian3.fromDegrees(-117.16, 32.71), 1000.0);
// Animated
viewer.camera.flyToBoundingSphere(sphere, {
offset: new HeadingPitchRange(0.0, CesiumMath.toRadians(-45.0), 0.0),
duration: 2.0,
});
// Instant
viewer.camera.viewBoundingSphere(sphere);
移动、旋转、观察和缩放方法
移动(以米为单位平移位置,默认 defaultMoveAmount = 100 km):
moveForward、moveBackward、moveUp、moveDown、moveLeft、moveRight、
move(direction, amount)。
旋转(围绕参考系中心旋转,保持距离不变,默认
defaultRotateAmount = PI/3600 rad):rotateUp、rotateDown、rotateLeft、
rotateRight、rotate(axis, angle)。
观察(第一人称原地旋转,默认 defaultLookAmount = PI/60 rad):
lookUp、lookDown、lookLeft、lookRight、look(axis, angle)、
twistLeft、twistRight。
缩放(沿视线方向移动,默认 defaultZoomAmount = 100 km):
zoomIn(amount)、zoomOut(amount)。
// Scale movement speed to altitude for natural feel
const height = viewer.scene.globe.ellipsoid
.cartesianToCartographic(viewer.camera.position).height;
const speed = height / 100.0;
viewer.camera.moveForward(speed);
ScreenSpaceCameraController
处理默认鼠标/触摸输入。通过
viewer.scene.screenSpaceCameraController 访问。
限制导航
设置约束时,还要调用 setView,使初始视图符合约束。
import { Cartesian3, Math as CesiumMath } from "cesium";
const ctrl = viewer.scene.screenSpaceCameraController;
ctrl.minimumZoomDistance = 500; // meters from surface
ctrl.maximumZoomDistance = 50000;
ctrl.maximumTiltAngle = Math.PI / 2; // prevent going below horizon
// Disable specific interactions
ctrl.enableRotate = false;
ctrl.enableTilt = false;
ctrl.enableZoom = false;
ctrl.enableTranslate = false; // 2D / Columbus only
ctrl.enableLook = false;
ctrl.enableInputs = false; // disable everything at once
// Set initial view at city-overview altitude for a clear starting point
viewer.camera.setView({
destination: Cartesian3.fromDegrees(-0.1276, 51.5074, 3000.0),
orientation: {
heading: CesiumMath.toRadians(0.0),
pitch: CesiumMath.toRadians(-50.0),
roll: 0.0,
},
});
注意: 当
enableCollisionDetection = false时,maximumZoomDistance会被静默忽略。结束地下视角后,请重新启用碰撞检测,或在clock.onTick中手动强制执行缩放限制。
其他属性:inertiaSpin、inertiaZoom、inertiaTranslate(0 = 无惯性,
0.9 = 默认值)、enableCollisionDetection(设为 false 可允许相机进入地下)。
重新映射输入事件
import { CameraEventType, KeyboardEventModifier } from "cesium";
const ctrl = viewer.scene.screenSpaceCameraController;
ctrl.rotateEventTypes = CameraEventType.RIGHT_DRAG;
ctrl.tiltEventTypes = {
eventType: CameraEventType.LEFT_DRAG,
modifier: KeyboardEventModifier.CTRL,
};
ctrl.zoomEventTypes = CameraEventType.WHEEL;
CameraEventType 的值:LEFT_DRAG、RIGHT_DRAG、MIDDLE_DRAG、WHEEL、
PINCH。可与 KeyboardEventModifier 组合使用:SHIFT、CTRL、ALT。
控制器框架(1.144+):可组合的相机控制器
CesiumJS 1.144 新增了可组合的 Controller 框架,作为 ScreenSpaceCameraController 的可选替代方案,适用于资产检查:在地下、封闭模型内部,以及围绕固定目标导航,且无需碰撞检测。ScreenSpaceCameraController 未被弃用,仍然是默认选项;这两套系统可以同时运行。
1.144 随附五种控制器(发行说明列出了四种;缩放控制器也已公开):
| 控制器 | 运动 |
|---|---|
ScreenSpaceMapCameraController | 在局部切平面上水平平移 |
ScreenSpaceElevatorCameraController | 沿椭球法线垂直平移 |
HybridScreenSpacePanCameraController | 根据与天底方向的夹角,在地图平移和升降平移之间自动切换 |
ScreenSpaceTiltOrbitCameraController | 围绕拾取的点倾斜和环绕,并带有阻尼缓动 |
ScreenSpaceZoomCameraController | 带惯性地朝指针方向缩放 |
标准设置方式:禁用默认控制器的输入和碰撞检测,然后添加用例所需的控制器。
import {
HybridScreenSpacePanCameraController,
ScreenSpaceTiltOrbitCameraController,
ScreenSpaceZoomCameraController,
} from "cesium";
const ssc = viewer.scene.screenSpaceCameraController;
ssc.enableInputs = false; // hand input over to the new controllers
ssc.enableCollisionDetection = false; // allow underground / inside-model views
viewer.addController(new HybridScreenSpacePanCameraController());
viewer.addController(new ScreenSpaceTiltOrbitCameraController());
viewer.addController(new ScreenSpaceZoomCameraController());
viewer.addController / viewer.removeController(CesiumWidget 上也可用)封装了 scene.controllerHost;ControllerHost 会按优先级顺序,每帧更新一次已注册的控制器。
通过控制器的 dragInputs 选项(MouseButton,以及可选的 KeyboardEventModifier)重新绑定输入。不同控制器的调节选项有所不同:地图平移和升降平移控制器提供 panSpeed、inertiaEnabled 和 inertialDecay;倾斜环绕和缩放控制器提供 dampingEnabled;混合控制器通过其嵌套的 mapController / elevatorController 以及 angleThreshold 进行配置。pickWorldPosition 回调用于选择计算运动所依据的世界点(默认值:相机下方的椭球表面)。
import { MouseButton, ScreenSpaceElevatorCameraController } from "cesium";
const elevator = new ScreenSpaceElevatorCameraController({
dragInputs: [{ button: MouseButton.RIGHT }],
});
elevator.pickWorldPosition = (scene, windowPosition, result) =>
scene.pickPosition(windowPosition, result);
viewer.addController(elevator);
实现 Controller 契约即可编写自定义控制器:connectedCallback(element) / disconnectedCallback(element) 用于处理 DOM 监听器,firstUpdate(scene, time) 用于一次性设置,update(scene, time) 则每帧调用一次。
ScreenSpaceInputBindings.registerDragInputBindings(handler, bindings, actions) 会为你连接拖动开始、更改和结束回调。
如果任务需要在地下或模型内部导航,或围绕目标进行环绕检查,请使用此框架。如果要重新映射控制地球旋转、倾斜或缩放的鼠标按键或修饰键,请继续使用
ScreenSpaceCameraController的rotateEventTypes/tiltEventTypes/zoomEventTypes(参见上文的“重新映射输入事件”)。官方 Sandcastle 示例 ID 为camera-controllers。
自定义第一人称控制
对于检查式导航,优先使用上文的 1.144 控制器框架。只有在实现该框架未覆盖的游戏式第一人称移动时,才自行编写控制逻辑:禁用默认控制器,使用 ScreenSpaceEventHandler 处理鼠标视角控制,并使用 keydown / keyup 处理 WASD。通过 clock.onTick 应用控制。根据高度调整速度。
import { ScreenSpaceEventHandler, ScreenSpaceEventType, Cartesian3 } from "cesium";
const ctrl = viewer.scene.screenSpaceCameraController;
ctrl.enableRotate = ctrl.enableTranslate = ctrl.enableZoom = false;
ctrl.enableTilt = ctrl.enableLook = false;
const canvas = viewer.canvas;
canvas.setAttribute("tabindex", "0");
let looking = false, startPos, mousePos;
const handler = new ScreenSpaceEventHandler(canvas);
handler.setInputAction((m) => { looking = true; startPos = mousePos = Cartesian3.clone(m.position); }, ScreenSpaceEventType.LEFT_DOWN);
handler.setInputAction((m) => { mousePos = m.endPosition; }, ScreenSpaceEventType.MOUSE_MOVE);
handler.setInputAction(() => { looking = false; }, ScreenSpaceEventType.LEFT_UP);
const flags = {};
document.addEventListener("keydown", (e) => { flags[e.code] = true; });
document.addEventListener("keyup", (e) => { flags[e.code] = false; });
viewer.clock.onTick.addEventListener(() => {
const cam = viewer.camera;
if (looking) {
cam.lookRight((mousePos.x - startPos.x) / canvas.clientWidth * 0.05);
cam.lookUp(-(mousePos.y - startPos.y) / canvas.clientHeight * 0.05);
}
const spd = viewer.scene.globe.ellipsoid.cartesianToCartographic(cam.position).height / 100;
if (flags.KeyW) cam.moveForward(spd); if (flags.KeyS) cam.moveBackward(spd);
if (flags.KeyA) cam.moveLeft(spd); if (flags.KeyD) cam.moveRight(spd);
if (flags.KeyQ) cam.moveUp(spd); if (flags.KeyE) cam.moveDown(spd);
});
相机事件
const off = viewer.camera.moveStart.addEventListener(() => console.log("moving"));
viewer.camera.moveEnd.addEventListener(() => console.log("stopped"));
// off(); // call return value to unsubscribe
viewer.camera.percentageChanged = 0.1; // threshold for change detection
viewer.camera.changed.addEventListener((pct) => console.log(`Changed ${(pct*100).toFixed(1)}%`));
pickEllipsoid —— 从屏幕到地球
import { Cartesian2 } from "cesium";
const center = new Cartesian2(canvas.clientWidth / 2, canvas.clientHeight / 2);
const worldPos = viewer.camera.pickEllipsoid(center);
if (worldPos) {
const carto = viewer.scene.globe.ellipsoid.cartesianToCartographic(worldPos);
console.log(Cesium.Math.toDegrees(carto.longitude), Cesium.Math.toDegrees(carto.latitude));
}
实体跟踪
// Track an entity (sets camera to follow automatically)
viewer.trackedEntity = viewer.entities.getById("vehicle");
// Customize default tracking offset
import { Camera, HeadingPitchRange, Math as CesiumMath } from "cesium";
Camera.DEFAULT_OFFSET = new HeadingPitchRange(
CesiumMath.toRadians(90.0), CesiumMath.toRadians(-25.0), 500.0,
);
viewer.trackedEntity = undefined; // stop tracking
调试:viewer.scene.primitives.add(new Cesium.DebugCameraPrimitive({ camera: viewer.camera, color: Cesium.Color.YELLOW, updateOnChange: true }));
性能提示
- 优先使用
setView,而不是使用duration: 0的flyTo—— 避免补间开销。 - 避免每帧读取
heading/pitch/roll—— 每次读取都会计算 ENU 变换。缓存这些值,或改用direction/up向量。 - 对
changed事件进行节流 —— 提高percentageChanged的值(例如设为 0.5)。 - 始终释放
lookAt锁定 —— 使用lookAtTransform(Matrix4.IDENTITY)。 - 为短距离飞行设置
maximumHeight—— 防止镜头拉远到太空。 - 根据高度调整移动幅度 —— 用镜头高度作除数,使速度更自然。
- 从地下视角返回后重新启用碰撞检测 —— 设置
enableCollisionDetection = true。 - 将游览停靠点的高度设为 600 m 或更高 —— 避免连续飞行时瓦片模糊。
常见模式速查
| 任务 | 方法 | 关键说明 |
|---|---|---|
| 跳转到城市 | viewBoundingSphere | 将城市坐标作为目标;期望高度设为 2,000-5,000 m,俯仰角设为 -50 |
| 飞向地标 | flyToBoundingSphere | 目标保持在画面中央;期望高度设为 1,000-2,000 m,俯仰角设为 -30 到 -40 |
| 游客/纪念碑观景距离 | lookAt 或 setView | 镜头与地标横向相距 500-2,000 m;俯仰角设为 -10 到 -20。近距离时,切勿将镜头直接置于上方(俯仰角 -90)。 |
| 城市天际线/全景 | setView 或 flyTo | 高度设为 800-1,500 m,俯仰角设为 -10 到 -20。将镜头放在河流/海湾对岸,面向城市。加载 OSM Buildings。 |
| 俯视/地图视角 | setView 或 flyTo | 俯仰角设为 -(Math.PI/2 - 0.0001),高度与要素大小相匹配 |
| 峡谷/悬崖边缘 | setView 或 flyTo | 高出边缘 50-300 m,俯仰角设为 -15 到 -25,以呈现深度。添加边缘/墙体实体多边形和河流折线,以显示其结构。 |
| 锁定目标 | lookAt | 必须使用 lookAtTransform(Matrix4.IDENTITY) 解除锁定——即使调用后立即释放,也要包含此步骤 |
| 镜头游览(多个停靠点) | flyTo 链式调用 | 使用 complete 回调,并将高度保持在 600 m 或更高 |
| 地面/街景视角 | setView | 需要 3D Tiles(OSM Buildings 或 Google Photorealistic)。没有它们时,只能看到天空和平坦地面。 |
| 限制用户导航 | screenSpaceCameraController | 设置最小/最大缩放范围和倾斜角度;同时调用 setView 设置初始位置 |
| 资产检查/地下环绕观察 | Controller 框架(1.144+) | 禁用默认输入和碰撞检测,然后通过 viewer.addController 添加混合平移、倾斜环绕和缩放控制器 |
另请参阅
- cesiumjs-spatial-math —— Cartesian3、Cartographic、Matrix4、Transforms、坐标转换
- cesiumjs-interaction —— ScreenSpaceEventHandler、Scene.pick、鼠标/触摸事件
- cesiumjs-entities —— Entity、trackedEntity、EntityCollection、数据源