原文链接及内容

: 由于个人的Cesium Ion中没有官方示例中的数据,因此仅在官方提供的在线编辑器中进行了学习、修改。

实现效果如下视频所示:

示例代码如下:

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
<style>
@import url(../templates/bucket.css);
#toolbar {
background: rgba(42, 42, 42, 0.8);
padding: 4px;
border-radius: 4px;
}
#toolbar input {
vertical-align: middle;
padding-top: 2px;
padding-bottom: 2px;
}
#toolbar .header {
font-weight: bold;
}
.cesium-performanceDisplay-defaultContainer {
top: 10px;
}
</style>
<div id="cesiumContainer" class="fullSize"></div>
<div id="loadingOverlay"><h1>加载中...</h1></div>
<div id="toolbar">
<select data-bind="options: exampleTypes, value: currentExampleType"></select>
<table>
<tbody>
<tr>
<td>最大屏幕空间误差</td>
<td>
<input type="range" min="0.0" max="64.0" step="0.1" data-bind="value: maximumScreenSpaceError, valueUpdate: 'input'">
<input type="text" size="5" data-bind="value: maximumScreenSpaceError">
</td>
</tr>
<tr>
<td class="header">衰减</td>
</tr>
<tr>
<td>几何误差比例</td>
<td>
<input type="range" min="0.0" max="2.0" step="0.1" data-bind="value: geometricErrorScale, valueUpdate: 'input'">
<input type="text" size="5" data-bind="value: geometricErrorScale">
</td>
</tr>
<tr>
<td>最大衰减</td>
<td>
<input type="range" min="0.0" max="32.0" step="1.0" data-bind="value: maximumAttenuation, valueUpdate: 'input'">
<input type="text" size="5" data-bind="value: maximumAttenuation">
</td>
</tr>
<tr>
<td>基础分辨率</td>
<td>
<input type="range" min="0.0" max="10.0" step="0.01" data-bind="value: baseResolution, valueUpdate: 'input'">
<input type="text" size="5" data-bind="value: baseResolution">
</td>
</tr>
<tr>
<td class="header">眼球(视点)穹顶照明(EDL)</td>
</tr>
<tr>
<td>EDL强度</td>
<td>
<input type="range" min="0.0" max="10.0" step="0.1" data-bind="value: eyeDomeLightingStrength, valueUpdate: 'input'">
<input type="text" size="5" data-bind="value: eyeDomeLightingStrength">
</td>
</tr>
<tr>
<td>EDL半径</td>
<td>
<input type="range" min="0.0" max="10.0" step="0.1" data-bind="value: eyeDomeLightingRadius, valueUpdate: 'input'">
<input type="text" size="5" data-bind="value: eyeDomeLightingRadius">
</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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
const viewer = new Cesium.Viewer("cesiumContainer", {
geocoder: false,
sceneModePicker: false,
homeButton: false,
navigationHelpButton: false,
baseLayerPicker: false,
navigationInstructionsInitiallyVisible: false,
animation: false,
timeline: false,
fullscreenButton: false,
selectionIndicator: false,
skyBox: false,
shouldAnimate: true,
terrain: Cesium.Terrain.fromWorldTerrain(),
});

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

const scene = viewer.scene;
let viewModelTileset;

if (!Cesium.PointCloudShading.isSupported(scene)) {
window.alert("该浏览器不支持点云着色");
}

function reset() {
viewer.scene.primitives.remove(viewModelTileset);
viewModelTileset = undefined;
}

/**
* St Helens:圣海伦斯,它是英国英格兰默西赛德郡的一个镇。
*/
const pointClouds = ["圣海伦斯小镇", "教堂"];
const viewModel = {
exampleTypes: pointClouds,
currentExampleType: pointClouds[0],
maximumScreenSpaceError: 16.0,
geometricErrorScale: 1.0,
maximumAttenuation: 0, // 该值等同于undefined
baseResolution: 0, // 该值等同于undefined
eyeDomeLightingStrength: 1.0,
eyeDomeLightingRadius: 1.0,
};

function tilesetToViewModel(tileset) {
viewModelTileset = tileset;

const pointCloudShading = tileset.pointCloudShading;
viewModel.maximumScreenSpaceError = tileset.maximumScreenSpaceError;
viewModel.geometricErrorScale = pointCloudShading.geometricErrorScale;
viewModel.maximumAttenuation = pointCloudShading.maximumAttenuation
? pointCloudShading.maximumAttenuation
: 0;
viewModel.baseResolution = pointCloudShading.baseResolution
? pointCloudShading.baseResolution
: 0;
viewModel.eyeDomeLightingStrength = pointCloudShading.eyeDomeLightingStrength;
viewModel.eyeDomeLightingRadius = pointCloudShading.eyeDomeLightingRadius;
}

async function loadStHelens() {
try {
// 将相机的初始视角看向圣海伦斯火山
const initialPosition = Cesium.Cartesian3.fromRadians(
-2.1344873183780484,
0.8071380277370774,
5743.394497982162,
);
const initialOrientation = new Cesium.HeadingPitchRoll.fromDegrees(
112.99596671210358,
-21.34390550872461,
0.0716951918898415,
);
viewer.scene.camera.setView({
destination: initialPosition,
orientation: initialOrientation,
endTransform: Cesium.Matrix4.IDENTITY,
});

/**
* 圣海伦斯山 3D Tiles数据集由 https://www.liblas.org/samples/ 提供的 LAS 数据生成。
* 此瓦片集采用替换细化(replacement refinement)方法,其几何误差大致等于每个瓦片内平均点间距离。
* 关于LAS数据请参考该网址学习:https://pro.arcgis.com/zh-cn/pro-app/3.3/help/data/las-dataset/storing-lidar-data.htm。
*/
const tileset = await Cesium.Cesium3DTileset.fromIonAssetId(5713);
if (viewModel.currentExampleType !== pointClouds[0]) {
return;
}
viewer.scene.primitives.add(tileset);

tileset.maximumScreenSpaceError = 16.0;
tileset.pointCloudShading.maximumAttenuation = undefined; // 将改为基于 maximumScreenSpaceError
tileset.pointCloudShading.baseResolution = undefined;
tileset.pointCloudShading.geometricErrorScale = 1.0;
tileset.pointCloudShading.attenuation = true;
tileset.pointCloudShading.eyeDomeLighting = true;

tilesetToViewModel(tileset);
} catch (error) {
console.log(`瓦片集加载出错: ${error}`);
}
}

async function loadChurch() {
try {
/**
* 点云由哥伦比亚大学机器人实验室的 Peter Allen 教授提供。扫描由 Alejandro Troccoli 和 Matei Ciocarlie 完成。
* 此瓦片集使用增量细化(additive refinement),每个瓦片的几何误差基于边界框大小。
*/
const tileset = await Cesium.Cesium3DTileset.fromIonAssetId(16421);
if (viewModel.currentExampleType !== pointClouds[1]) {
return;
}
viewer.scene.primitives.add(tileset);

tileset.maximumScreenSpaceError = 16.0;
tileset.pointCloudShading.maximumAttenuation = 4.0; // 不允许点大于 4 pixels.
tileset.pointCloudShading.baseResolution = 0.05; // 假设相邻点之间的原始捕捉分辨率为 5 厘米,即0.05米
tileset.pointCloudShading.geometricErrorScale = 0.5; // // 适用于几何误差和基础分辨率
tileset.pointCloudShading.attenuation = true;
tileset.pointCloudShading.eyeDomeLighting = true;

viewer.scene.camera.setView({
destination: new Cesium.Cartesian3(
4401744.644145314,
225051.41078911052,
4595420.374784433,
),
orientation: new Cesium.HeadingPitchRoll(
5.646733805039757,
-0.276607153839886,
6.281110875400085,
),
});

tilesetToViewModel(tileset);
} catch (error) {
console.log(`瓦片集加载出错: ${error}`);
}
}

function checkZero(newValue) {
const newValueFloat = parseFloat(newValue);
return newValueFloat === 0.0 ? undefined : newValueFloat;
}

loadStHelens();

// 将 viewModel 成员转换为 knockout 可观察对象。
Cesium.knockout.track(viewModel);

// 将 viewModel 绑定到需要使用它的 UI DOM 元素上。
const toolbar = document.getElementById("toolbar");
Cesium.knockout.applyBindings(viewModel, toolbar);

Cesium.knockout
.getObservable(viewModel, "currentExampleType")
.subscribe(function (newValue) {
reset();
if (newValue === pointClouds[0]) {
loadStHelens();
} else if (newValue === pointClouds[1]) {
loadChurch();
}
});

Cesium.knockout
.getObservable(viewModel, "maximumScreenSpaceError")
.subscribe(function (newValue) {
if (Cesium.defined(viewModelTileset)) {
viewModelTileset.maximumScreenSpaceError = parseFloat(newValue);
}
});

Cesium.knockout
.getObservable(viewModel, "geometricErrorScale")
.subscribe(function (newValue) {
if (Cesium.defined(viewModelTileset)) {
viewModelTileset.pointCloudShading.geometricErrorScale =
parseFloat(newValue);
}
});

Cesium.knockout
.getObservable(viewModel, "maximumAttenuation")
.subscribe(function (newValue) {
if (Cesium.defined(viewModelTileset)) {
viewModelTileset.pointCloudShading.maximumAttenuation = checkZero(newValue);
}
});

Cesium.knockout
.getObservable(viewModel, "baseResolution")
.subscribe(function (newValue) {
if (Cesium.defined(viewModelTileset)) {
viewModelTileset.pointCloudShading.baseResolution = checkZero(newValue);
}
});

Cesium.knockout
.getObservable(viewModel, "eyeDomeLightingStrength")
.subscribe(function (newValue) {
if (Cesium.defined(viewModelTileset)) {
viewModelTileset.pointCloudShading.eyeDomeLightingStrength =
parseFloat(newValue);
}
});

Cesium.knockout
.getObservable(viewModel, "eyeDomeLightingRadius")
.subscribe(function (newValue) {
if (Cesium.defined(viewModelTileset)) {
viewModelTileset.pointCloudShading.eyeDomeLightingRadius =
parseFloat(newValue);
}
});

Sandcastle.addToggleButton("启用衰减", true, function (checked) {
if (Cesium.defined(viewModelTileset)) {
viewModelTileset.pointCloudShading.attenuation = checked;
}
});

Sandcastle.addToggleButton("启用眼球(视点)穹顶照明(EDL)", true, function (checked) {
if (Cesium.defined(viewModelTileset)) {
viewModelTileset.pointCloudShading.eyeDomeLighting = checked;
}
});