原文链接及内容

效果如下视频所示:

示例代码如下:

在自定义材质用到了下述两种材质类型及其uniforms: ElevationRampWaterMask

色带如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
const viewer = new Cesium.Viewer("cesiumContainer", {
geocoder: false,
sceneModePicker: false,
homeButton: false,
navigationHelpButton: false,
baseLayerPicker: false,
navigationInstructionsInitiallyVisible: false,
fullscreenButton: false,
selectionIndicator: false,
skyBox: false,
timeline: false,
animation: false,
shouldAnimate: true,
terrain: Cesium.Terrain.fromWorldTerrain({
requestVertexNormals: true, // 用于(渲染)坡面(山体)阴影,这里的need for翻译为用于...需要
requestWaterMask: true, // 用于区分陆地和水域
}),
});

viewer.cesiumWidget.creditContainer.style.display = "none";

// 创建一个地球材质,仅用于陆地高程着色
const customElevationMaterial = new Cesium.Material({
//fabric属性:用于生成材质的 fabric JSON,该属性为必须属性,其他为可选属性
fabric: {
type: "ElevationLand",
materials: {
waterMaskMaterial: {
type: "WaterMask",
},
elevationRampMaterial: {
type: "ElevationRamp",
},
},
components: {
diffuse: "elevationRampMaterial.diffuse",
alpha: "1.0 - waterMaskMaterial.alpha", // 我们需要水掩膜的逆运算来为陆地着色
},
},
//translucent属性:当值 true 或返回 true 的函数,几何在使用此材质时,预期会呈现半透明。
translucent: false,
});

const minHeight = -414.0; // 近似死海的高程
const maxHeight = 8777.0; // 近似珠穆朗玛峰的高程,everest翻译为难以做到的事,是西方人对珠穆朗玛峰的称呼
const elevationRamp = [0.0, 0.045, 0.45, 0.5, 0.55, 1.0];
function getColorRamp() {
const ramp = document.createElement("canvas");
ramp.width = 100;
ramp.height = 1;
const ctx = ramp.getContext("2d");

const values = elevationRamp;

//创建线性渐变样式
const grd = ctx.createLinearGradient(0, 0, 100, 0);

// See https://gis.stackexchange.com/questions/25099/choosing-colour-ramp-to-use-for-elevation
grd.addColorStop(values[0], "#344f31");
grd.addColorStop(values[1], "#5b8742");
grd.addColorStop(values[2], "#e6daa5");
grd.addColorStop(values[3], "#fdc771");
grd.addColorStop(values[4], "#b99d89");
grd.addColorStop(values[5], "#f0f0f0");

ctx.fillStyle = grd;
ctx.fillRect(0, 0, 100, 1);

return ramp;
}

const globe = viewer.scene.globe;
const material = customElevationMaterial;
const shadingUniforms = material.materials.elevationRampMaterial.uniforms;
shadingUniforms.minimumHeight = minHeight;
shadingUniforms.maximumHeight = maxHeight;
shadingUniforms.image = getColorRamp();

globe.material = material;
//showWaterEffect属性:若为 true,则在地球水体覆盖区域显示动态波浪效果;否则为 false。若 terrainProvider 未提供水体遮罩,则忽略此属性。
globe.showWaterEffect = false;
globe.enableLighting = true;//开启光照
globe.maximumScreenSpaceError = 0.5; // 加载更高分辨率的图块以获得更细致的阴影效果

/**
* 为场景添加类似山体阴影效果的照明,
* 详情请见:https://pro.arcgis.com/en/pro-app/latest/tool-reference/3d-analyst/how-hillshade-works.htm
*/
const scene = viewer.scene;
scene.light = new Cesium.DirectionalLight({
//direction属性表示:光的发射方向。
direction: new Cesium.Cartesian3(1, 0, 0), // 每帧更新
});

// 根据相机位置更新光源位置
//这里的scratch normal结合语境应翻译为初始法线
const scratchNormal = new Cesium.Cartesian3();
scene.preRender.addEventListener(function (scene, time) {
const surfaceNormal = globe.ellipsoid.geodeticSurfaceNormal(
scene.camera.positionWC,
scratchNormal
);
//Cartesian3.negate()方法:对提供的笛卡尔坐标取反。
const negativeNormal = Cesium.Cartesian3.negate(surfaceNormal, surfaceNormal);
//Cartesian3.normalize()方法:计算所提供笛卡尔坐标的归一化形式。
/**
* scene.camera.rightWC:获取摄像机在世界坐标系(world coordinates)中的右方向向量
*/
scene.light.direction = Cesium.Cartesian3.normalize(
Cesium.Cartesian3.add(negativeNormal, scene.camera.rightWC, surfaceNormal),
scene.light.direction
);
});