原文链接及内容

效果实现如下视频所示:

示例代码如下:

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
<style>
@import url(../templates/bucket.css);
.cesium-performanceDisplay-defaultContainer {
top: 10px;
}
</style>
<div id="cesiumContainer" class="fullSize"></div>
<div id="loadingOverlay"><h1>数据加载中...</h1></div>
<div id="toolbar">
<table>
<tbody>
<tr>
<td>启用环境光遮蔽(效果)</td>
<td><input type="checkbox" data-bind="checked: show" /></td>
</tr>
<tr>
<td>仅启用环境光遮蔽(效果)</td>
<td>
<input type="checkbox" data-bind="checked: ambientOcclusionOnly" />
</td>
</tr>
<tr>
<td>(遮蔽)强度</td>
<td>
<input
type="range"
min="1"
max="10"
step="1"
data-bind="value: intensity, valueUpdate: 'input'"
/>
</td>
</tr>
<tr>
<td>最大采样距离</td>
<td>
<input
type="range"
min="0"
max="1"
step="0.01"
data-bind="value: lengthCap, valueUpdate: 'input'"
/>
</td>
</tr>
<tr>
<td>(每个方向)采样步数</td>
<td>
<input
type="range"
min="1"
max="64"
step="1"
data-bind="value: stepCount, valueUpdate: 'input'"
/>
</td>
</tr>
<tr>
<td>采样方向数量</td>
<td>
<input
type="range"
min="1"
max="16"
step="1"
data-bind="value: directionCount, valueUpdate: 'input'"
/>
</td>
</tr>
<tr>
<td>采样偏差</td>
<td>
<input
type="range"
min="0"
max="1"
step="0.01"
data-bind="value: bias, valueUpdate: 'input'"
/>
</td>
</tr>
</tbody>
</table>
</div>
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
const viewer = new Cesium.Viewer("cesiumContainer", {
sceneModePicker: false,
homeButton: false,
navigationHelpButton: false,
baseLayerPicker: false,
navigationInstructionsInitiallyVisible: false,
animation: false,
timeline: false,
fullscreenButton: false,
selectionIndicator: false,
skyBox: false,
shouldAnimate: true,
geocoder: false,
});

viewer.cesiumWidget.creditContainer.style.display = "none"; //隐藏版权信息
viewer.scene.debugShowFramesPerSecond = true; //添加帧速显示

const { canvas, camera, clock, scene } = viewer;

camera.frustum.near = 1.0;
scene.debugShowFramesPerSecond = true;

clock.currentTime = Cesium.JulianDate.fromIso8601("2022-08-01T00:00:00Z");

if (!Cesium.PostProcessStageLibrary.isAmbientOcclusionSupported(viewer.scene)) {
window.alert(
"这个浏览器不支持环境光遮蔽后期处理(post process)。",
);
}

const viewModel = {
show: true,
ambientOcclusionOnly: false,
intensity: 3.0,
bias: 0.1,
lengthCap: 0.26,
directionCount: 8,
stepCount: 32,
};

Cesium.knockout.track(viewModel);
const toolbar = document.getElementById("toolbar");
Cesium.knockout.applyBindings(viewModel, toolbar);
for (const name in viewModel) {
if (viewModel.hasOwnProperty(name)) {
Cesium.knockout.getObservable(viewModel, name).subscribe(updatePostProcess);
}
}

/**
* 该函数通过UI控件动态调整环境光遮蔽的渲染参数,
* 实现实时效果预览与优化,提升场景的视觉真实感。
*/
function updatePostProcess() {
/**
* 获取场景中的环境光遮蔽后处理组合阶段对象
* ambientOcclusion的类为Cesium.PostProcessStageComposite
* 其uniforms属性:后处理阶段(post-process stages)的统一值别名
*/
const ambientOcclusion = scene.postProcessStages.ambientOcclusion;
// enabled属性:准备就绪后是否执行此后期处理阶段。
ambientOcclusion.enabled =
Boolean(viewModel.show) || Boolean(viewModel.ambientOcclusionOnly);
// 设置是否仅显示环境光遮蔽(不与其他光照混合)
ambientOcclusion.uniforms.ambientOcclusionOnly = Boolean(
viewModel.ambientOcclusionOnly,
);
//intensity:控制遮蔽的明暗强度,值越大阴影越深。
ambientOcclusion.uniforms.intensity = Number(viewModel.intensity);
//bias: 避免物体表面因采样误差产生不正确的自阴影。
ambientOcclusion.uniforms.bias = Number(viewModel.bias);
//lengthCap: 限制采样距离,平衡效果精度与性能。
ambientOcclusion.uniforms.lengthCap = Number(viewModel.lengthCap);// 最大采样距离
//directionCount 与 stepCount: 联合决定采样质量,方向数和步数越多效果越细腻,但计算开销越大。
ambientOcclusion.uniforms.directionCount = Number(viewModel.directionCount);// 采样方向数量
ambientOcclusion.uniforms.stepCount = Number(viewModel.stepCount);// 每个方向的采样步数
}

updatePostProcess();

camera.position = new Cesium.Cartesian3(
1234127.2294710164,
-5086011.666443127,
3633337.0413351045,
);
camera.direction = new Cesium.Cartesian3(
-0.5310064396211631,
-0.30299013818088416,
-0.7913464078682514,
);
camera.right = new Cesium.Cartesian3(
-0.8468592075426076,
0.1574051185945647,
0.507989282604011,
);

//cross方法:计算垂直于两个向量的法线向量
camera.up = Cesium.Cartesian3.cross(
camera.right,
camera.direction,
new Cesium.Cartesian3(),
);

try {
// 由 Bentley Systems 提供的发电厂设计模型
const tileset = await Cesium.Cesium3DTileset.fromIonAssetId(2464651);
scene.primitives.add(tileset);
} catch (error) {
console.log(`Error loading tileset: ${error}`);
}