Cesium箭头线实现原理分析

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

 图1 Cesium箭头线效果

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

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

图2 普通带宽度的线

图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)。

图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 非箭头充区域定义

 

图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 箭头充区域定义

图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));

 图11 箭头线最终填充颜色

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

引用\[1\]中的代码是用于计算两点之间距离的函数,它使用了经纬度坐标来计算地球上两点之间的直线距离。这段代码并不是用于实现流动箭头线的,而是用于计算距离的。要实现流动箭头线,你可以使用Cesium库来创建和操作3D地球场景。以下是一个简单的示例代码,展示了如何在Cesium中实现流动箭头线: ```javascript // 创建Cesium Viewer var viewer = new Cesium.Viewer('cesiumContainer'); // 创建起点和终点的坐标 var startPoint = Cesium.Cartesian3.fromDegrees(lon1, lat1, height1); var endPoint = Cesium.Cartesian3.fromDegrees(lon2, lat2, height2); // 创建流动箭头线的路径 var path = new Cesium.SampledPositionProperty(); path.addSample(Cesium.JulianDate.now(), startPoint); path.addSample(Cesium.JulianDate.now(), endPoint); // 创建流动箭头线的样式 var arrowMaterial = new Cesium.PolylineArrowMaterialProperty(Cesium.Color.RED); var arrowLine = viewer.entities.add({ polyline: { positions: path, width: 5, material: arrowMaterial } }); // 设置箭头线的动画效果 viewer.clock.onTick.addEventListener(function(clock) { var time = clock.currentTime; arrowLine.polyline.positions = path; arrowLine.polyline.width = 5; arrowLine.polyline.material = arrowMaterial; }); // 设置相机视角 viewer.camera.flyTo({ destination: Cesium.Cartesian3.fromDegrees((lon1 + lon2) / 2, (lat1 + lat2) / 2, 10000) }); ``` 这段代码使用Cesium库创建了一个Viewer对象,并在地球上创建了起点和终点的坐标。然后,它使用SampledPositionProperty来定义流动箭头线的路径,并使用PolylineArrowMaterialProperty来定义箭头线的样式。最后,通过监听clock的onTick事件,实现了箭头线的动画效果。你可以根据需要修改起点和终点的坐标,以及箭头线的样式和动画效果。 #### 引用[.reference_title] - *1* [cesium 生成抛物线 流动线](https://blog.csdn.net/qq_40216244/article/details/118890793)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值