Cesium箭头线实现原理分析

Cesium原生提供了箭头线的材质,效果如图1所示

Cesium箭头线实现原理分析_第1张图片 图1 Cesium箭头线效果

由于遇到了改造箭头线材质的需求,因此花了一些时间对箭头线材质的原理做了一些了解。在此总结和分享,不足之处也请大家指正。

Cesium在内部做了哪些操作,使得我们通常认为的如图2所示的一根带宽度线变为如图3所示的箭头线的呢?

Cesium箭头线实现原理分析_第2张图片

图2 普通带宽度的线

Cesium箭头线实现原理分析_第3张图片

图3 箭头线轮廓

Cesium箭头线材质的着色器代码位于Source/Shaders/Materials/PolylineArrowMaterial.glsl下。

这里对关键代码进行分析:

(1)计算非箭头部分占比

#ifdef GL_OES_standard_derivatives
    float base = 1.0 - abs(fwidth(st.s)) * 10.0 * czm_pixelRatio;
#else
    float base = 0.975; // 2.5% of the line will be the arrow head
#endif

表4 计算非箭头部分的占比

表4代码中定义的变量base用于指定非箭头部分的占比,默认开启了GL_OES_standard_derivatives扩展,执行第一个分支。

fwidth(v) = abs( ddx(v) )+ abs(ddy(v))

ddx(v) = 该像素点右边的v值 - 该像素点的v值

ddy(v) = 该像素点下面的v值 - 该像素点的v值

fwidth(st.s) 表示当前像素相邻两个像素纹理坐标s分量的差值,可以看出箭头部分的占比取决于纹理坐标值的差异大小。

(2)定义箭头斜边

vec2 center = vec2(1.0, 0.5);
float ptOnUpperLine = getPointOnLine(vec2(base, 1.0), center, st.s);
float ptOnLowerLine = getPointOnLine(vec2(base, 0.0), center, st.s);

 表5-1 计算箭头斜边-定义关键点

float getPointOnLine(vec2 p0, vec2 p1, float x)
{
    float slope = (p0.y - p1.y) / (p0.x - p1.x);
    return slope * (x - p0.x) + p0.y;
}

表5-2 计算箭头斜边-其他片元拉到斜边上

表5-1和5-2的代码定义了箭头的斜边。给定三个点center、(base, 1.0)、(base, 0.0),假设当前正在处理的片元坐标为(st.s, st.t)。

Cesium箭头线实现原理分析_第4张图片

图5-3 箭头斜边片元处理

float slope = (p0.y - p1.y) / (p0.x - p1.x);  这句代码计算的是一个正切值tanθ;

getPointOnLine函数的返回值 slope * (x - p0.x) + p0.y 就是把当前处理的片元拉到斜边上,而且还是拉到对称的斜边上。

(3)计算非箭头区域

Cesium用glsl的step函数做了一个小技巧,把箭头区域和两侧一部分区域剔除,留下s值为1的区域作为非箭头区域,其余区域s均为0。

float halfWidth = 0.15;
float s = step(0.5 - halfWidth, st.t);
s *= 1.0 - step(0.5 + halfWidth, st.t);
s *= 1.0 - step(base, st.s);

 表6 非箭头充区域定义

 Cesium箭头线实现原理分析_第5张图片

图7 非箭头区域 

(4)计算箭头区域 

和步骤(3)用的技巧类似,留下t值为1的区域作为箭头区域,其余区域t值均为0。

float t = step(base, materialInput.st.s);
t *= 1.0 - step(ptOnUpperLine, st.t);
t *= step(ptOnLowerLine, st.t);

表8 箭头充区域定义

Cesium箭头线实现原理分析_第6张图片

图10 箭头区域 

(5)填充箭头线 

这两句是最后决定箭头线着色的地方。使用glsl的mix函数,s + t 为1的区域,也就是图7和图10中s和t为1的区域被赋予颜色,其他区域都为透明。

vec4 outsideColor = vec4(0.0);
vec4 currentColor = mix(outsideColor, color, clamp(s + t, 0.0, 1.0));

Cesium箭头线实现原理分析_第7张图片 图11 箭头线最终填充颜色

除此之外,箭头线还用到了抗锯齿的技术。本文主要总结箭头线的形状是如何形成的,抗锯齿相关原理后续有机会再总结和分享。

你可能感兴趣的:(Cesium,图形渲染)