Cesium5--官方地形
本文介绍了Cesium三维地球开发环境的配置和核心功能实现。首先说明了两种运行方式(Python http.server和npm),并给出了一个加载3DTiles模型的典型代码示例。文章详细解析了Cesium的核心类:Viewer(地球容器)、Scene(场景控制)、Camera(视角操作)、Globe(地球本体)等。重点分析了地形系统的实现,包括多种地形数据源的切换(Cesium World T
1 环境安装
直接下载的cesium最新版本,现在的版本是1.133

在运行的时候要注意,如果使用python http.server,要放在Apps外面,也就是最外层执行。
不过官方推荐是npm。
npm install
npm start
之后访问http://localhost:8080/Apps/Sandcastle/index.html
不过我还是习惯python哈。。。
2 典型的cesium程序
这里以之前的glb模型的例子为例,来自:https://blog.csdn.net/fanged/article/details/151680096
<div id="cesiumContainer"></div>
<script>
// 初始化 Cesium Viewer
Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIzYjVkMmRhYy03OGMxLTQwM2EtYWY0Ny00MDM4YjhjZmVkNzIiLCJpZCI6MzA0Mzc4LCJpYXQiOjE3NDc3MzE5NDN9.kzP84v1ibzx6iJP_ESqc-PiJ6-fTbHQvCR2KMc9lvws';
const viewer = new Cesium.Viewer("cesiumContainer", {
terrainProvider: new Cesium.EllipsoidTerrainProvider()
});
// 加载 3D Tiles (指向 rootTileset.json)
const tileset = new Cesium.Cesium3DTileset({
url: "data/rootTileset.json" // 相对路径,index.html 同级目录下的 data 文件夹
});
viewer.scene.primitives.add(tileset);
tileset.readyPromise.then(function() {
const longitude = 139.7101;
const latitude = 35.6852;
const height = 50.0;
const position = Cesium.Cartesian3.fromDegrees(longitude, latitude, height);
// 设置旋转角度(弧度制)
const heading = Cesium.Math.toRadians(90); // 水平方向
const pitch = Cesium.Math.toRadians(0); // 上下倾斜
const roll = Cesium.Math.toRadians(300); // 翻滚
const hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll);
const modelMatrix = Cesium.Transforms.headingPitchRollToFixedFrame(position, hpr);
// 如果需要缩放,可以加这一句(比如缩小 0.1 倍)
const scale = 0.1;
tileset.modelMatrix = Cesium.Matrix4.multiplyByUniformScale(modelMatrix, scale, new Cesium.Matrix4());
// 相机飞过去
viewer.zoomTo(tileset);
});
</script>
可以看到,一开始初始化viewer,然后用Cesium3DTileset加载3dtiles模型,之后加到scene.primitives,最后用viewer控制视角。
把cesium的几个核心类简单介绍如下

2.1 Viewer类
作用:一键生成一个完整的地球应用。包含内容:相机、图层管理、UI 控件(比例尺、时间轴、动画控件)、场景(Scene)等。使用场景:绝大多数入门代码都是 new Cesium.Viewer("container") 开始的。
const viewer = new Cesium.Viewer("cesiumContainer", {
terrain: Cesium.Terrain.fromWorldTerrain()
});
2.2 Cesium.Scene类
作用:表示 3D 场景,控制渲染、光照、雾效、天空盒等。获取方式:viewer.scene
常用属性:
scene.globe → 地球本体(椭球 + 地形)
scene.primitives → 原语(模型、几何体等)
scene.postProcessStages → 后处理特效(比如黑白滤镜、辉光)
低层渲染控制核心。
2.3 Cesium.Camera
作用:控制视角,决定你在地球上的“眼睛”位置。获取方式:viewer.camera
常用方法:
camera.flyTo() → 动画飞行到某个位置
camera.lookAt(target, offset) → 以某点为中心环视
camera.setView() → 立即跳转
2.4 Cesium.Globe
作用:地球本体,包含 椭球 + 影像 + 地形。获取方式:viewer.scene.globe
常用设置:
globe.enableLighting = true → 按太阳光照显示昼夜
globe.depthTestAgainstTerrain = true → 启用地形遮挡效果
2.5 Cesium.Entity & Cesium.EntityCollection
作用:高层抽象的地理对象。
支持内容:点(billboard)、线(polyline)、面(polygon)、模型(3D tiles、GLTF)等。
viewer.entities.add({
name: "My Point",
position: Cesium.Cartesian3.fromDegrees(116.39, 39.9, 100),
point: { pixelSize: 10, color: Cesium.Color.RED }
});
2.6 Cesium.Primitive & Cesium.PrimitiveCollection
作用:更底层的几何渲染对象,比 Entity 更接近 WebGL。用法:一般加载大规模模型(如 3D Tiles)或自定义几何体时用。
const primitive = new Cesium.Primitive({
geometryInstances: new Cesium.GeometryInstance({ geometry: ... }),
appearance: new Cesium.PerInstanceColorAppearance()
});
viewer.scene.primitives.add(primitive);
2.7 Cesium.DataSource
作用:外部数据的入口,比如 CZML、GeoJSON、KML。
Cesium.GeoJsonDataSource.load("data.geojson").then(function(ds) {
viewer.dataSources.add(ds);
viewer.zoomTo(ds);
});
2.8 Cesium.Cesium3DTileset
作用:3D Tiles 格式的数据集(大规模建筑、点云、城市模型)。
const tileset = await Cesium.Cesium3DTileset.fromUrl("tileset.json");
viewer.scene.primitives.add(tileset);
viewer.zoomTo(tileset);
3 地形代码
这里主要分析的代码是地形,也就是示例代码中的http://127.0.0.1:8000/Apps/Sandcastle/gallery/Terrain.html
核心代码整理如下:
const viewer = new Cesium.Viewer("cesiumContainer", {
terrain: Cesium.Terrain.fromWorldTerrain({
requestWaterMask: true,
requestVertexNormals: true,
}),
});
// set lighting to true
viewer.scene.globe.enableLighting = true;
// adjust time so scene is lit by sun
viewer.clock.currentTime = Cesium.JulianDate.fromIso8601("2023-01-01T00:00:00");
// setup alternative terrain providers
const ellipsoidProvider = new Cesium.EllipsoidTerrainProvider();
// Sine wave
const customHeightmapWidth = 32;
const customHeightmapHeight = 32;
const customHeightmapProvider = new Cesium.CustomHeightmapTerrainProvider({
width: customHeightmapWidth,
height: customHeightmapHeight,
callback: function (x, y, level) {
const width = customHeightmapWidth;
const height = customHeightmapHeight;
const buffer = new Float32Array(width * height);
for (let yy = 0; yy < height; yy++) {
for (let xx = 0; xx < width; xx++) {
const u = (x + xx / (width - 1)) / Math.pow(2, level);
const v = (y + yy / (height - 1)) / Math.pow(2, level);
const heightValue = 4000 * (Math.sin(8000 * v) * 0.5 + 0.5);
const index = yy * width + xx;
buffer[index] = heightValue;
}
}
return buffer;
},
});
Sandcastle.addToolbarMenu(
[
{
text: "CesiumTerrainProvider - Cesium World Terrain",
onselect: function () {
viewer.scene.setTerrain(
Cesium.Terrain.fromWorldTerrain({
requestWaterMask: true,
requestVertexNormals: true,
}),
);
viewer.scene.globe.enableLighting = true;
},
},
{
text: "CesiumTerrainProvider - Cesium World Terrain - no effects",
onselect: function () {
viewer.scene.setTerrain(Cesium.Terrain.fromWorldTerrain());
},
},
{
text: "CesiumTerrainProvider - Cesium World Terrain w/ Lighting",
onselect: function () {
viewer.scene.setTerrain(
Cesium.Terrain.fromWorldTerrain({
requestVertexNormals: true,
}),
);
viewer.scene.globe.enableLighting = true;
},
},
{
text: "CesiumTerrainProvider - Cesium World Terrain w/ Water",
onselect: function () {
viewer.scene.setTerrain(
Cesium.Terrain.fromWorldTerrain({
requestWaterMask: true,
}),
);
},
},
{
text: "EllipsoidTerrainProvider",
onselect: function () {
viewer.terrainProvider = ellipsoidProvider;
},
},
{
text: "CustomHeightmapTerrainProvider",
onselect: function () {
viewer.terrainProvider = customHeightmapProvider;
},
},
{
text: "VRTheWorldTerrainProvider",
onselect: function () {
viewer.scene.setTerrain(
new Cesium.Terrain(
Cesium.VRTheWorldTerrainProvider.fromUrl(
"http://www.vr-theworld.com/vr-theworld/tiles1.0.0/73/",
{
credit: "Terrain data courtesy VT MÄK",
},
),
),
);
},
},
{
text: "ArcGISTerrainProvider",
onselect: function () {
viewer.scene.setTerrain(
new Cesium.Terrain(
Cesium.ArcGISTiledElevationTerrainProvider.fromUrl(
"https://elevation3d.arcgis.com/arcgis/rest/services/WorldElevation3D/Terrain3D/ImageServer",
),
),
);
},
},
],
"terrainMenu",
);
Sandcastle.addDefaultToolbarMenu(
[
{
text: "Mount Everest",
onselect: function () {
lookAtMtEverest();
},
},
{
text: "Half Dome",
onselect: function () {
const target = new Cesium.Cartesian3(
-2489625.0836225147,
-4393941.44443024,
3882535.9454173897,
);
const offset = new Cesium.Cartesian3(
-6857.40902037546,
412.3284835694358,
2147.5545426812023,
);
viewer.camera.lookAt(target, offset);
viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY);
},
},
{
text: "San Francisco Bay",
onselect: function () {
const target = new Cesium.Cartesian3(
-2708814.85583248,
-4254159.450845907,
3891403.9457429945,
);
const offset = new Cesium.Cartesian3(
70642.66030209465,
-31661.517948317807,
35505.179997143336,
);
viewer.camera.lookAt(target, offset);
viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY);
},
},
],
"zoomButtons",
);
let terrainSamplePositions;
function lookAtMtEverest() {
const target = new Cesium.Cartesian3(
300770.50872389384,
5634912.131394585,
2978152.2865545116,
);
const offset = new Cesium.Cartesian3(
6344.974098678562,
-793.3419798081741,
2499.9508860763162,
);
viewer.camera.lookAt(target, offset);
viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY);
}
function sampleTerrainSuccess(terrainSamplePositions) {
const ellipsoid = Cesium.Ellipsoid.WGS84;
//By default, Cesium does not obsure geometry
//behind terrain. Setting this flag enables that.
viewer.scene.globe.depthTestAgainstTerrain = true;
viewer.entities.suspendEvents();
viewer.entities.removeAll();
for (let i = 0; i < terrainSamplePositions.length; ++i) {
const position = terrainSamplePositions[i];
viewer.entities.add({
name: position.height.toFixed(1),
position: ellipsoid.cartographicToCartesian(position),
billboard: {
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
scale: 0.7,
image: "../images/facility.gif",
},
label: {
text: position.height.toFixed(1),
font: "10pt monospace",
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
pixelOffset: new Cesium.Cartesian2(0, -14),
fillColor: Cesium.Color.BLACK,
outlineColor: Cesium.Color.BLACK,
showBackground: true,
backgroundColor: new Cesium.Color(0.9, 0.9, 0.9, 0.7),
backgroundPadding: new Cesium.Cartesian2(4, 3),
},
});
}
viewer.entities.resumeEvents();
}
function createGrid(rectangleHalfSize) {
const gridWidth = 41;
const gridHeight = 41;
const everestLatitude = Cesium.Math.toRadians(27.988257);
const everestLongitude = Cesium.Math.toRadians(86.925145);
const e = new Cesium.Rectangle(
everestLongitude - rectangleHalfSize,
everestLatitude - rectangleHalfSize,
everestLongitude + rectangleHalfSize,
everestLatitude + rectangleHalfSize,
);
const terrainSamplePositions = [];
for (let y = 0; y < gridHeight; ++y) {
for (let x = 0; x < gridWidth; ++x) {
const longitude = Cesium.Math.lerp(e.west, e.east, x / (gridWidth - 1));
const latitude = Cesium.Math.lerp(e.south, e.north, y / (gridHeight - 1));
const position = new Cesium.Cartographic(longitude, latitude);
terrainSamplePositions.push(position);
}
}
return terrainSamplePositions;
}
Sandcastle.addToggleButton(
"Enable Lighting",
viewer.scene.globe.enableLighting,
function (checked) {
viewer.scene.globe.enableLighting = checked;
},
);
Sandcastle.addToggleButton(
"Enable fog",
viewer.scene.fog.enabled,
function (checked) {
viewer.scene.fog.enabled = checked;
},
);
Sandcastle.addToolbarButton(
"Sample Everest Terrain at Level 9",
function () {
const terrainSamplePositions = createGrid(0.005);
Promise.resolve(
Cesium.sampleTerrain(viewer.terrainProvider, 9, terrainSamplePositions),
).then(sampleTerrainSuccess);
lookAtMtEverest();
},
"sampleButtons",
);
Sandcastle.addToolbarButton(
"Sample Most Detailed Everest Terrain",
function () {
if (!Cesium.defined(viewer.terrainProvider.availability)) {
window.alert(
"sampleTerrainMostDetailed is not supported for the selected terrain provider",
);
return;
}
const terrainSamplePositions = createGrid(0.0005);
Promise.resolve(
Cesium.sampleTerrainMostDetailed(
viewer.terrainProvider,
terrainSamplePositions,
),
).then(sampleTerrainSuccess);
lookAtMtEverest();
},
"sampleButtons",
);
3.1 初始化
const viewer = new Cesium.Viewer("cesiumContainer", {
terrain: Cesium.Terrain.fromWorldTerrain({
requestWaterMask: true,
requestVertexNormals: true,
}),
});
默认加载 Cesium World Terrain (Cesium ion 提供的全球高程数据)。
requestWaterMask: true → 在水体区域绘制动态水面效果。
requestVertexNormals: true → 用于更真实的地形光照(比如阴影、坡面朝向)。
viewer.scene.globe.enableLighting = true;
viewer.clock.currentTime = Cesium.JulianDate.fromIso8601("2023-01-01T00:00:00");
打开地形光照(根据太阳位置计算阴影效果)。
固定时间 → 方便调试,不然光照会随着系统时间走。
3.2 地形
初始化的地形是terrain: Cesium.Terrain.fromWorldTerrain
后面提供了几种替换的。分别是
CesiumTerrainProvider - Cesium World Terrain
就是默认地形

CesiumTerrainProvider - Cesium World Terrain - no effects
在模型地形上去掉了requestWaterMask,requestVertexNormals这两个参数。
CesiumTerrainProvider - Cesium World Terrain w/ Lighting
增加了requestVertexNormals: true,,viewer.scene.globe.enableLighting = true;
CesiumTerrainProvider - Cesium World Terrain w/ Water
增加了requestWaterMask: true。
EllipsoidTerrainProvider
const ellipsoidProvider = new Cesium.EllipsoidTerrainProvider();
提供基础球体,所有高程都是基于WGS84,没有高低起伏。

VRTheWorldTerrainProvider
Cesium.VRTheWorldTerrainProvider.fromUrl(
"http://www.vr-theworld.com/vr-theworld/tiles1.0.0/73/",
{
credit: "Terrain data courtesy VT MÄK",
},
VT MÄK 公司提供的 VR-TheWorld 地形数据,这是一种高精度的商业地形服务,提供全球范围的高分辨率地形数据。
不过这个好像不是免费的,所以在我这边没有显示。。。
ArcGISTerrainProvider
Cesium.ArcGISTiledElevationTerrainProvider.fromUrl(
"https://elevation3d.arcgis.com/arcgis/rest/services/WorldElevation3D/Terrain3D/ImageServer",
),
Esri(易智瑞)提供的 WorldElevation3D 地形数据,这是一种高质量的全球三维高程地形服务,由知名地理信息公司 Esri 提供支持。
看着和Cesium默认的地形好像差不多。。。
CustomHeightmapTerrainProvider
搞了一个波浪地形。
const customHeightmapProvider = new Cesium.CustomHeightmapTerrainProvider({
width: customHeightmapWidth,
height: customHeightmapHeight,
callback: function (x, y, level) {
const width = customHeightmapWidth;
const height = customHeightmapHeight;
const buffer = new Float32Array(width * height);
for (let yy = 0; yy < height; yy++) {
for (let xx = 0; xx < width; xx++) {
const u = (x + xx / (width - 1)) / Math.pow(2, level);
const v = (y + yy / (height - 1)) / Math.pow(2, level);
const heightValue = 4000 * (Math.sin(8000 * v) * 0.5 + 0.5);
const index = yy * width + xx;
buffer[index] = heightValue;
}
}
return buffer;
},
});

3.3 跳转
以珠峰为例
function lookAtMtEverest() {
const target = new Cesium.Cartesian3(
300770.50872389384,
5634912.131394585,
2978152.2865545116,
);
const offset = new Cesium.Cartesian3(
6344.974098678562,
-793.3419798081741,
2499.9508860763162,
);
viewer.camera.lookAt(target, offset);
viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY);
这里的坐标是 WGS84。
target是中心点,offset是观察角度。。
3.4 其它
高程
Cesium.sampleTerrain(viewer.terrainProvider, 9, terrainSamplePositions),
短时间还用不到这个,所以就不细看了。。。
Sandcastle
演示的辅助类,估计后面也是不会用,跳过。。。
更多推荐

所有评论(0)