@mesh3d/cesium-vectortile-gl 0.1.0
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/LICENSE.md +21 -0
- package/README.md +120 -0
- package/Source/Cesium.d.ts +2692 -0
- package/Source/VectorTileLOD.js +494 -0
- package/Source/VectorTileRenderList.js +65 -0
- package/Source/VectorTileset.js +309 -0
- package/Source/layers/BackgroundRenderLayer.js +82 -0
- package/Source/layers/FillRenderLayer.js +18 -0
- package/Source/layers/IRenderLayer.js +128 -0
- package/Source/layers/LineRenderLayer.js +94 -0
- package/Source/layers/SymbolRenderLayer.js +31 -0
- package/Source/layers/index.js +16 -0
- package/Source/layers/registerRenderLayer.js +24 -0
- package/Source/layers/visualizers/FillLayerVisualizer.js +420 -0
- package/Source/layers/visualizers/ILayerVisualizer.js +73 -0
- package/Source/layers/visualizers/LineLayerVisualizer.js +565 -0
- package/Source/layers/visualizers/SymbolLayerVisualizer.js +179 -0
- package/Source/sources/GeoJSONSource.js +46 -0
- package/Source/sources/ISource.js +39 -0
- package/Source/sources/VectorSource.js +45 -0
- package/Source/sources/granularitySettings.js +20 -0
- package/Source/sources/index.js +11 -0
- package/Source/sources/registerSource.js +19 -0
- package/Source/style/StyleLayer.js +43 -0
- package/Source/style/StyleLayerProperties.js +43 -0
- package/Source/style/index.js +2 -0
- package/dist/cvt-gl.js +10642 -0
- package/dist/cvt-gl.js.map +1 -0
- package/dist/cvt-gl.min.js +135 -0
- package/dist/cvt-gl.min.js.map +1 -0
- package/index.js +6 -0
- package/logo.svg +47 -0
- package/package.json +36 -0
|
@@ -0,0 +1,565 @@
|
|
|
1
|
+
import { VectorTileFeature } from "@mapbox/vector-tile"
|
|
2
|
+
import { IRenderLayer } from "../IRenderLayer"
|
|
3
|
+
import { ILayerVisualizer } from "./ILayerVisualizer"
|
|
4
|
+
import { VectorTileset } from "../../VectorTileset"
|
|
5
|
+
import { subdivideVertexLine } from "maplibre-gl/src/render/subdivision"
|
|
6
|
+
import { loadGeometry } from "maplibre-gl/src/data/load_geometry"
|
|
7
|
+
import * as mvt from '@mapbox/vector-tile';
|
|
8
|
+
import { EXTENT } from 'maplibre-gl/src/data/extent';
|
|
9
|
+
import { granularitySettings } from "../../sources/granularitySettings"
|
|
10
|
+
import { warnOnce } from "maplibre-gl/src/util/util"
|
|
11
|
+
import { LineRenderLayer } from "../LineRenderLayer"
|
|
12
|
+
const toGeoJSON = mvt.VectorTileFeature.prototype.toGeoJSON;
|
|
13
|
+
|
|
14
|
+
export class LineFeature {
|
|
15
|
+
constructor() {
|
|
16
|
+
this.featureId = 0
|
|
17
|
+
this.lineColor = Cesium.Color.BLACK.clone()
|
|
18
|
+
this.lineWidth = 1
|
|
19
|
+
this.lineOpacity = 1
|
|
20
|
+
this.coordinates = []
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export class LineLayerVisualizer extends ILayerVisualizer {
|
|
25
|
+
constructor(layers, tile) {
|
|
26
|
+
super(layers, tile)
|
|
27
|
+
|
|
28
|
+
this.geometryInstances = []
|
|
29
|
+
this.primitive = null
|
|
30
|
+
this.commandsReady = false
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @param {VectorTileFeature[]} features
|
|
35
|
+
* @param {LineRenderLayer} layer
|
|
36
|
+
* @param {Cesium.frameState} frameState
|
|
37
|
+
* @param {VectorTileset} tileset
|
|
38
|
+
*/
|
|
39
|
+
addLayer(features, layer, frameState, tileset) {
|
|
40
|
+
const style = layer.style
|
|
41
|
+
const { tile, geometryInstances } = this
|
|
42
|
+
const granularity = granularitySettings.globe.line.getGranularityForZoomLevel(tile.z)
|
|
43
|
+
const scope = this
|
|
44
|
+
const promoteId = tileset.sources[layer.style.source].styleSource.promoteId
|
|
45
|
+
let featureId = 0
|
|
46
|
+
|
|
47
|
+
//支持虚线
|
|
48
|
+
const dasharray = style.paint.getDataConstValue('line-dasharray', tile.z)
|
|
49
|
+
if (dasharray && dasharray.length) {
|
|
50
|
+
if (dasharray.length % 2 > 0) {
|
|
51
|
+
dasharray.push(0)
|
|
52
|
+
}
|
|
53
|
+
layer.dashLength = 0
|
|
54
|
+
for (let i = 0; i < dasharray.length; i++) {
|
|
55
|
+
layer.dashLength += dasharray[i]
|
|
56
|
+
}
|
|
57
|
+
layer.dasharray = dasharray
|
|
58
|
+
|
|
59
|
+
if (dasharray.length > 8) {
|
|
60
|
+
warnOnce('line图层:line-dasharray 超过最大长度(8)')
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function addPolyline(coordinates, lineWidth, lineColor, lineOpacity, id, properties) {
|
|
65
|
+
if (coordinates.length < 2) return
|
|
66
|
+
|
|
67
|
+
const batchId = geometryInstances.length
|
|
68
|
+
if (featureId == 0) {
|
|
69
|
+
layer.firstBatchId = batchId
|
|
70
|
+
}
|
|
71
|
+
layer.lastBatchId = batchId
|
|
72
|
+
|
|
73
|
+
const lineFeature = {
|
|
74
|
+
coordinates,
|
|
75
|
+
featureId,
|
|
76
|
+
lineColor,
|
|
77
|
+
lineOpacity,
|
|
78
|
+
lineWidth,
|
|
79
|
+
properties,
|
|
80
|
+
//保存原始数据的要素id,后续可以用来支持 featureState 表达式,这个表达式可以实现选定要素高亮显示
|
|
81
|
+
id,
|
|
82
|
+
//保存batchId,将矢量要素与几何顶点关联,后续可以实时更新图层样式
|
|
83
|
+
batchId
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
scope.addFeature(lineFeature)
|
|
87
|
+
|
|
88
|
+
featureId++
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
for (const sourceFeature of features) {
|
|
92
|
+
const featureType = VectorTileFeature.types[sourceFeature.type]
|
|
93
|
+
if (featureType === 'Point' || featureType === 'Unknown') continue
|
|
94
|
+
|
|
95
|
+
const properties = sourceFeature.properties
|
|
96
|
+
|
|
97
|
+
//关键:使用 maplibre-gl 的 subdivideVertexLine 对投影坐标细分,
|
|
98
|
+
// 如果转成经纬度之后使用cesium内置的细分,高纬度的线很难拟合地球椭球面
|
|
99
|
+
const vtCoords = loadGeometry(sourceFeature)
|
|
100
|
+
for (let i = 0; i < vtCoords.length; i++) {
|
|
101
|
+
vtCoords[i] = subdivideVertexLine(vtCoords[i], granularity)
|
|
102
|
+
}
|
|
103
|
+
const feature = toGeoJSON.call({
|
|
104
|
+
extent: EXTENT,
|
|
105
|
+
type: sourceFeature.type,
|
|
106
|
+
properties,
|
|
107
|
+
loadGeometry() {
|
|
108
|
+
return vtCoords
|
|
109
|
+
}
|
|
110
|
+
}, tile.x, tile.y, tile.z);
|
|
111
|
+
if (!feature.geometry) continue
|
|
112
|
+
|
|
113
|
+
const sourceFeatureId = sourceFeature.id || properties[promoteId]
|
|
114
|
+
//读取图层样式属性
|
|
115
|
+
const lineWidth = style.paint.getDataValue('line-width', tile.z, sourceFeature)
|
|
116
|
+
const lineColor = style.convertColor(style.paint.getDataValue('line-color', tile.z, sourceFeature))
|
|
117
|
+
const lineOpacity = style.paint.getDataValue('line-opacity', tile.z, sourceFeature)
|
|
118
|
+
const linePattern = style.paint.getDataValue('line-pattern', tile.z, sourceFeature)
|
|
119
|
+
if (linePattern) {
|
|
120
|
+
warnOnce('line图层:不支持纹理填充(line-pattern)')
|
|
121
|
+
continue
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const lineJoin = style.paint.getDataValue('line-join', tile.z, sourceFeature)
|
|
125
|
+
const lineCap = style.paint.getDataValue('line-cap', tile.z, sourceFeature)
|
|
126
|
+
if (lineJoin !== 'miter') {
|
|
127
|
+
warnOnce('line图层:line-join 仅支持 miter 模式')
|
|
128
|
+
}
|
|
129
|
+
if (lineCap !== 'butt') {
|
|
130
|
+
warnOnce('line图层:line-cap 仅支持 butt 模式')
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const geometryType = feature.geometry.type
|
|
134
|
+
const coordinates = feature.geometry.coordinates
|
|
135
|
+
if (geometryType == 'LineString') {
|
|
136
|
+
addPolyline(coordinates, lineWidth, lineColor, lineOpacity, sourceFeatureId, properties)
|
|
137
|
+
}
|
|
138
|
+
else if (geometryType == 'MultiLineString' || geometryType == 'Polygon') {
|
|
139
|
+
for (const ring of coordinates) {
|
|
140
|
+
addPolyline(ring, lineWidth, lineColor, lineOpacity, sourceFeatureId, properties)
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
else if (geometryType == 'MultiPolygon') {
|
|
144
|
+
for (const polygon of coordinates) {
|
|
145
|
+
for (const ring of polygon) {
|
|
146
|
+
addPolyline(ring, lineWidth, lineColor, lineOpacity, sourceFeatureId, properties)
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
warnOnce('line图层:不支持几何类型:' + geometryType);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
layer.offsets = []
|
|
156
|
+
layer.counts = []
|
|
157
|
+
|
|
158
|
+
this.layers.push(layer)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* @param {LineFeature} feature
|
|
163
|
+
*/
|
|
164
|
+
addFeature(feature) {
|
|
165
|
+
const geometryInstances = this.geometryInstances
|
|
166
|
+
const { coordinates, lineColor, lineWidth, lineOpacity } = feature
|
|
167
|
+
const colorBytes = lineColor.toBytes()
|
|
168
|
+
colorBytes[3] = Math.floor(colorBytes[3] * lineOpacity)
|
|
169
|
+
|
|
170
|
+
const positions = coordinates.map(coord => Cesium.Cartesian3.fromDegrees(coord[0], coord[1]))
|
|
171
|
+
|
|
172
|
+
const boundingSphere = Cesium.BoundingSphere.fromPoints(positions)
|
|
173
|
+
const cartographic = Cesium.Cartographic.fromCartesian(boundingSphere.center)
|
|
174
|
+
cartographic.height = 0//包围盒中心可能高于或者低于地面,需要避免双击锁定视角时进入地下
|
|
175
|
+
const center = Cesium.Cartographic.toCartesian(cartographic, null, cartesian)
|
|
176
|
+
|
|
177
|
+
const instance = new Cesium.GeometryInstance({
|
|
178
|
+
geometry: new Cesium.PolylineGeometry({
|
|
179
|
+
positions,
|
|
180
|
+
width: lineWidth,
|
|
181
|
+
}),
|
|
182
|
+
attributes: {
|
|
183
|
+
color: new Cesium.GeometryInstanceAttribute({
|
|
184
|
+
componentDatatype: Cesium.ComponentDatatype.UNSIGNED_BYTE,
|
|
185
|
+
componentsPerAttribute: 4,
|
|
186
|
+
normalize: true,
|
|
187
|
+
value: colorBytes
|
|
188
|
+
}),
|
|
189
|
+
},
|
|
190
|
+
//通过entity的形式暴露给Cesium pickEntity,这样点击时系统自带的inforbox可以弹出
|
|
191
|
+
id: new Cesium.Entity({
|
|
192
|
+
position: center,
|
|
193
|
+
id: feature.id,
|
|
194
|
+
properties: feature.properties
|
|
195
|
+
})
|
|
196
|
+
})
|
|
197
|
+
geometryInstances.push(instance)
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
createPrimitive() {
|
|
201
|
+
const primitive = new Cesium.Primitive({
|
|
202
|
+
geometryInstances: this.geometryInstances,
|
|
203
|
+
asynchronous: true,
|
|
204
|
+
appearance: new Cesium.PolylineMaterialAppearance({
|
|
205
|
+
flat: true,
|
|
206
|
+
translucent: false,
|
|
207
|
+
vertexShaderSource:/*glsl*/`
|
|
208
|
+
${Cesium._shadersPolylineCommon}
|
|
209
|
+
|
|
210
|
+
in vec4 color;
|
|
211
|
+
out vec4 v_color;
|
|
212
|
+
in vec3 position3DHigh;
|
|
213
|
+
in vec3 position3DLow;
|
|
214
|
+
in vec3 prevPosition3DHigh;
|
|
215
|
+
in vec3 prevPosition3DLow;
|
|
216
|
+
in vec3 nextPosition3DHigh;
|
|
217
|
+
in vec3 nextPosition3DLow;
|
|
218
|
+
in vec2 expandAndWidth;
|
|
219
|
+
in vec2 st;
|
|
220
|
+
in float batchId;
|
|
221
|
+
|
|
222
|
+
out float v_width;
|
|
223
|
+
out vec2 v_st;
|
|
224
|
+
out float v_polylineAngle;
|
|
225
|
+
|
|
226
|
+
void main()
|
|
227
|
+
{
|
|
228
|
+
float expandDir = expandAndWidth.x;
|
|
229
|
+
float width = abs(expandAndWidth.y) + 0.5;
|
|
230
|
+
bool usePrev = expandAndWidth.y < 0.0;
|
|
231
|
+
|
|
232
|
+
vec4 p = czm_computePosition();
|
|
233
|
+
vec4 prev = czm_computePrevPosition();
|
|
234
|
+
vec4 next = czm_computeNextPosition();
|
|
235
|
+
|
|
236
|
+
float angle;
|
|
237
|
+
vec4 positionWC = getPolylineWindowCoordinates(p, prev, next, expandDir, width, usePrev, angle);
|
|
238
|
+
gl_Position = czm_viewportOrthographic * positionWC;
|
|
239
|
+
|
|
240
|
+
v_width = width;
|
|
241
|
+
v_st.s = st.s;
|
|
242
|
+
v_st.t = czm_writeNonPerspective(st.t, gl_Position.w);
|
|
243
|
+
v_polylineAngle = angle;
|
|
244
|
+
v_color = color;
|
|
245
|
+
}
|
|
246
|
+
`,
|
|
247
|
+
fragmentShaderSource:/*glsl*/`
|
|
248
|
+
in vec2 v_st;
|
|
249
|
+
|
|
250
|
+
uniform vec4 tileId;
|
|
251
|
+
uniform sampler2D tileIdTexture;
|
|
252
|
+
|
|
253
|
+
void main()
|
|
254
|
+
{
|
|
255
|
+
vec2 id_st = gl_FragCoord.xy / czm_viewport.zw;
|
|
256
|
+
vec4 bgId = texture(tileIdTexture, id_st);
|
|
257
|
+
if (all(equal(bgId, tileId)) == false)
|
|
258
|
+
{
|
|
259
|
+
discard;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
czm_materialInput materialInput;
|
|
263
|
+
|
|
264
|
+
vec2 st = v_st;
|
|
265
|
+
st.t = czm_readNonPerspective(st.t, gl_FragCoord.w);
|
|
266
|
+
|
|
267
|
+
materialInput.s = st.s;
|
|
268
|
+
materialInput.st = st;
|
|
269
|
+
materialInput.str = vec3(st, 0.0);
|
|
270
|
+
|
|
271
|
+
czm_material material = czm_getMaterial(materialInput);
|
|
272
|
+
out_FragColor = vec4(material.diffuse + material.emission, material.alpha);
|
|
273
|
+
|
|
274
|
+
czm_writeLogDepth();
|
|
275
|
+
}
|
|
276
|
+
`,
|
|
277
|
+
material: new Cesium.Material({
|
|
278
|
+
fabric: {
|
|
279
|
+
//cesium不支持数组类型的uniform,我们在分配图层绘图命令的时候修改uniformMap
|
|
280
|
+
// uniforms: {
|
|
281
|
+
// dashLength: 16,
|
|
282
|
+
// arrayLength: 0,
|
|
283
|
+
// dasharray: []
|
|
284
|
+
// },
|
|
285
|
+
source:/*glsl*/`
|
|
286
|
+
const int maxArrayLength = 8;
|
|
287
|
+
|
|
288
|
+
in float v_width;
|
|
289
|
+
in vec4 v_color;
|
|
290
|
+
uniform float dashLength;
|
|
291
|
+
uniform float arrayLength;
|
|
292
|
+
uniform float dasharray[maxArrayLength];
|
|
293
|
+
in float v_polylineAngle;
|
|
294
|
+
|
|
295
|
+
mat2 rotate(float rad) {
|
|
296
|
+
float c = cos(rad);
|
|
297
|
+
float s = sin(rad);
|
|
298
|
+
return mat2(
|
|
299
|
+
c, s,
|
|
300
|
+
-s, c
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
czm_material czm_getMaterial(czm_materialInput materialInput)
|
|
305
|
+
{
|
|
306
|
+
czm_material material = czm_getDefaultMaterial(materialInput);
|
|
307
|
+
|
|
308
|
+
vec2 pos = rotate(v_polylineAngle) * gl_FragCoord.xy;
|
|
309
|
+
|
|
310
|
+
// Get the relative position within the dash from 0 to 1
|
|
311
|
+
float dashPosition = fract(pos.x / (v_width * dashLength * czm_pixelRatio));
|
|
312
|
+
|
|
313
|
+
float currDashPos = 0.;
|
|
314
|
+
for (int i = 0; i < maxArrayLength; i += 2) {
|
|
315
|
+
if(float(i) >= arrayLength) break;
|
|
316
|
+
|
|
317
|
+
float gapStart = currDashPos + dasharray[i] / dashLength;
|
|
318
|
+
float gapEnd = gapStart + dasharray[i + 1] / dashLength;
|
|
319
|
+
|
|
320
|
+
if(dashPosition > gapStart && dashPosition < gapEnd) {
|
|
321
|
+
discard;
|
|
322
|
+
break;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
currDashPos = gapEnd;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
vec4 fragColor = v_color;
|
|
329
|
+
fragColor = czm_gammaCorrect(fragColor);
|
|
330
|
+
material.emission = fragColor.rgb;
|
|
331
|
+
material.alpha = fragColor.a;
|
|
332
|
+
return material;
|
|
333
|
+
}
|
|
334
|
+
`
|
|
335
|
+
}
|
|
336
|
+
})
|
|
337
|
+
}),
|
|
338
|
+
})
|
|
339
|
+
|
|
340
|
+
//通过定义 Primitive 私有变量 _geometries、_batchTable 的 setter 和 getter,
|
|
341
|
+
//监听合批几何体和批次表的创建:
|
|
342
|
+
//1、几何体创建完成后,根据 batchId 和 featureId,计算每个图层几何体的起始索引(offset)和索引数量(count)
|
|
343
|
+
//2、批次表创建完成后,保存备用
|
|
344
|
+
let scope = this
|
|
345
|
+
Object.defineProperties(primitive, {
|
|
346
|
+
_geometries: {
|
|
347
|
+
get() {
|
|
348
|
+
return this._geometries_
|
|
349
|
+
},
|
|
350
|
+
set(geometries) {
|
|
351
|
+
this._geometries_ = geometries
|
|
352
|
+
if (geometries) {
|
|
353
|
+
scope.onGeometriesLoaded(geometries)
|
|
354
|
+
}
|
|
355
|
+
else {
|
|
356
|
+
scope = null
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
},
|
|
360
|
+
_batchTable: {
|
|
361
|
+
get() {
|
|
362
|
+
return this._batchTable_
|
|
363
|
+
},
|
|
364
|
+
set(batchTable) {
|
|
365
|
+
this._batchTable_ = batchTable
|
|
366
|
+
if (batchTable) {
|
|
367
|
+
scope.onBatchTableCreated(batchTable)
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
})
|
|
372
|
+
|
|
373
|
+
this.primitive = primitive
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* 根据 batchId 和 featureId,计算每个图层几何体的起始索引(offset)和索引数量(count)
|
|
378
|
+
* @param {Cesium.Geometry[]} geometries
|
|
379
|
+
*/
|
|
380
|
+
onGeometriesLoaded(geometries) {
|
|
381
|
+
//Cesium 几何体合批结果可能是多个几何体,对应多个 DrawCommand
|
|
382
|
+
for (let pass = 0; pass < geometries.length; pass++) {
|
|
383
|
+
const batches = {}
|
|
384
|
+
const geometry = geometries[pass];
|
|
385
|
+
const batchIds = geometry.attributes.batchId.values
|
|
386
|
+
const indices = geometry.indices
|
|
387
|
+
|
|
388
|
+
//提取每个批次的起始和结束索引
|
|
389
|
+
let currBatchId = -1
|
|
390
|
+
let currBatch = null
|
|
391
|
+
for (let i = 0; i < indices.length; i++) {
|
|
392
|
+
const vertIndex = indices[i]
|
|
393
|
+
const batchId = batchIds[vertIndex]
|
|
394
|
+
if (currBatchId !== batchId) {
|
|
395
|
+
currBatchId = batchId
|
|
396
|
+
currBatch = batches[currBatchId] = {
|
|
397
|
+
begin: i,
|
|
398
|
+
end: i
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
currBatch.end = i
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
//根据图层批次范围,提取图层几何体索引范围,即起始索引(offset)和索引数量(count)
|
|
405
|
+
for (const layer of this.layers) {
|
|
406
|
+
const { firstBatchId, lastBatchId } = layer
|
|
407
|
+
if (firstBatchId === -1 || lastBatchId === -1) {
|
|
408
|
+
continue
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
let begin = -1, end = -1
|
|
412
|
+
for (let batchId = firstBatchId; batchId <= lastBatchId; batchId++) {
|
|
413
|
+
const batch = batches[batchId]
|
|
414
|
+
if (batch) {
|
|
415
|
+
if (begin === -1) begin = batch.begin
|
|
416
|
+
end = batch.end
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
if (begin === -1 || end === -1) {
|
|
421
|
+
continue
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
//起始和结束索引,索引数量需要加1
|
|
425
|
+
layer.offsets[pass] = begin
|
|
426
|
+
layer.counts[pass] = end - begin + 1
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
/**
|
|
432
|
+
* 保存 Cesium Primitive 创建的批次表。图层样式变化时,通过更新批次表传递到GPU,同步更新渲染效果
|
|
433
|
+
* @param {Cesium.BatchTable} batchTable
|
|
434
|
+
*/
|
|
435
|
+
onBatchTableCreated(batchTable) {
|
|
436
|
+
this._batchTable = batchTable
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* 使用合批后的 drawCommand 创建副本,为渲染图层分配 drawCommand
|
|
441
|
+
* @param {Cesium.DrawCommand[]} batchedCommandList
|
|
442
|
+
* @param {VectorTileset} tileset
|
|
443
|
+
*/
|
|
444
|
+
createLayerCommands(batchedCommandList, tileset) {
|
|
445
|
+
const renderState = Cesium.RenderState.fromCache({
|
|
446
|
+
id: 'line',
|
|
447
|
+
blending: Cesium.BlendingState.ALPHA_BLEND,
|
|
448
|
+
depthMask: false,
|
|
449
|
+
depthTest: {
|
|
450
|
+
enabled: true
|
|
451
|
+
},
|
|
452
|
+
cull: {
|
|
453
|
+
enabled: true
|
|
454
|
+
},
|
|
455
|
+
colorMask: {
|
|
456
|
+
red: true,
|
|
457
|
+
green: true,
|
|
458
|
+
blue: true,
|
|
459
|
+
alpha: true
|
|
460
|
+
}
|
|
461
|
+
})
|
|
462
|
+
const tileId = this.tile.tileId
|
|
463
|
+
|
|
464
|
+
function modifyUniformMap(uniformMap, layer) {
|
|
465
|
+
uniformMap = {
|
|
466
|
+
...uniformMap
|
|
467
|
+
}
|
|
468
|
+
uniformMap.tileIdTexture = function () {
|
|
469
|
+
return tileset.tileIdTexture
|
|
470
|
+
}
|
|
471
|
+
uniformMap.tileId = function () {
|
|
472
|
+
return tileId.color
|
|
473
|
+
}
|
|
474
|
+
uniformMap.dasharray = function () {
|
|
475
|
+
return layer.dasharray
|
|
476
|
+
}
|
|
477
|
+
uniformMap.dashLength = function () {
|
|
478
|
+
return layer.dashLength
|
|
479
|
+
}
|
|
480
|
+
uniformMap.arrayLength = function () {
|
|
481
|
+
return layer.dasharray.length
|
|
482
|
+
}
|
|
483
|
+
return uniformMap
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
for (let i = 0; i < this.layers.length; i++) {
|
|
487
|
+
const layer = this.layers[i]
|
|
488
|
+
const layerCommandList = layer.commandList = []
|
|
489
|
+
|
|
490
|
+
for (let pass = 0; pass < batchedCommandList.length; pass++) {
|
|
491
|
+
const offset = layer.offsets[pass], count = layer.counts[pass]
|
|
492
|
+
if (typeof offset !== 'number' || typeof count !== 'number') {
|
|
493
|
+
continue
|
|
494
|
+
}
|
|
495
|
+
const command = batchedCommandList[pass]
|
|
496
|
+
//通过副本的 offset 和 count 指定图层的绘制范围
|
|
497
|
+
const layerCommand = Cesium.DrawCommand.shallowClone(command)
|
|
498
|
+
layerCommand.pass = Cesium.Pass.CESIUM_3D_TILE
|
|
499
|
+
layerCommand.uniformMap = modifyUniformMap(layerCommand.uniformMap, layer)
|
|
500
|
+
layerCommand.renderState = renderState
|
|
501
|
+
layerCommand.offset = offset
|
|
502
|
+
layerCommand.count = count
|
|
503
|
+
layerCommandList.push(layerCommand)
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
//标记 drawCommand 创建完成
|
|
508
|
+
this.state = 'done'
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
update(frameState, tileset) {
|
|
512
|
+
if (!this.geometryInstances) {
|
|
513
|
+
return
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
super.update(frameState, tileset)
|
|
517
|
+
|
|
518
|
+
if (!this.primitive && this.geometryInstances.length) {
|
|
519
|
+
this.createPrimitive()
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
if (this.primitive && this.state !== 'done' && this.state !== 'error') {
|
|
523
|
+
//先保存系统的 commandList
|
|
524
|
+
const preCommandList = frameState.commandList
|
|
525
|
+
//临时覆盖 frameState.commandList,用于获取合批之后的drawCommand
|
|
526
|
+
const batchedCommandList = frameState.commandList = []
|
|
527
|
+
|
|
528
|
+
//执行 primitive 的 update ,直到生成了合批后的drawCommand
|
|
529
|
+
try {
|
|
530
|
+
this.primitive.update(frameState)
|
|
531
|
+
} catch (err) {//如果报错,下一帧就不要再执行 update 了,以免重复打印错误信息
|
|
532
|
+
this.geometryInstances = []
|
|
533
|
+
this.state = 'error'
|
|
534
|
+
if (err.stack) console.trace(err.stack)
|
|
535
|
+
else console.error(err);
|
|
536
|
+
return
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
//使用合批后的 drawCommand 创建副本,为渲染图层分配 drawCommand
|
|
540
|
+
if (batchedCommandList.length > 0) {
|
|
541
|
+
this.createLayerCommands(batchedCommandList, tileset)
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
//恢复系统的 commandList
|
|
545
|
+
frameState.commandList = preCommandList
|
|
546
|
+
this.geometryInstances = []
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
if (this.primitive && frameState.camera.pitch > -1.309) {
|
|
550
|
+
warnOnce('line图层:不支持透视,建议保持相机俯仰角(pitch)小于 -75 度')
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
destroy() {
|
|
555
|
+
this.primitive = this.primitive && this.primitive.destroy()
|
|
556
|
+
this._batchTable = null
|
|
557
|
+
this.geometryInstances = null
|
|
558
|
+
|
|
559
|
+
super.destroy()
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
isDestroyed() {
|
|
563
|
+
return false
|
|
564
|
+
}
|
|
565
|
+
}
|