前言
本篇博客将会尝试还原 大疆司空2 平台的栅栏飞行区材质,并将材质应用到 Primitive 中。
司空2 效果
多边形和圆形飞行区栅栏效果
圆形栅栏效果
编辑中效果
如何绘制圆形
目前 Cesium 支持的圆形 geometry 只有 ellipse,刚开始我也尝试过用 ellipse 来实现,但是栅栏效果是个 polyline 材质
当内部填充区域通过 ellipse 实现,但是外围通过 polyline 来包裹的话,要实现完全贴合的包围效果会比较难。
要以相对简单的方式实现完全贴合的包围效果,可以通过圆心坐标和半径,通过圆心坐标向外移动半径距离,得出作为填充区域的 polygon 和包围边框的 polyline 的坐标。
这样就可以得到一个完全包围的圆形效果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
/**
* 创建圆形 polygon 坐标
* @param {Array} centerLatlng 圆心坐标(经纬度)
* @param {Number} radius 半径
*/
export const generateCirclePolygon = (centerLatlng, radius) => {
const point = turf.point([centerLatlng[0], centerLatlng[1]])
const polylinePointsArray = []
for (let i = 0; i <= 360; i = i + 1) {
if (i % 3 === 0) continue
const targetLatlng = turf.destination(point, radius, i, {
units: 'meters'
}).geometry.coordinates
const resLatlng = [targetLatlng[0], targetLatlng[1], 0]
polylinePointsArray.push(resLatlng)
}
return polylinePointsArray.filter((_, i) => i % 2 === 0)
}
|
创建材质
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
|
// 创建 polyline 栅栏材质
export function createFenceMaterial() {
const source = `#ifdef GL_OES_standard_derivatives\n
#extension GL_OES_standard_derivatives : enable\n
#endif\n\n\n
uniform vec4 color;
uniform float dashLength;
uniform float dashPattern;
uniform float maskLength;
uniform float outlineWidth;
uniform vec4 outlineColor;
in float v_polylineAngle;
in float v_width; // 线段宽度
mat2 rotate(float rad) {
float c = cos(rad);
float s = sin(rad);
return mat2(
c, s,
-s, c
);
}
// 计算给定输入的材质
// 栅栏形状的polyline是以虚线材质未基础,往虚线空隙里面填充外轮廓是透明的外轮廓线所绘制的
czm_material czm_getMaterial(czm_materialInput materialInput)
{
// 获取默认的材质
czm_material material = czm_getDefaultMaterial(materialInput);
// 外轮廓纹理部分
// 获取标准化的纹理坐标
vec2 st = materialInput.st;
//v_width是整个线宽,outlineWidth是轮廓线宽,两者差值的一半就是外轮廓线内部线条的宽度
float halfInteriorWidth = 0.5 * (v_width - outlineWidth) / v_width;
// 判断当前的纹理坐标是否在内部线条范围内,如果在范围内,b值将为1,否则为0。step(edge, x)函数会返回一个值,如果x < edge,返回0.0,否则返回1.0
float b = step(0.5 - halfInteriorWidth, st.t);
b *= 1.0 - step(0.5 + halfInteriorWidth, st.t);
//计算当前片元距离最近的颜色分隔线的距离,这个距离将被用于后面的抗锯齿处理。
float d1 = abs(st.t - (0.5 - halfInteriorWidth));
float d2 = abs(st.t - (0.5 + halfInteriorWidth));
float dist = min(d1, d2);
// 根据b的值选择颜色,如果b是1,则选择color,否则选择outlineColor。这就确定了当前片元的基础颜色
vec4 currentColor = mix(outlineColor, color, b);
// 使用czm_antialias()函数进行抗锯齿处理,输入参数包括轮廓色,内部色,当前色和距离
vec4 outColor = czm_antialias(outlineColor, color, currentColor, dist);
// 对经过抗锯齿处理后的颜色进行伽马校正
vec4 gapColor = czm_gammaCorrect(outColor);
// 虚线纹理部分
// 计算旋转后的片元位置。
vec2 pos = rotate(v_polylineAngle) * gl_FragCoord.xy;
// 计算当前片元在虚线模式中的位置。
float dashPosition = fract(pos.x / (dashLength * czm_pixelRatio));
// 计算对应虚线模式的索引位置。
float maskIndex = floor(dashPosition * maskLength);
// 通过使用虚线模式和索引位置,计算当前位置是否应有线条。
float maskTest = floor(dashPattern / pow(2.0, maskIndex));
// 如果当前位置应为虚线的间隔部分,则颜色设为gapColor,否则设为color。
vec4 fragColor = (mod(maskTest, 2.0) < 1.0) ? gapColor : color;
if (fragColor.a < 0.005) {
discard;
}
// 设置材质的颜色和透明度,后返回处理过后的材质
fragColor = czm_gammaCorrect(fragColor);
material.emission = fragColor.rgb;
material.alpha = fragColor.a;
return material;
}`
if (!Cesium.Material._materialCache.getMaterial('PolylineFenceMaterial')) {
Cesium.Material._materialCache.addMaterial('PolylineFenceMaterial', {
fabric: {
type: 'PolylineFenceMaterial',
uniforms: {
color: new Cesium.Color(1, 1, 1, 1),
outlineColor: new Cesium.Color(1, 1, 1, 1),
dashLength: 10,
dashPattern: 15,
outlineWidth: 16,
maskLength: 16
},
source: source
},
translucent: function (material) {
return true
}
})
}
}
|
应用材质
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
|
/**
* 添加贴地多段线
* @param {* Object} cartesian xyz 坐标
*/
addGroundPolyline(cartesian) {
// 创建折线Primitive
const polyline = new Cesium.GeometryInstance({
id: uuid(),
geometry: new Cesium.GroundPolylineGeometry({
positions: cartesian,
loop: true,
width: 14.0
})
})
// 通过自定义材质创建 primitive
viewer.scene.groundPrimitives.add(
new Cesium.GroundPolylinePrimitive({
geometryInstances: polyline,
appearance: new Cesium.EllipsoidSurfaceAppearance({
material: new Cesium.Material({
fabric: {
type: 'PolylineFenceMaterial',
uniforms: {
color: Cesium.Color.fromCssColorString('#fa0707'),
outlineColor: new Cesium.Color(1, 1, 1, 0),
dashLength: 10,
dashPattern: 15,
outlineWidth: 11,
maskLength: 16
}
}
})
})
})
)
}
|
(完)