@mesh3d/cesium-vectortile-gl 0.4.4 → 0.4.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gitattributes +11 -0
- package/.gitconfig +3 -0
- package/.husky/pre-commit +1 -0
- package/.prettierignore +5 -0
- package/.vscode/settings.json +25 -0
- package/LICENSE.md +203 -203
- package/README.md +202 -167
- package/Source/Cesium.d.ts +2692 -2691
- package/Source/VectorTileLOD.js +720 -532
- package/Source/VectorTileRenderList.js +70 -70
- package/Source/VectorTileset.js +473 -447
- package/Source/layers/BackgroundRenderLayer.js +91 -89
- package/Source/layers/FillRenderLayer.js +18 -18
- package/Source/layers/IRenderLayer.js +160 -152
- package/Source/layers/LineRenderLayer.js +104 -94
- package/Source/layers/SymbolRenderLayer.js +30 -31
- package/Source/layers/index.js +23 -16
- package/Source/layers/registerRenderLayer.js +24 -24
- package/Source/layers/visualizers/FillLayerVisualizer.js +542 -426
- package/Source/layers/visualizers/ILayerVisualizer.js +90 -94
- package/Source/layers/visualizers/LineLayerVisualizer.js +702 -571
- package/Source/layers/visualizers/SymbolLayerVisualizer.js +514 -244
- package/Source/sources/GeoJSONSource.js +53 -46
- package/Source/sources/ISource.js +39 -39
- package/Source/sources/VectorSource.js +94 -52
- package/Source/sources/granularitySettings.js +23 -20
- package/Source/sources/index.js +6 -11
- package/Source/sources/registerSource.js +17 -19
- package/Source/style/StyleLayer.js +43 -43
- package/Source/style/StyleLayerProperties.js +44 -43
- package/Source/style/index.js +2 -2
- package/Source/symbol/SymbolPlacements.js +117 -88
- package/Source/workers/VectorTileWorker.js +41 -0
- package/Source/workers/ellipsoid.js +47 -0
- package/Source/workers/processTileTask.js +329 -0
- package/Source/workers/styleEvaluator.js +168 -0
- package/benchmark.html +148 -0
- package/dist/cvt-gl-worker.js +9274 -0
- package/dist/cvt-gl-worker.js.map +1 -0
- package/dist/cvt-gl.js +2570 -2001
- package/dist/cvt-gl.js.map +1 -1
- package/dist/cvt-gl.min.js +3 -3
- package/dist/cvt-gl.min.js.map +1 -1
- package/eslint.config.mjs +58 -0
- package/index.js +9 -6
- package/mlt.html +26 -25
- package/package.json +64 -41
- package/prettier.config.mjs +30 -0
- package/vite.config.mjs +43 -0
- package/vite.worker.config.mjs +31 -0
- package/worker.html +26 -0
|
@@ -1,426 +1,542 @@
|
|
|
1
|
-
import { VectorTileFeature, classifyRings } from
|
|
2
|
-
import { IRenderLayer } from
|
|
3
|
-
import { ILayerVisualizer } from
|
|
4
|
-
import { loadGeometry } from
|
|
5
|
-
import { EXTENT } from 'maplibre-gl/src/data/extent'
|
|
6
|
-
import { subdividePolygon } from
|
|
7
|
-
import { granularitySettings } from
|
|
8
|
-
import { warnOnce } from
|
|
9
|
-
import { VectorTileset } from
|
|
10
|
-
|
|
11
|
-
export class FillFeature {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export class FillLayerVisualizer extends ILayerVisualizer {
|
|
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
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
}
|
|
1
|
+
import { VectorTileFeature, classifyRings } from '@mapbox/vector-tile'
|
|
2
|
+
import { IRenderLayer } from '../IRenderLayer'
|
|
3
|
+
import { ILayerVisualizer } from './ILayerVisualizer'
|
|
4
|
+
import { loadGeometry } from 'maplibre-gl/src/data/load_geometry'
|
|
5
|
+
import { EXTENT } from 'maplibre-gl/src/data/extent'
|
|
6
|
+
import { subdividePolygon } from 'maplibre-gl/src/render/subdivision'
|
|
7
|
+
import { granularitySettings } from '../../sources/granularitySettings'
|
|
8
|
+
import { warnOnce } from 'maplibre-gl/src/util/util'
|
|
9
|
+
import { VectorTileset } from '../../VectorTileset'
|
|
10
|
+
|
|
11
|
+
export class FillFeature {
|
|
12
|
+
constructor() {
|
|
13
|
+
this.featureId = 0
|
|
14
|
+
this.fillColor = Cesium.Color.BLACK.clone()
|
|
15
|
+
this.fillOpacity = 1
|
|
16
|
+
this.coordinates = []
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export class FillLayerVisualizer extends ILayerVisualizer {
|
|
21
|
+
constructor(layers, tile) {
|
|
22
|
+
super(layers, tile)
|
|
23
|
+
|
|
24
|
+
this.geometryInstances = []
|
|
25
|
+
this.primitive = null
|
|
26
|
+
this.commandsReady = false
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @param {VectorTileFeature[]} features
|
|
31
|
+
* @param {IRenderLayer} layer
|
|
32
|
+
* @param {Cesium.frameState} frameState
|
|
33
|
+
* @param {VectorTileset} tileset
|
|
34
|
+
*/
|
|
35
|
+
addLayer(features, layer, frameState, tileset) {
|
|
36
|
+
const style = layer.style
|
|
37
|
+
const { tile, geometryInstances } = this
|
|
38
|
+
const granularity =
|
|
39
|
+
granularitySettings.globe.line.getGranularityForZoomLevel(tile.z) / 2
|
|
40
|
+
const scope = this
|
|
41
|
+
let featureId = 0
|
|
42
|
+
const promoteId = tileset.sources[layer.style.source].styleSource.promoteId
|
|
43
|
+
|
|
44
|
+
for (const sourceFeature of features) {
|
|
45
|
+
const featureType = VectorTileFeature.types[sourceFeature.type]
|
|
46
|
+
const properties = sourceFeature.properties
|
|
47
|
+
if (featureType !== 'Polygon') continue
|
|
48
|
+
|
|
49
|
+
const fillPattern = style.paint.getDataValue(
|
|
50
|
+
'fill-pattern',
|
|
51
|
+
tile.z,
|
|
52
|
+
sourceFeature
|
|
53
|
+
)
|
|
54
|
+
if (fillPattern) {
|
|
55
|
+
warnOnce('fill图层:不支持纹理填充(fill-pattern)')
|
|
56
|
+
continue
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const sourceFeatureId = sourceFeature.id || properties[promoteId]
|
|
60
|
+
//读取图层样式属性
|
|
61
|
+
const fillColor = style.convertColor(
|
|
62
|
+
style.paint.getDataValue('fill-color', tile.z, sourceFeature)
|
|
63
|
+
)
|
|
64
|
+
const fillOpacity = style.paint.getDataValue(
|
|
65
|
+
'fill-opacity',
|
|
66
|
+
tile.z,
|
|
67
|
+
sourceFeature
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
//关键:对投影坐标细分,而不是使用cesium内置的细分
|
|
71
|
+
const vtCoords = loadGeometry(sourceFeature)
|
|
72
|
+
const polygons = classifyRings(vtCoords)
|
|
73
|
+
for (const coordinates of polygons) {
|
|
74
|
+
if (coordinates.some(ring => ring.length < 3)) continue
|
|
75
|
+
|
|
76
|
+
const batchId = geometryInstances.length
|
|
77
|
+
if (featureId == 0) {
|
|
78
|
+
layer.firstBatchId = batchId
|
|
79
|
+
}
|
|
80
|
+
layer.lastBatchId = batchId
|
|
81
|
+
|
|
82
|
+
const fillFeature = {
|
|
83
|
+
coordinates,
|
|
84
|
+
featureId,
|
|
85
|
+
fillColor,
|
|
86
|
+
fillOpacity,
|
|
87
|
+
properties,
|
|
88
|
+
//保存原始数据的要素id,后续可以用来支持 featureState 表达式,这个表达式可以实现选定要素高亮显示
|
|
89
|
+
id: sourceFeatureId,
|
|
90
|
+
//保存batchId,将矢量要素与几何顶点关联,后续可以实时更新图层样式
|
|
91
|
+
batchId
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
scope.addFeature(fillFeature, granularity)
|
|
95
|
+
|
|
96
|
+
featureId++
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
layer.offsets = []
|
|
101
|
+
layer.counts = []
|
|
102
|
+
|
|
103
|
+
this.layers.push(layer)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* 从 Web Worker 结果构建图层几何体(positions/normals/indices 已由 Worker 算好)
|
|
108
|
+
* @param {object} workerLayerData - { layerId, source, sourceLayer, styleLayer, batches, firstBatchId, lastBatchId }
|
|
109
|
+
* @param {IRenderLayer} layer
|
|
110
|
+
* @param {Cesium.FrameState} frameState
|
|
111
|
+
* @param {VectorTileset} tileset
|
|
112
|
+
*/
|
|
113
|
+
addLayerFromWorkerResult(workerLayerData, layer, frameState, tileset) {
|
|
114
|
+
const { batches, firstBatchId, lastBatchId } = workerLayerData
|
|
115
|
+
const geometryInstances = this.geometryInstances
|
|
116
|
+
const cartesian = new Cesium.Cartesian3()
|
|
117
|
+
|
|
118
|
+
for (const batch of batches) {
|
|
119
|
+
const { positions, normals, st, indices, colorBytes, id, properties } =
|
|
120
|
+
batch
|
|
121
|
+
const vertCount = positions.length / 3
|
|
122
|
+
const geometry = new Cesium.Geometry({
|
|
123
|
+
attributes: {
|
|
124
|
+
position: {
|
|
125
|
+
componentDatatype: Cesium.ComponentDatatype.DOUBLE,
|
|
126
|
+
componentsPerAttribute: 3,
|
|
127
|
+
normalize: false,
|
|
128
|
+
values: positions
|
|
129
|
+
},
|
|
130
|
+
normal: {
|
|
131
|
+
componentDatatype: Cesium.ComponentDatatype.FLOAT,
|
|
132
|
+
componentsPerAttribute: 3,
|
|
133
|
+
normalize: false,
|
|
134
|
+
values: normals
|
|
135
|
+
},
|
|
136
|
+
st: {
|
|
137
|
+
componentDatatype: Cesium.ComponentDatatype.FLOAT,
|
|
138
|
+
componentsPerAttribute: 2,
|
|
139
|
+
normalize: false,
|
|
140
|
+
values: st
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
primitiveType: Cesium.PrimitiveType.TRIANGLES,
|
|
144
|
+
indices,
|
|
145
|
+
boundingSphere: Cesium.BoundingSphere.fromVertices(positions)
|
|
146
|
+
})
|
|
147
|
+
const cartographic = Cesium.Cartographic.fromCartesian(
|
|
148
|
+
geometry.boundingSphere.center
|
|
149
|
+
)
|
|
150
|
+
cartographic.height = 0
|
|
151
|
+
const center = Cesium.Cartographic.toCartesian(
|
|
152
|
+
cartographic,
|
|
153
|
+
null,
|
|
154
|
+
cartesian
|
|
155
|
+
)
|
|
156
|
+
const instance = new Cesium.GeometryInstance({
|
|
157
|
+
geometry,
|
|
158
|
+
attributes: {
|
|
159
|
+
color: new Cesium.GeometryInstanceAttribute({
|
|
160
|
+
componentDatatype: Cesium.ComponentDatatype.UNSIGNED_BYTE,
|
|
161
|
+
componentsPerAttribute: 4,
|
|
162
|
+
normalize: true,
|
|
163
|
+
value: Array.from(colorBytes)
|
|
164
|
+
})
|
|
165
|
+
},
|
|
166
|
+
id: new Cesium.Entity({
|
|
167
|
+
position: center,
|
|
168
|
+
id,
|
|
169
|
+
properties
|
|
170
|
+
})
|
|
171
|
+
})
|
|
172
|
+
geometryInstances.push(instance)
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
layer.firstBatchId = firstBatchId
|
|
176
|
+
layer.lastBatchId = lastBatchId
|
|
177
|
+
layer.offsets = []
|
|
178
|
+
layer.counts = []
|
|
179
|
+
this.layers.push(layer)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* 创建一个多边形的几何体实例
|
|
184
|
+
* @param {FillFeature} feature
|
|
185
|
+
* @param {number} granularity
|
|
186
|
+
*/
|
|
187
|
+
addFeature(feature, granularity) {
|
|
188
|
+
const geometryInstances = this.geometryInstances
|
|
189
|
+
const { coordinates, fillColor, fillOpacity } = feature
|
|
190
|
+
const colorBytes = fillColor.toBytes()
|
|
191
|
+
colorBytes[3] = Math.floor(colorBytes[3] * fillOpacity)
|
|
192
|
+
|
|
193
|
+
// 使用 maplibre-gl 的 subdividePolygon 基于投影坐标进行细分,
|
|
194
|
+
// 而不是在转成世界坐标后再使用 Cesium.PolygonGeometry 构建,这样才能避免出现自相交、破面等现象。
|
|
195
|
+
// 商业版性能优化:将此过程移到 Web Worker ,多线程加速,同时避免主线程阻塞
|
|
196
|
+
|
|
197
|
+
const subdivisionRes = subdividePolygon(
|
|
198
|
+
coordinates,
|
|
199
|
+
this.tile,
|
|
200
|
+
granularity,
|
|
201
|
+
false
|
|
202
|
+
)
|
|
203
|
+
const verticesFlattened = subdivisionRes.verticesFlattened
|
|
204
|
+
const coordDeg = [0, 0],
|
|
205
|
+
cartesian = new Cesium.Cartesian3()
|
|
206
|
+
const vertCount = verticesFlattened.length / 2
|
|
207
|
+
const positions = new Float64Array(vertCount * 3)
|
|
208
|
+
const normals = new Float32Array(vertCount * 3)
|
|
209
|
+
const sts = new Float32Array(vertCount * 2)
|
|
210
|
+
|
|
211
|
+
for (let i = 0, j = 0; i < verticesFlattened.length; i += 2, j++) {
|
|
212
|
+
const x = verticesFlattened[i],
|
|
213
|
+
y = verticesFlattened[i + 1]
|
|
214
|
+
const coord = this.tile.transformPoint(x, y, coordDeg)
|
|
215
|
+
const position = Cesium.Cartesian3.fromDegrees(
|
|
216
|
+
coord[0],
|
|
217
|
+
coord[1],
|
|
218
|
+
0,
|
|
219
|
+
null,
|
|
220
|
+
cartesian
|
|
221
|
+
)
|
|
222
|
+
positions[j * 3] = position.x
|
|
223
|
+
positions[j * 3 + 1] = position.y
|
|
224
|
+
positions[j * 3 + 2] = position.z
|
|
225
|
+
|
|
226
|
+
const normal = Cesium.Cartesian3.normalize(position, position)
|
|
227
|
+
normals[j * 3] = normal.x
|
|
228
|
+
normals[j * 3 + 1] = normal.y
|
|
229
|
+
normals[j * 3 + 2] = normal.z
|
|
230
|
+
|
|
231
|
+
sts[j * 2] = x / EXTENT
|
|
232
|
+
sts[j * 2 + 1] = y / EXTENT
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const indices = new (
|
|
236
|
+
vertCount > 65535
|
|
237
|
+
? Uint32Array
|
|
238
|
+
: vertCount > 255
|
|
239
|
+
? Uint16Array
|
|
240
|
+
: Uint8Array
|
|
241
|
+
)(subdivisionRes.indicesTriangles)
|
|
242
|
+
|
|
243
|
+
const geometry = new Cesium.Geometry({
|
|
244
|
+
attributes: {
|
|
245
|
+
position: {
|
|
246
|
+
componentDatatype: Cesium.ComponentDatatype.DOUBLE,
|
|
247
|
+
componentsPerAttribute: 3,
|
|
248
|
+
normalize: false,
|
|
249
|
+
values: positions
|
|
250
|
+
},
|
|
251
|
+
normal: {
|
|
252
|
+
componentDatatype: Cesium.ComponentDatatype.FLOAT,
|
|
253
|
+
componentsPerAttribute: 3,
|
|
254
|
+
normalize: false,
|
|
255
|
+
values: normals
|
|
256
|
+
},
|
|
257
|
+
st: {
|
|
258
|
+
componentDatatype: Cesium.ComponentDatatype.FLOAT,
|
|
259
|
+
componentsPerAttribute: 2,
|
|
260
|
+
normalize: false,
|
|
261
|
+
values: sts
|
|
262
|
+
}
|
|
263
|
+
},
|
|
264
|
+
primitiveType: Cesium.PrimitiveType.TRIANGLES,
|
|
265
|
+
indices: indices,
|
|
266
|
+
boundingSphere: Cesium.BoundingSphere.fromVertices(positions)
|
|
267
|
+
})
|
|
268
|
+
|
|
269
|
+
const cartographic = Cesium.Cartographic.fromCartesian(
|
|
270
|
+
geometry.boundingSphere.center
|
|
271
|
+
)
|
|
272
|
+
cartographic.height = 0 //包围盒中心可能高于或者低于地面,需要避免双击锁定视角时进入地下
|
|
273
|
+
const center = Cesium.Cartographic.toCartesian(
|
|
274
|
+
cartographic,
|
|
275
|
+
null,
|
|
276
|
+
cartesian
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
const instance = new Cesium.GeometryInstance({
|
|
280
|
+
geometry,
|
|
281
|
+
attributes: {
|
|
282
|
+
color: new Cesium.GeometryInstanceAttribute({
|
|
283
|
+
componentDatatype: Cesium.ComponentDatatype.UNSIGNED_BYTE,
|
|
284
|
+
componentsPerAttribute: 4,
|
|
285
|
+
normalize: true,
|
|
286
|
+
value: colorBytes
|
|
287
|
+
})
|
|
288
|
+
},
|
|
289
|
+
//通过entity的形式暴露给Cesium pickEntity,这样点击时系统自带的inforbox可以弹出
|
|
290
|
+
id: new Cesium.Entity({
|
|
291
|
+
position: center,
|
|
292
|
+
id: feature.id,
|
|
293
|
+
properties: feature.properties
|
|
294
|
+
})
|
|
295
|
+
})
|
|
296
|
+
geometryInstances.push(instance)
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
createPrimitive() {
|
|
300
|
+
const primitive = new Cesium.Primitive({
|
|
301
|
+
geometryInstances: this.geometryInstances,
|
|
302
|
+
asynchronous: !(
|
|
303
|
+
this.geometryInstances[0].geometry instanceof Cesium.Geometry
|
|
304
|
+
),
|
|
305
|
+
appearance: new Cesium.PerInstanceColorAppearance({
|
|
306
|
+
flat: true,
|
|
307
|
+
translucent: false,
|
|
308
|
+
renderState: {
|
|
309
|
+
//这里设置是没有用的,只要 translucent 为 false,
|
|
310
|
+
//Cesium 内部都会覆盖成 true,所以我们需要在 DrawCommand 创建完成后再设置
|
|
311
|
+
depthMask: false
|
|
312
|
+
},
|
|
313
|
+
fragmentShaderSource: /*glsl*/ `
|
|
314
|
+
in vec4 v_color;
|
|
315
|
+
|
|
316
|
+
uniform vec4 tileId;
|
|
317
|
+
uniform sampler2D tileIdTexture;
|
|
318
|
+
|
|
319
|
+
void main()
|
|
320
|
+
{
|
|
321
|
+
vec2 id_st = gl_FragCoord.xy / czm_viewport.zw;
|
|
322
|
+
vec4 bgId = texture(tileIdTexture, id_st);
|
|
323
|
+
if (!all(equal(bgId, tileId)))
|
|
324
|
+
{
|
|
325
|
+
discard;
|
|
326
|
+
}
|
|
327
|
+
out_FragColor = v_color;
|
|
328
|
+
}
|
|
329
|
+
`
|
|
330
|
+
})
|
|
331
|
+
})
|
|
332
|
+
|
|
333
|
+
//通过定义 Primitive 私有变量 _geometries、_batchTable 的 setter 和 getter,
|
|
334
|
+
//监听合批几何体和批次表的创建:
|
|
335
|
+
//1、几何体创建完成后,根据 batchId 和 featureId,计算每个图层几何体的起始索引(offset)和索引数量(count)
|
|
336
|
+
//2、批次表创建完成后,保存备用
|
|
337
|
+
let scope = this
|
|
338
|
+
Object.defineProperties(primitive, {
|
|
339
|
+
_geometries: {
|
|
340
|
+
get() {
|
|
341
|
+
return this._geometries_
|
|
342
|
+
},
|
|
343
|
+
set(geometries) {
|
|
344
|
+
this._geometries_ = geometries
|
|
345
|
+
if (geometries) {
|
|
346
|
+
scope.onGeometriesLoaded(geometries)
|
|
347
|
+
} else {
|
|
348
|
+
scope = null
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
},
|
|
352
|
+
_batchTable: {
|
|
353
|
+
get() {
|
|
354
|
+
return this._batchTable_
|
|
355
|
+
},
|
|
356
|
+
set(batchTable) {
|
|
357
|
+
this._batchTable_ = batchTable
|
|
358
|
+
if (batchTable) {
|
|
359
|
+
scope.onBatchTableCreated(batchTable)
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
})
|
|
364
|
+
|
|
365
|
+
this.primitive = primitive
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* 根据 batchId 和 featureId,计算每个图层几何体的起始索引(offset)和索引数量(count)
|
|
370
|
+
* @param {Cesium.Geometry[]} geometries
|
|
371
|
+
*/
|
|
372
|
+
onGeometriesLoaded(geometries) {
|
|
373
|
+
//Cesium 几何体合批结果可能是多个几何体,对应多个 DrawCommand
|
|
374
|
+
for (let pass = 0; pass < geometries.length; pass++) {
|
|
375
|
+
const batches = {}
|
|
376
|
+
const geometry = geometries[pass]
|
|
377
|
+
const batchIds = geometry.attributes.batchId.values
|
|
378
|
+
const indices = geometry.indices
|
|
379
|
+
|
|
380
|
+
//提取每个批次的起始和结束索引
|
|
381
|
+
let currBatchId = -1
|
|
382
|
+
let currBatch = null
|
|
383
|
+
for (let i = 0; i < indices.length; i++) {
|
|
384
|
+
const vertIndex = indices[i]
|
|
385
|
+
const batchId = batchIds[vertIndex]
|
|
386
|
+
if (currBatchId !== batchId) {
|
|
387
|
+
currBatchId = batchId
|
|
388
|
+
currBatch = batches[currBatchId] = {
|
|
389
|
+
begin: i,
|
|
390
|
+
end: i
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
currBatch.end = i
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
//根据图层批次范围,提取图层几何体索引范围,即起始索引(offset)和索引数量(count)
|
|
397
|
+
for (const layer of this.layers) {
|
|
398
|
+
const { firstBatchId, lastBatchId } = layer
|
|
399
|
+
if (firstBatchId === -1 || lastBatchId === -1) {
|
|
400
|
+
continue
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
let begin = -1,
|
|
404
|
+
end = -1
|
|
405
|
+
for (let batchId = firstBatchId; batchId <= lastBatchId; batchId++) {
|
|
406
|
+
const batch = batches[batchId]
|
|
407
|
+
if (batch) {
|
|
408
|
+
if (begin === -1) begin = batch.begin
|
|
409
|
+
end = batch.end
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
if (begin === -1 || end === -1) {
|
|
414
|
+
continue
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
//起始和结束索引,索引数量需要加1
|
|
418
|
+
layer.offsets[pass] = begin
|
|
419
|
+
layer.counts[pass] = end - begin + 1
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* 保存 Cesium Primitive 创建的批次表。图层样式变化时,通过更新批次表传递到GPU,同步更新渲染效果
|
|
426
|
+
* @param {Cesium.BatchTable} batchTable
|
|
427
|
+
*/
|
|
428
|
+
onBatchTableCreated(batchTable) {
|
|
429
|
+
this._batchTable = batchTable
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* 使用合批后的 drawCommand 创建副本,为渲染图层分配 drawCommand
|
|
434
|
+
* @param {Cesium.DrawCommand[]} batchedCommandList
|
|
435
|
+
* @param {VectorTileset} tileset
|
|
436
|
+
*/
|
|
437
|
+
createLayerCommands(batchedCommandList, tileset) {
|
|
438
|
+
const renderState = Cesium.RenderState.fromCache({
|
|
439
|
+
id: 'fill',
|
|
440
|
+
blending: Cesium.BlendingState.ALPHA_BLEND,
|
|
441
|
+
depthMask: false,
|
|
442
|
+
depthTest: {
|
|
443
|
+
enabled: true
|
|
444
|
+
},
|
|
445
|
+
cull: {
|
|
446
|
+
enabled: true
|
|
447
|
+
}
|
|
448
|
+
})
|
|
449
|
+
const tileId = this.tile.tileId
|
|
450
|
+
this.renderState = renderState
|
|
451
|
+
|
|
452
|
+
for (let i = 0; i < this.layers.length; i++) {
|
|
453
|
+
const layer = this.layers[i]
|
|
454
|
+
const layerCommandList = (layer.commandList = [])
|
|
455
|
+
|
|
456
|
+
for (let pass = 0; pass < batchedCommandList.length; pass++) {
|
|
457
|
+
const offset = layer.offsets[pass],
|
|
458
|
+
count = layer.counts[pass]
|
|
459
|
+
if (typeof offset !== 'number' || typeof count !== 'number') {
|
|
460
|
+
continue
|
|
461
|
+
}
|
|
462
|
+
const command = batchedCommandList[pass]
|
|
463
|
+
command.uniformMap.tileIdTexture = function () {
|
|
464
|
+
return tileset.tileIdTexture
|
|
465
|
+
}
|
|
466
|
+
command.uniformMap.tileId = function () {
|
|
467
|
+
return tileId.color
|
|
468
|
+
}
|
|
469
|
+
command.pass = Cesium.Pass.CESIUM_3D_TILE
|
|
470
|
+
//通过副本的 offset 和 count 指定图层的绘制范围
|
|
471
|
+
const layerCommand = Cesium.DrawCommand.shallowClone(command)
|
|
472
|
+
layerCommand.pass = Cesium.Pass.CESIUM_3D_TILE
|
|
473
|
+
layerCommand.renderState = renderState
|
|
474
|
+
layerCommand.layerType = 'fill'
|
|
475
|
+
layerCommand.offset = offset
|
|
476
|
+
layerCommand.count = count
|
|
477
|
+
layerCommandList.push(layerCommand)
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
layer.state = 'done'
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
//标记 drawCommand 创建完成
|
|
484
|
+
this.state = 'done'
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
update(frameState, tileset) {
|
|
488
|
+
if (!this.geometryInstances) {
|
|
489
|
+
return
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
super.update(frameState, tileset)
|
|
493
|
+
|
|
494
|
+
if (!this.primitive && this.geometryInstances.length) {
|
|
495
|
+
this.createPrimitive()
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
if (this.primitive && this.state !== 'done' && this.state !== 'error') {
|
|
499
|
+
//先保存系统的 commandList
|
|
500
|
+
const preCommandList = frameState.commandList
|
|
501
|
+
//临时覆盖 frameState.commandList,用于获取合批之后的drawCommand
|
|
502
|
+
const batchedCommandList = (frameState.commandList = [])
|
|
503
|
+
|
|
504
|
+
//执行 primitive 的 update ,直到生成了合批后的drawCommand
|
|
505
|
+
try {
|
|
506
|
+
this.primitive.update(frameState)
|
|
507
|
+
} catch (err) {
|
|
508
|
+
//如果报错,下一帧就不要再执行 update 了,以免重复打印错误信息
|
|
509
|
+
this.geometryInstances = []
|
|
510
|
+
this.setState('error')
|
|
511
|
+
if (err.stack) console.trace(err.stack)
|
|
512
|
+
else console.error(err)
|
|
513
|
+
return
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
//使用合批后的 drawCommand 创建副本,为渲染图层分配 drawCommand
|
|
517
|
+
if (batchedCommandList.length > 0) {
|
|
518
|
+
this.createLayerCommands(batchedCommandList, tileset)
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
if (this.primitive._state === Cesium.PrimitiveState.FAILED) {
|
|
522
|
+
this.setState('error')
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
//恢复系统的 commandList
|
|
526
|
+
frameState.commandList = preCommandList
|
|
527
|
+
this.geometryInstances = []
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
destroy() {
|
|
532
|
+
this.primitive = this.primitive && this.primitive.destroy()
|
|
533
|
+
this._batchTable = null
|
|
534
|
+
this.geometryInstances = null
|
|
535
|
+
|
|
536
|
+
super.destroy()
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
isDestroyed() {
|
|
540
|
+
return false
|
|
541
|
+
}
|
|
542
|
+
}
|