CesiumJS 全景影像显示——官方教程翻译
CesiumJS 支持全景和 360° 球面影像,让你能够在 CesiumJS 场景中直接渲染等距柱状投影(equirectangular)和立方体贴图(cube map)全景图。这为在 3D 地理空间环境中流式加载 Google Street View 全景图(以及其他全景影像服务)提供了支持。

法国拉昂大教堂内部的 360° 全景影像。照片由 David Iliff 拍摄,基于 CC BY-SA 3.0 许可。
你将学习如何:
- 将等距柱状投影全景图添加到 CesiumJS 场景,并将相机放置到其”内部”
- 添加立方体贴图全景图(六个面)并正确朝向
- 配置相机控制以获得沉浸式体验,包括可选的视场角”缩放”
先决条件
- 一个基础的 CesiumJS 应用。如果从零开始,请先遵循 CesiumJS 快速入门教程 并确保应用正常运行
- 一张全景影像:
- 等距柱状投影:最好为 2:1 宽高比,代表水平 360° / 垂直 180°
- 立方体贴图:六个面(每面 90° × 90° 透视投影)
本教程中的代码示例会提供示例数据供你上手。
信息:关于图片托管和 CORS 的说明:如果你的全景图片托管在不同的域名上,服务器必须允许跨域使用(CORS),否则 WebGL 无法将其作为纹理采样。如果来源不支持 CORS,你需要一个同源代理。
步骤 1:设置查看器用于全景浏览
创建一个查看器并关闭地球,使全景图成为场景背景。为了获得最佳的全景浏览体验,建议通过设置 globe.show = false 来隐藏地球。
import * as Cesium from "cesium";
const viewer = new Cesium.Viewer("cesiumContainer");
// 为获得最佳全景浏览效果,关闭地球
viewer.scene.globe.show = false;
const controller = viewer.scene.screenSpaceCameraController;
为什么要隐藏地球?
- 全景影像通常作为背景上下文层使用,而其他图元(3D Tiles、模型、实体)在前方渲染
- 实用提示:退出全景模式时,可以重新启用地球(例如
viewer.scene.globe.show = true) - 性能提示:在许多应用中,这还能在全景浏览期间避免地球渲染,从而减少绘制开销
步骤 2:添加等距柱状投影全景图
等距柱状投影全景图是一张包裹在相机周围球体上的单一图像。准备好影像后,定位并朝向你的全景图:你需要在地球上确定一个位置,并在可用时使用航向/俯仰/翻滚元数据来正确朝向。
const equirectangularFromFile = () => {
const position = Cesium.Cartesian3.fromDegrees(-122.4175, 37.655, 100);
// 如果你有朝向元数据(例如来自 EXIF/XMP 或影像服务),
// 将其转换为弧度并在此使用。
// 以下为演示用的示例值。
const heading = Cesium.Math.toRadians(10.0); // 绕本地向上轴旋转
const pitch = Cesium.Math.toRadians(-5.0); // 负值表示向下看
const roll = Cesium.Math.toRadians(2.0); // 绕前向轴翻滚
const hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll);
// 创建一个变换矩阵来定位并朝向全景图。
// 这在全景图的世界位置处融合了航向/俯仰/翻滚。
const transform = Cesium.Transforms.headingPitchRollToFixedFrame(
position,
hpr,
Cesium.Ellipsoid.WGS84,
Cesium.Transforms.eastNorthUpToFixedFrame,
);
const image =
"https://upload.wikimedia.org/wikipedia/commons/0/08/Laon_Cathedral_Interior_360x180%2C_Picardy%2C_France_-_Diliff.jpg";
const credit = new Cesium.Credit(
"Photo by DAVID ILIFF. Interior of Laon Cathedral, France. Licensed under " +
"https://creativecommons.org/licenses/by-sa/3.0/.",
);
const panorama = new Cesium.EquirectangularPanorama({
transform,
image,
credit,
});
viewer.scene.primitives.add(panorama);
// 将相机放置在全景图中心
viewer.scene.camera.lookAt(
position,
new Cesium.HeadingPitchRange(0, 0, 2), // 微小偏移以允许旋转
);
// 将用户"固定"在全景图内部(可选,但对许多体验推荐)
controller.enableZoom = false;
controller.enableTranslate = false;
};
信息:为什么要用航向/俯仰/翻滚?许多拍摄流程和影像服务会提供朝向元数据。将其纳入全景图的变换矩阵中,可以确保全景图与实际场景正确对齐。
这里发生了什么?
- 你计算了一个本地坐标系变换矩阵并将其传递给全景图,使其在全局场景中正确定位/朝向
- 你使用
camera.lookAt将相机放置在全景图中心 - 你可以选择性地限制相机控制,使相机保持固定,获得清晰的”环顾四周”体验
- 你将航向/俯仰/翻滚融入了变换矩阵中
一个可直接在 CesiumJS 场景中渲染的沉浸式全景图。
—
步骤 3:添加立方体贴图全景图(六张图片)
立方体贴图是六张图片(前/后/左/右/上/下),包裹在相机周围的立方体上。与等距柱状投影全景图类似,你需要创建一个变换矩阵来在场景中正确朝向。
const cubeMapFromFiles = () => {
const position = Cesium.Cartesian3.fromDegrees(104.923323, 11.569967, 0);
// 创建一个变换矩阵来朝向全景图
const matrix4 = Cesium.Transforms.localFrameToFixedFrameGenerator(
"north",
"down",
)(position, Cesium.Ellipsoid.default);
const transform = Cesium.Matrix4.getMatrix3(matrix4, new Cesium.Matrix3());
const credit = new Cesium.Credit(
"Image by Kiensvay via Wikimedia Commons " +
"Licensed under " +
'<a href="https://creativecommons.org/licenses/by-sa/4.0/" target="_blank">CC BY-SA 4.0</a>.',
);
const cubeMapPanorama = new Cesium.CubeMapPanorama({
sources: {
positiveZ:
"https://upload.wikimedia.org/wikipedia/commons/3/37/360%C2%B0_Phnom_Penh_%28Central_Market_2022%29_%28left%29.jpg",
negativeZ:
"https://upload.wikimedia.org/wikipedia/commons/1/1b/360%C2%B0_Phnom_Penh_%28Central_Market_2022%29_%28right%29.jpg",
positiveY:
"https://upload.wikimedia.org/wikipedia/commons/7/73/360%C2%B0_Phnom_Penh_%28Central_Market_2022%29_%28down%29.jpg",
negativeY:
"https://upload.wikimedia.org/wikipedia/commons/d/de/360%C2%B0_Phnom_Penh_%28Central_Market_2022%29_%28up%29.jpg",
negativeX:
"https://upload.wikimedia.org/wikipedia/commons/2/2e/360%C2%B0_Phnom_Penh_%28Central_Market_2022%29_%28back%29.jpg",
positiveX:
"https://upload.wikimedia.org/wikipedia/commons/d/db/360%C2%B0_Phnom_Penh_%28Central_Market_2022%29_%28front%29.jpg",
},
transform,
credit,
});
viewer.scene.camera.lookAt(position, new Cesium.HeadingPitchRange(0, 0, 2));
removeAndDestroyPanoramas();
viewer.scene.primitives.add(cubeMapPanorama);
// 可选:为此模式恢复默认导航
controller.enableZoom = true;
controller.enableTranslate = true;
};
信息:要将航向/俯仰/翻滚元数据纳入变换矩阵,请参考步骤 2 中的示例。
提示: 如果立方体面出现交换/旋转的情况,请检查:
- 面的命名约定(positiveX、negativeX 等)
- 本地坐标系轴的选择(此处为 north/down)
金边的立方体贴图全景图。创建一个变换矩阵来在场景中正确朝向立方体贴图。
—
步骤 4:移除(并可选销毁)全景图元以清理
当你使用完一个全景图后,可能需要将其移除(例如,切换回”世界视图”,或在新的位置加载不同的全景图)。
function removeAndDestroyPanoramas() {
const primitives = viewer.scene.primitives;
for (let i = primitives.length - 1; i >= 0; i--) {
const primitive = primitives.get(i);
const isPanorama =
primitive instanceof Cesium.CubeMapPanorama ||
primitive instanceof Cesium.EquirectangularPanorama;
if (isPanorama) {
// 从场景中移除
primitives.remove(primitive);
// 可选:如果你的 CesiumJS 版本暴露了 destroy() 方法,
// 调用它以释放 GPU 资源。
// if (typeof primitive.destroy === "function") {
// primitive.destroy();
// }
}
}
}
如果要切换回”世界视图”,重置相机和地球默认设置:
function exitPanoramaMode() {
// 重新启用地球/世界上下文
viewer.scene.globe.show = true;
controller.enableZoom = true;
controller.enableTranslate = true;
viewer.scene.camera.lookAtTransform(Cesium.Matrix4.IDENTITY);
}
步骤 5:沉浸式全景体验的相机控制
要在场景中查看全景图,使用 camera.lookAt 将相机放置在全景图中心。为了获得沉浸式体验,通常建议允许旋转和倾斜,但禁用平移和缩放,使用户固定在全景图原点。
信息: 等距柱状投影设置禁用了缩放和平移以将用户”固定”在全景图内部,而立方体贴图设置恢复了默认导航(缩放/平移)以便更自由地探索。请选择最适合你应用用户体验的行为。
推荐的控制器设置
你已经在步骤 2 和 3 中设置了 camera.lookAt,以下代码片段明确了控制器行为:
const controller = viewer.scene.screenSpaceCameraController;
controller.enableRotate = true;
controller.enableTilt = true;
controller.enableTranslate = false;
controller.enableZoom = false;
可选:通过调整视场角(FOV)实现”缩放”
在全景模式下,鼠标滚轮自然地缩放/扩大相机的 FOV(而不是平移相机)。如果你想在保持 enableZoom = false 的情况下使用滚轮缩放,可以调整相机的视场角:
const handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
const minFov = Cesium.Math.toRadians(20.0);
const maxFov = Cesium.Math.toRadians(100.0);
const zoomSpeed = 0.05;
function enableFieldOfViewAdjustment() {
handler.setInputAction(
function (movement) {
const camera = viewer.camera;
const frustum = camera.frustum;
let fov = frustum.fov;
const delta = movement;
if (delta < 0) {
fov *= 1.0 + zoomSpeed; // 放大(更窄的视野)
} else {
fov *= 1.0 - zoomSpeed; // 缩小(更宽的视野)
}
fov = Cesium.Math.clamp(fov, minFov, maxFov);
frustum.fov = fov;
},
Cesium.ScreenSpaceEventType.WHEEL,
);
}
enableFieldOfViewAdjustment();
完整代码(Sandcastle)
点击 + 拖动进行交互
探索并尝试 全景图 Sandcastle。
故障排除
全景图为黑色,不渲染?
- 检查图片主机的 CORS 头信息;WebGL 在没有正确 CORS 的情况下无法采样跨域纹理
全景图旋转了或朝向错误?
- 确认在构建变换矩阵时使用了正确的本地坐标系和朝向元数据(航向/俯仰/翻滚)
想知道为什么可以”离开”全景图?
- 禁用平移/缩放控制(或将相机固定在全景图中心),使交互保持沉浸感
资源
- CesiumJS 等距柱状投影全景图文档:在 CesiumJS 场景中显示单张等距柱状投影(360×180)全景图的 API 参考
- CesiumJS 立方体贴图全景图文档:在 CesiumJS 场景中显示六面立方体贴图全景图的 API 参考
- Google Street View Cesium 文档:通过
GoogleStreetViewCubeMapPanoramaProvider加载 Google Street View 影像到 CesiumJS 全景图的 API 参考 - Google Street View Sandcastle:在 CesiumJS 中体验 Google Street View 的交互式示例和实时代码编辑器
- 全景图 Sandcastle:体验等距柱状投影和立方体贴图全景图的交互式示例和实时代码编辑器
- CesiumJS 文档:使用 CesiumJS 构建 3D 地理空间应用的核心 API 参考和指南
- CesiumJS 相机和交互控制:配置沉浸式体验的相机行为,包括旋转、倾斜、受限导航和视场角调整的详细信息
- Cesium ion 文档:管理访问令牌、资产和第三方数据集成
- CesiumJS 全景影像介绍
其他全景数据源
除 Google Street View 外,还有多个公共和开放数据源提供可用于 CesiumJS 全景图的全景影像。
地理定位的街景影像 API
这些平台提供地理参考的街景影像,可按位置或空间范围查询,并集成到自定义全景工作流中:
- Google Street View Cesium 文档:通过
GoogleStreetViewCubeMapPanoramaProvider加载 Google Street View 影像到 CesiumJS 全景图的 API 参考 - Mapillary:大量众包、地理定位的街景影像集合,提供基于位置、边界框和元数据发现图像的 API
- Panoramax:一个开放的、联邦式平台,用于托管和访问地理定位的街景照片。Panoramax 提供基于标准(STAC)的 API,用于在公共和自托管实例中发现影像及关联元数据
非地理定位或松散地理参考的全景图
这些来源适用于室内场景或不需要精确定位的一般环境上下文:
- Wikimedia Commons(360° 全景图):大量自由许可的 360° 全景影像集合,包括等距柱状投影和立方体贴图资源,适用于演示、示例和教育用途
- Poly Haven HDRIs:高质量等距柱状投影 HDR 全景图,常用于背景上下文。虽未地理定位,但适用于室内场景、天空盒和非特定位置的全景体验
总结
全景影像实现了沉浸式的街景和场地级别可视化,同时保留了完整 3D 地理空间场景的空间上下文。使用 CesiumJS,你可以无缝集成等距柱状投影和立方体贴图全景图,在地球上精确定位,并将用户直接置于体验之中。
这一能力对于受益于人类尺度上下文的工作流尤其强大,例如基础设施巡检、资产状况评估、场地规划和态势感知。通过将全景图与 CesiumJS 的其他图元(如地形、3D Tiles、模型和分析覆盖层)结合使用,你可以弥合地理空间数据与实地视觉理解之间的鸿沟。
cesium.com/learn 上的内容和代码示例根据 Apache 2.0 许可证 提供。你可以在商业或非商业应用中使用这些代码示例。
专业服务
奇小狐工作室 – 3D 数据处理专家
- 高斯溅射(Gaussian Splat)PLY 数据处理
- 大批量点云数据处理
- 3D Tiles 格式转换与优化
联系方式:微信
Elusive57