原文链接及内容

效果如下视频所示:针对具体的绘制过程,针对第一个建筑物正面高亮的绘制进行了详细的分析,具体看代码的注释,后续按参考第一个绘制即可。

示例代码如下:

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
<style>
@import url(../templates/bucket.css);
#toolbar {
background: rgba(42, 42, 42, 0.8);
padding: 4px;
border-radius: 4px;
}
.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>
<button class="cesium-button" data-bind="click: highlightTrees">
定位至高亮树木
</button>
</td>
</tr>
<tr>
<td>
<button class="cesium-button" data-bind="click: highlightBuilding">
定位至高亮建筑物的face(正面)
</button>
</td>
</tr>
<tr>
<td>反转分类</td>
<td><input type="checkbox" data-bind="checked: inverted"></td>
</tr>
<tr>
<td>反转颜色的透明度</td>
<td>
<input type="range" min="0.0" max="1.0" step="0.01" data-bind="value: invertedAlpha, valueUpdate: 'input'">
<input type="text" size="3" data-bind="value: invertedAlpha">
</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
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
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 { camera, scene } = viewer;

//#region ---------绘制一个8×5×8的长方体,用于高亮---------------------------------
let center = new Cesium.Cartesian3(
1216389.3637977627,
-4736323.641980423,
4081321.7428341154
);
/**
* eastNorthUpToFixedFrame():
* 计算一个从以提供原点为中心的东-北-上(天)轴参考系到提供的椭球体固定参考系的 4x4 变换矩阵。
* x轴直线本地东方;y轴指向本地北方;z轴指向通过该位置的椭球面法线方向。
*/
let modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(center);
// 定义基于航向-俯仰-滚转的旋转矩阵
let hprRotation = Cesium.Matrix3.fromHeadingPitchRoll(
new Cesium.HeadingPitchRoll(2.619728786416368, 0.0, 0.0)
);
/**
* 创建旋转和平移的变换矩阵,
* fromRotationTranslation方法将一个3×3的旋转矩阵和一个平移向量组合成一个4×4的变换矩阵hpr。
* 具体地表示一个先旋转再平移的变换。
*/
let hpr = Cesium.Matrix4.fromRotationTranslation(
hprRotation,
new Cesium.Cartesian3(0.0, 0.0, -2.0)
);
/**
* multiply方法将modelMatrix和hpr相乘,结果存储在modelMatrix中。
* 具体表示先应用modelMatrix变换,将局部坐标系定位至center,然后再应用hpr旋转和平移。
*/
Cesium.Matrix4.multiply(modelMatrix, hpr, modelMatrix);

const buildingHighlight = scene.primitives.add(
new Cesium.ClassificationPrimitive({
geometryInstances: new Cesium.GeometryInstance({
/**
* fromDimensions方法:根据其尺寸创建一个以原点为中心的立方体。
* - vertexFormat:顶点格式,值为VERTEX_FORMAT,直译为顶点格式,
* 而值FLAT_VERTEX_FORMAT直译为平面顶点格式。
*/
geometry: Cesium.BoxGeometry.fromDimensions({
vertexFormat: Cesium.PerInstanceColorAppearance.VERTEX_FORMAT,
dimensions: new Cesium.Cartesian3(8.0, 5.0, 8.0),
}),
modelMatrix: modelMatrix,
/**
* attributes是用于实例的属性
*/
attributes: {
/**
* new Cesium.Color(red, green, blue, alpha):各个分量范围都是0~1
* 这里显然为半透明红色
*/
color: Cesium.ColorGeometryInstanceAttribute.fromColor(
new Cesium.Color(1.0, 0.0, 0.0, 0.5)
),
/**
* ShowGeometryInstanceAttribute(true):确定几何实例是否显示。
* 这里显然是显示几何实例
*/
show: new Cesium.ShowGeometryInstanceAttribute(true),
},
id: "volume",
}),
/**
* ClassificationType:
* - TERRAIN: 仅对地形进行分类。
* - CESIUM_3D_TILE: 仅对 3D Tiles 进行分类。
* - BOTH: 对地形和3D Tiles都进行分类。
*/
classificationType: Cesium.ClassificationType.CESIUM_3D_TILE,
})
);
//#endregion

//#region -------------------绘制一个橙色椭球体用于树木高亮---------------------------------
center = new Cesium.Cartesian3(
1216409.0189737265,
-4736252.144235287,
4081393.6027081604
);
modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(center);
hprRotation = Cesium.Matrix3.fromHeadingPitchRoll(
new Cesium.HeadingPitchRoll(5.785339046755887, 0.0, 0.0)
);
hpr = Cesium.Matrix4.fromRotationTranslation(
hprRotation,
new Cesium.Cartesian3(0.4, 0.0, -2.0)
);
Cesium.Matrix4.multiply(modelMatrix, hpr, modelMatrix);

const treeHighlight1 = scene.primitives.add(
new Cesium.ClassificationPrimitive({
geometryInstances: new Cesium.GeometryInstance({
geometry: new Cesium.EllipsoidGeometry({
radii: new Cesium.Cartesian3(3.25, 5.0, 4.0),
}),
modelMatrix: modelMatrix,
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(
Cesium.Color.fromCssColorString("#F26419").withAlpha(0.5)
),
show: new Cesium.ShowGeometryInstanceAttribute(true),
},
id: "volume 1",
}),
classificationType: Cesium.ClassificationType.CESIUM_3D_TILE,
})
);
//#endregion

//#region -------------------绘制一个红色椭球体用于树木高亮---------------------------------
center = new Cesium.Cartesian3(
1216404.8844045496,
-4736255.287065536,
4081392.010192471
);
modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(center);
hprRotation = Cesium.Matrix3.fromHeadingPitchRoll(
new Cesium.HeadingPitchRoll(5.785339046755887, 0.0, 0.0)
);
hpr = Cesium.Matrix4.fromRotationTranslation(
hprRotation,
new Cesium.Cartesian3(-0.25, 0.0, -2.0)
);
Cesium.Matrix4.multiply(modelMatrix, hpr, modelMatrix);

const treeHighlight2 = scene.primitives.add(
new Cesium.ClassificationPrimitive({
geometryInstances: new Cesium.GeometryInstance({
geometry: new Cesium.EllipsoidGeometry({
radii: new Cesium.Cartesian3(3.25, 5.0, 4.0),
}),
modelMatrix: modelMatrix,
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(
Cesium.Color.fromCssColorString("#F03A47").withAlpha(0.5)
),
show: new Cesium.ShowGeometryInstanceAttribute(true),
},
id: "volume 2",
}),
classificationType: Cesium.ClassificationType.CESIUM_3D_TILE,
})
);
//#endregion

//#region -------------------绘制一个蓝色椭球体用于树木高亮---------------------------------
center = new Cesium.Cartesian3(
1216398.813990024,
-4736258.039875737,
4081387.9562678365
);
modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(center);
let translation = Cesium.Matrix4.fromTranslation(
new Cesium.Cartesian3(0.0, 0.0, -2.0)
);
Cesium.Matrix4.multiply(modelMatrix, translation, modelMatrix);

const treeHighlight3 = scene.primitives.add(
new Cesium.ClassificationPrimitive({
geometryInstances: new Cesium.GeometryInstance({
geometry: new Cesium.EllipsoidGeometry({
radii: new Cesium.Cartesian3(2.45, 2.45, 3.0),
}),
modelMatrix: modelMatrix,
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(
Cesium.Color.fromCssColorString("#004FFF").withAlpha(0.5)
),
show: new Cesium.ShowGeometryInstanceAttribute(true),
},
id: "volume 3",
}),
classificationType: Cesium.ClassificationType.CESIUM_3D_TILE,
})
);
//#endregion

//#region -------------------绘制一个水蓝色球体用于树木高亮---------------------------------
center = new Cesium.Cartesian3(
1216393.6257790313,
-4736259.809075361,
4081384.4858198245
);
modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(center);
translation = Cesium.Matrix4.fromTranslation(
new Cesium.Cartesian3(0.0, 0.0, -1.0)
);
Cesium.Matrix4.multiply(modelMatrix, translation, modelMatrix);

const treeHighlight4 = scene.primitives.add(
new Cesium.ClassificationPrimitive({
geometryInstances: new Cesium.GeometryInstance({
geometry: new Cesium.SphereGeometry({
radius: 2.0,
}),
modelMatrix: modelMatrix,
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(
Cesium.Color.fromCssColorString("#55DDE0").withAlpha(0.5)
),
show: new Cesium.ShowGeometryInstanceAttribute(true),
},
id: "volume 4",
}),
classificationType: Cesium.ClassificationType.CESIUM_3D_TILE,
})
);
//#endregion

function highlightBuilding() {
camera.setView({
destination: new Cesium.Cartesian3(
1216394.1392207467,
-4736348.59346919,
4081293.9160685353
),
orientation: {
heading: 0.018509338875732695,
pitch: -0.09272999615872646,
},
});
}

function highlightTrees() {
camera.setView({
destination: new Cesium.Cartesian3(
1216435.0352745096,
-4736283.144192113,
4081368.0920420634
),
orientation: {
heading: 5.718380792746039,
pitch: -0.3087010195266797,
},
});
}

function invertClassification(checked) {
if (checked && !scene.invertClassificationSupported) {
window.alert("该浏览器不支持反转分类(invert classification)");
}

scene.invertClassification = checked;
scene.invertClassificationColor = new Cesium.Color(0.25, 0.25, 0.25, 1.0);

buildingHighlight.getGeometryInstanceAttributes("volume").show =
Cesium.ShowGeometryInstanceAttribute.toValue(!checked);
treeHighlight1.getGeometryInstanceAttributes("volume 1").show =
Cesium.ShowGeometryInstanceAttribute.toValue(!checked);
treeHighlight2.getGeometryInstanceAttributes("volume 2").show =
Cesium.ShowGeometryInstanceAttribute.toValue(!checked);
treeHighlight3.getGeometryInstanceAttributes("volume 3").show =
Cesium.ShowGeometryInstanceAttribute.toValue(!checked);
treeHighlight4.getGeometryInstanceAttributes("volume 4").show =
Cesium.ShowGeometryInstanceAttribute.toValue(!checked);
}

function updateAlpha(value) {
scene.invertClassificationColor.alpha = parseFloat(value);
}

try {
const tileset = await Cesium.Cesium3DTileset.fromIonAssetId(40866);
scene.primitives.add(tileset);
} catch (error) {
console.log(`tileset加载出错: ${error}`);
}

const viewModel = {
inverted: viewer.scene.invertClassification,
invertedAlpha: viewer.scene.invertClassificationColor.alpha,
highlightBuilding: highlightBuilding,
highlightTrees: highlightTrees,
};
Cesium.knockout.track(viewModel);
const toolbar = document.getElementById("toolbar");
Cesium.knockout.applyBindings(viewModel, toolbar);
Cesium.knockout
.getObservable(viewModel, "inverted")
.subscribe(invertClassification);
Cesium.knockout
.getObservable(viewModel, "invertedAlpha")
.subscribe(updateAlpha);

highlightTrees();

let currentObjectId;
let currentPrimitive;
let currentColor;
let currentShow;
let attributes;

const handler = new Cesium.ScreenSpaceEventHandler(scene.canvas);
handler.setInputAction(function (movement) {
const pickedObject = scene.pick(movement.endPosition);
if (Cesium.defined(pickedObject) && Cesium.defined(pickedObject.id)) {
if (pickedObject.id === currentObjectId) {
return;
}

if (Cesium.defined(currentObjectId)) {
attributes =
currentPrimitive.getGeometryInstanceAttributes(currentObjectId);
attributes.color = currentColor;
attributes.show = currentShow;
currentObjectId = undefined;
currentPrimitive = undefined;
currentColor = undefined;
currentShow = undefined;
}
}

if (
Cesium.defined(pickedObject) &&
Cesium.defined(pickedObject.primitive) &&
Cesium.defined(pickedObject.id) &&
Cesium.defined(pickedObject.primitive.getGeometryInstanceAttributes)
) {
currentObjectId = pickedObject.id;
currentPrimitive = pickedObject.primitive;
attributes =
currentPrimitive.getGeometryInstanceAttributes(currentObjectId);
currentColor = attributes.color;
currentShow = attributes.show;
if (!scene.invertClassification) {
attributes.color = [255, 0, 255, 128];
}
attributes.show = [1];
} else if (Cesium.defined(currentObjectId)) {
attributes =
currentPrimitive.getGeometryInstanceAttributes(currentObjectId);
attributes.color = currentColor;
attributes.show = currentShow;
currentObjectId = undefined;
currentPrimitive = undefined;
currentColor = undefined;
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);