《Cesium 中两点绘制线的实现:实线、虚线、动态线、流动线详解》

摘要

在 Cesium 三维地球可视化开发中,两点之间绘制线是常见的需求。本文详细介绍如何在 Cesium 中实现两点间绘制实线、虚线、动态线和流动线,并提供完整的代码示例,方便开发者快速上手,满足不同场景下的可视化需求。

一、环境与依赖

本文代码基于 Cesium 库进行开发,在使用代码前,请确保已引入 Cesium 库文件。可以通过 CDN 引入:

\<script src="https://cesium.com/downloads/cesiumjs/releases/1.106/Build/Cesium/Cesium.js">\</script>

\<link href="https://cesium.com/downloads/cesiumjs/releases/1.106/Build/Cesium/Widgets/widgets.css" rel="stylesheet">

或者通过 npm 安装后在项目中引入:

npm install cesium

二、两点绘制实线

在 Cesium 中绘制两点间的实线较为简单,直接通过viewer.entities.add方法添加polyline实体即可,示例代码如下:

// 假设已有viewer实例

let startPoint = Cesium.Cartesian3.fromDegrees(116.38, 39.90);

let endPoint = Cesium.Cartesian3.fromDegrees(116.40, 39.92);

let lineEntity = viewer.entities.add({

  polyline: {
      positions: [startPoint, endPoint],

      width: 5,

    material: Cesium.Color.RED // 设置线的颜色

}

});

上述代码中,通过Cesium.Cartesian3.fromDegrees将经纬度坐标转换为笛卡尔坐标,然后在polyline配置中指定起止点坐标、线宽和颜色,即可完成实线绘制。

三、两点绘制虚线

绘制虚线可以使用PolylineGlowMaterialProperty材质来实现,该材质通过设置特定参数模拟虚线效果,示例代码如下:

// 假设已有viewer实例

var first = Cesium.Cartesian3.fromDegrees(116.38, 39.90);

var end = Cesium.Cartesian3.fromDegrees(116.40, 39.92);

// 计算两个点的中点坐标&#x20;

var midpoint = Cesium.Cartesian3.midpoint(first, end, new Cesium.Cartesian3());

// 创建虚线材质

var dashMaterial = new Cesium.PolylineGlowMaterialProperty({
<think>我们正在使用Cesium库,目标是创建两个地理坐标点之间的动态线段(流动效果)。根据引用[^1]中提到的,我们可以通过自定义材质来实现流动线效果。 步骤: 1. 创建两个点(起点和终点)之间的线段(实线)。 2. 使用自定义材质(Material)来创建流动效果,这通常涉及到使用着色器(GLSL)编写材质,并在材质中根据时间变化来改变纹理坐标,从而实现流动的视觉效果。 引用[^1]中提到,他们提供了完整的代码示例,包括实线虚线动态线流动线。因此,我们可以参考其中的流动线实现方法。 具体实现思路: - 使用Cesium.PolylineGeometry创建一条线段。 - 为这条线段应用自定义的材质,材质中需要包含时间变量,以实现动态效果。 - 流动效果通常是通过在着色器中沿着线的方向移动纹理(比如一个渐变的透明度纹理)来实现的。 以下是一个简单的实现示例: 1. 定义流动线的材质(使用GLSL编写顶点着色器和片元着色器): - 顶点着色器:传递纹理坐标(沿着线的方向,从0到1)。 - 片元着色器:根据时间变化和纹理坐标计算颜色,通常使用一个渐变纹理,并随时间移动纹理坐标。 2. 创建材质,并在材质中更新统一变量(uniforms)的时间。 3. 创建线段实体(Entity)或图元(Primitive),并应用该材质。 由于在Cesium中,我们通常使用Entity或Primitive API来添加图形。这里我们使用Primitive,因为它更灵活,特别是对于自定义材质。 注意:Cesium中,线段的材质需要支持多段线(polyline),所以我们需要使用`PolylineMaterialAppearance`。 但是,对于流动线,我们可能需要自己编写整个材质和外观(Appearance)。不过,我们可以通过创建一个自定义材质对象,然后将其用于PolylineGeometryInstance。 参考引用[^1]中的示例,我们可以这样实现: 步骤1:定义材质(Material)的源(Source) 我们可以创建一个自定义材质,命名为`DynamicLineMaterial`,它包含一个时间参数。 步骤2:创建线段几何体 使用起点和终点的坐标创建`Cesium.PolylineGeometry`。 步骤3:创建图元(Primitive)并添加到场景中 由于代码较长,下面给出关键代码片段: 首先,定义材质: ```javascript // 自定义流动线材质 const dynamicLineMaterial = new Cesium.Material({ fabric: { type: 'DynamicLine', uniforms: { color: new Cesium.Color(1.0, 0.0, 0.0, 1.0), // 线的颜色 speed: 1.0, // 流动速度 time: 0, // 时间,需要在渲染时更新 image: Cesium.Material.DefaultImageId // 可以使用默认的白色纹理,或者使用自定义的渐变纹理 }, source: ` czm_material czm_getMaterial(czm_materialInput materialInput) { czm_material material = czm_getDefaultMaterial(materialInput); // 获取纹理坐标(这里我们使用st,在Polyline中,st.s是沿着线的方向,0到1) vec2 st = materialInput.st; // 根据时间移动纹理坐标(减去时间,形成从起点到终点的流动) st.t = fract(st.t - time * speed); // 使用一个渐变纹理,这里我们用一个简单的渐变代替,实际中可以使用纹理图 // 或者用sin函数等生成周期性的透明度变化 float alpha = sin(st.t * 3.1415926); // 0到1再到0,形成一个脉冲 material.alpha = alpha; material.diffuse = color.rgb; return material; } ` } }); ``` 但是,请注意,上面的着色器代码只是一个示例,实际效果可能需要调整。另外,在Cesium中,线段的材质输入中,`st`的t方向是沿着线的长度方向(从0到1),s方向是垂直方向(0到1,但通常我们只使用t)。 步骤2和3:创建线段并添加到场景 ```javascript // 起点和终点(经纬度坐标,高度) const start = Cesium.Cartesian3.fromDegrees(116.391, 39.907, 0); const end = Cesium.Cartesian3.fromDegrees(116.41, 39.92, 0); // 创建线段几何体 const polylineGeometry = new Cesium.PolylineGeometry({ positions: [start, end], width: 5.0 // 线宽 }); // 创建几何实例 const geometryInstance = new Cesium.GeometryInstance({ geometry: polylineGeometry }); // 创建外观,使用自定义材质 const appearance = new Cesium.PolylineMaterialAppearance({ material: dynamicLineMaterial }); // 创建图元 const primitive = new Cesium.Primitive({ geometryInstances: geometryInstance, appearance: appearance, asynchronous: false // 同步创建,便于立即显示 }); // 添加到场景 viewer.scene.primitives.add(primitive); ``` 步骤4:更新材质的时间 我们需要在每一帧更新材质中的时间uniform。 ```javascript viewer.scene.preUpdate.addEventListener(function(scene, time) { // 获取材质,并更新time dynamicLineMaterial.uniforms.time = Cesium.JulianDate.now(viewer.clock.currentTime).secondsOfDay / 10.0; }); ``` 注意:上面的更新方式只是示例,实际可以根据需要调整时间单位。 但是,上述实现存在一个问题:我们无法在材质中直接使用`czm_frameTime`(Cesium内置的帧时间)吗?实际上,在自定义材质的源中,我们可以使用`czm_frameTime`,但是这里我们通过uniform传递时间更可控。 另外,上面的着色器效果可能不够理想,我们可以改进: 例如,使用一个纹理图来模拟流动的光带,通过移动纹理坐标来实现流动。 改进的材质定义(使用纹理): ```javascript // 首先,我们可以创建一个Canvas来生成一个渐变纹理(或者使用图片) const canvas = document.createElement('canvas'); canvas.width = 256; canvas.height = 1; const context = canvas.getContext('2d'); const gradient = context.createLinearGradient(0, 0, 256, 0); gradient.addColorStop(0, 'rgba(0, 255, 255, 0)'); gradient.addColorStop(0.25, 'rgba(0, 255, 255, 1)'); gradient.addColorStop(0.75, 'rgba(0, 255, 255, 1)'); gradient.addColorStop(1, 'rgba(0, 255, 255, 0)'); context.fillStyle = gradient; context.fillRect(0, 0, 256, 1); const flowTexture = new Cesium.Texture({ context: context, source: canvas }); // 然后,在材质中使用这个纹理 const dynamicLineMaterial = new Cesium.Material({ fabric: { type: 'DynamicLine', uniforms: { color: new Cesium.Color(0.0, 1.0, 1.0, 1.0), // 可以叠加颜色 speed: 1.0, time: 0, flowTexture: flowTexture // 使用我们创建的纹理 }, source: ` uniform sampler2D flowTexture; uniform float speed; uniform float time; uniform vec4 color; czm_material czm_getMaterial(czm_materialInput materialInput) { czm_material material = czm_getDefaultMaterial(materialInput); vec2 st = materialInput.st; // 移动纹理坐标,形成流动 float t = fract(st.t - time * speed); // 从纹理中取颜色(纹理的s方向是0到1,t方向为0) vec4 texColor = texture2D(flowTexture, vec2(t, 0.0)); material.alpha = texColor.a * color.a; material.diffuse = color.rgb * texColor.rgb; // 混合颜色 return material; } ` } }); ``` 这样,流动效果会更加平滑。注意,纹理是一维的(高度为1),所以我们使用t坐标的0.0。 最后,记得在渲染循环中更新时间: ```javascript viewer.scene.preUpdate.addEventListener(function() { // 这里使用秒数,速度可以调整 dynamicLineMaterial.uniforms.time = Cesium.JulianDate.now(viewer.clock.currentTime).secondsOfDay; }); ``` 注意:由于`secondsOfDay`是一天的秒数,数值很大,所以我们在着色器中用fract取小数部分,这样就会形成循环。 以上就是一个简单的流动线实现。根据引用[^1]中的描述,他们可能提供了更完整的示例,包括如何调整速度、颜色等。 另外,引用[^2]中提供了Cesium中文API文档,如果在实现过程中需要查询API,可以参考。 由于代码较长,且需要结合具体的Cesium场景,建议用户根据实际情况调整。 相关问题: 1. 如何调整流动线的速度和颜色? 2. 如何实现多条流动线? 3. 流动线在3D地球上的高度如何设置?</think>### Cesium两点动态流动线实现详解Cesium实现两点间的动态流动线效果,需要结合自定义材质和着色器编程。以下是完整实现方案: #### 核心实现代码 ```javascript // 1. 创建起点和终点(以北京和上海为例) const start = Cesium.Cartesian3.fromDegrees(116.40, 39.90); // 北京 const end = Cesium.Cartesian3.fromDegrees(121.47, 31.23); // 上海 // 2. 创建流动线材质 const flowMaterial = new Cesium.Material({ fabric: { type: 'FlowLine', uniforms: { color: new Cesium.Color(0.0, 0.7, 1.0, 0.8), // 流动线颜色 speed: 0.5, // 流动速度 image: Cesium.Material.DefaultImageId // 默认纹理 }, source: ` uniform vec4 color; uniform float speed; czm_material czm_getMaterial(czm_materialInput materialInput) { czm_material material = czm_getDefaultMaterial(materialInput); // 计算纹理坐标(沿线段方向) float t = materialInput.st.t; // 创建动态偏移效果 float time = fract(czm_frameNumber * speed / 1000.0); float alpha = 0.0; // 生成流动光带效果 if (t > time - 0.1 && t < time) { alpha = smoothstep(0.0, 1.0, (t - (time - 0.1)) * 10.0); } material.alpha = alpha * color.a; material.diffuse = color.rgb; return material; } ` } }); // 3. 创建动态线段实体 const flowLine = viewer.entities.add({ polyline: { positions: [start, end], width: 8, // 线宽 material: flowMaterial, // 应用自定义材质 arcType: Cesium.ArcType.NONE // 直线连接 } }); // 4. 添加起点终点标记(可选) viewer.entities.add({ position: start, point: { pixelSize: 15, color: Cesium.Color.RED } }); viewer.entities.add({ position: end, point: { pixelSize: 15, color: Cesium.Color.GREEN } }); ``` #### 关键实现原理 1. **着色器动态效果**: - 通过 `czm_frameNumber` 获取连续帧数实现动画效果 - 使用 `fract()` 函数创建循环流动效果 - `smoothstep()` 函数实现光带平滑过渡 2. **参数控制**: - `speed`:控制光点流动速度(值越大越快) - `color`:RGBA格式控制线条颜色和透明度 - `width`:控制线条视觉宽度 #### 效果优化建议 1. **多段线支持**: ```javascript // 创建多节点流动线 const positions = Cesium.Cartesian3.fromDegreesArray([ 116.40, 39.90, // 北京 117.20, 38.90, // 天津 121.47, 31.23 // 上海 ]); ``` 2. **3D地形适配**: ```javascript polyline: { positions: positions, clampToGround: true // 贴地效果 } ``` 3. **性能优化**: ```javascript // 使用Primitive替代Entity提升性能 const primitive = new Cesium.Primitive({ geometryInstances: new Cesium.GeometryInstance({ geometry: new Cesium.PolylineGeometry({ positions: positions, width: 8 }) }), appearance: new Cesium.PolylineMaterialAppearance({ material: flowMaterial }) }); ``` #### 完整示例效果 实现的光带效果会沿着线段方向循环流动,形成从起点到终点的动态光带效果,通过调整 `speed` 参数可控制光带移动速度,通过修改 `color` 可改变光带颜色[^1]。 [^1]:Cesium两点绘制线实现实线虚线动态线流动线详解
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值