news 2026/7/12 10:29:00

Cesium 曲线管道教程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Cesium 曲线管道教程

曲线管道 ·Curve Pipe· ▶ 在线运行案例

  • 案例合集:三维可视化功能案例(threehub.cn)
  • 开源仓库github地址:https://github.com/z2586300277/three-cesium-examples
  • 400个案例代码:网盘链接

你将学到什么

  • Cesium Entity 高层实体 API

效果说明

本案例演示曲线管道效果:基于 WebGL 实现「曲线管道」可视化效果,附完整可运行源码;核心用到 Cesium。建议先打开文首在线案例查看动态画面,再对照下方源码逐步理解。

核心概念

  • Viewer聚合 Scene、Camera、Clock 与渲染循环,是 Cesium 应用入口。
  • Entity面向点线面/模型/标签的高层 API;与 Primitive 相比更适合交互与属性驱动。
  • 阅读下方完整源码时,建议从init/load/animate三条主线入手,再深入 shader 与工具函数。

实现步骤

  • 创建 Viewer,配置地形/影像(若案例需要)并设置初始相机
  • requestAnimationFrame循环中更新状态并 render(Cesium 为viewer.render或自动渲染)
  • 代码要点

    import * as Cesium from 'cesium'

    import { Color, defined, Event, Material, Property } from 'cesium'

    const box = document.getElementById('box')

    const viewer = new Cesium.Viewer(box, {

    animation: false,//是否创建动画小器件,左下角仪表

    baseLayerPicker: false,//是否显示图层选择器,右上角图层选择按钮

    baseLayer: Cesium.ImageryLayer.fromProviderAsync(Cesium.ArcGisMapServerImageryProvider.fromUrl(GLOBAL_CONFIG.getLayerUrl())),

    fullscreenButton: false,//是否显示全屏按钮,右下角全屏选择按钮

    timeline: false,//是否显示时间轴

    infoBox: false,//是否显示信息框

    })

    viewer._cesiumWidget._creditContainer.style.display = "none"

    viewer.clock.shouldAnimate = true

    //定位北京 viewer.camera.flyTo({

    destination: Cesium.Cartesian3.fromDegrees(116.41, 36.91, 1000000),

    orientation: {

    heading: Cesium.Math.toRadians(0),

    pitch: Cesium.Math.toRadians(-90),

    roll: 0

    }

    })

    /飞线材质类/ class PolylineTrailLinkMaterialProperty {

    constructor(image, color = Color.WHITE, duration = 1000, repeat = 60) {

    this._definitionChanged = new Event()

    this._color = undefined

    this.color = color

    this.duration = duration

    this._time = new Date().getTime()

    this.image = image

    Material._materialCache.addMaterial('PolylineTrailLink', {

    fabric: {

    type: 'PolylineTrailLink',

    uniforms: {

    color: color.withAlpha(1.0),

    image: image,

    time: 0,

    repeat

    },

    source:czm_material czm_getMaterial(czm_materialInput materialInput) { czm_material material = czm_getDefaultMaterial(materialInput); vec2 st = materialInput.st; vec4 sampledColor = texture(image, vec2(fract(repeat*st.s - time), st.t)); material.alpha = sampledColor.a * color.a; material.diffuse = (sampledColor.rgb + color.rgb) / 2.0; return material; }

    },

    translucent: () => true

    })

    }

    get isConstant() { return false }

    get definitionChanged() { return this._definitionChanged }

    getType(_) { return 'PolylineTrailLink' }

    getValue(time, result) {

    if (!defined(result)) result = {}

    result.color = Property.getValueOrClonedDefault(this._color, time, Color.WHITE, result.color)

    result.image = this.image

    result.time = (new Date().getTime() - this._time) % this.duration / this.duration

    return result

    }

    equals(other) { return this === other || Property.equals(this._color, other._color) }

    }

    // 生成一组飞线动画 [ [[116.41, 36.91], [130.40, 45.39]], [[116.41, 36.91], [114.11, 39.44]], [[116.41, 36.91], [109.62, 25.72]], [[116.41, 36.91], [121.48, 31.22]], [[116.41, 36.91], [13.78, 12.31]], [[116.41, 36.91], [74.12, 33.50]], ].forEach(([p1, p2]) => createPlaneCurve(p1, p2))

    // 组合 function createPlaneCurve(p1, p2) {

    const { curvePoints } = getGenerateCurve(p1, p2, { maxHeight: 100000 })

    viewer.entities.add({ polylineVolume: createCurvePipe(curvePoints)

    })

    }

    /生成曲线/ function getGenerateCurve(start, end, params = {}) {

    const [startLongitude, startLatitude] = start

    const [endLongitude, endLatitude] = end

    const startCartographic = Cesium.Cartographic.fromDegrees(startLongitude, startLatitude)

    const endCartographic = Cesium.Cartographic.fromDegrees(endLongitude, endLatitude)

    const geodesic = new Cesium.EllipsoidGeodesic(startCartographic, endCartographic)

    const curvePoints = []

    for (let t = 0; t <= 1; t += (params.step || 0.01)) {

    const pointCartographic = geodesic.interpolateUsingFraction(t)

    pointCartographic.height = (params.maxHeight || 400000)Math.sin(Math.PIt)

    const pointCartesian = Cesium.Cartographic.toCartesian(pointCartographic)

    curvePoints.push(pointCartesian)

    }

    endCartographic.height = 0

    const endPointCartesian = Cesium.Cartographic.toCartesian(endCartographic)

    curvePoints.push(endPointCartesian)

    function getCurvePointAtTime(t) {

    const pointCartographic = geodesic.interpolateUsingFraction(t)

    pointCartographic.height = (params.maxHeight || 400000)Math.sin(Math.PIt)

    return Cesium.Cartographic.toCartesian(pointCartographic)

    }

    return { curvePoints, getCurvePointAtTime }

    }

    function createCurvePipe(curvePoints, params = {}) {

    const getShape = (radius) => {

    const positions = [];

    for (let i = 0; i < 360; i++) {

    if (i % 1 === 0) {

    const radians = Cesium.Math.toRadians(i);

    positions.push(

    new Cesium.Cartesian2(

    (radius / 2) * Math.cos(radians),

    (radius / 2) * Math.sin(radians)

    )

    );

    }

    }

    return positions;

    }

    const radius = 16000.0

    const _ps = curvePoints.map(i => {

    const [longitude, latitude, height] = cartesian3ToDegrees(i)

    return Cesium.Cartesian3.fromDegrees(longitude, latitude, height - radius)

    })

    return {

    positions: _ps,

    shape: getShape(2 * radius),

    cornerType: Cesium.CornerType.ROUNDED,

    material: new PolylineTrailLinkMaterialProperty(FILE_HOST + 'images/channels/lmap.png', Cesium.Color.RED, 2000)

    }

    }

    function cartesian3ToDegrees(cartesian3, type = 'Array') {

    const cartographic = Cesium.Cartographic.fromCartesian(cartesian3) // 笛卡尔坐标转经纬度

    const longitude = Cesium.Math.toDegrees(cartographic.longitude) // 弧度转度

    const latitude = Cesium.Math.toDegrees(cartographic.latitude) // 弧度转度

    const height = cartographic.height // 高度

    return type === 'Array' ? [longitude, latitude, height] : { longitude, latitude, height }

    }

    完整源码:GitHub

    小结

    • 本文提供曲线管道完整 Cesium.js 源码与在线 Demo,建议先运行案例再改 uniform/参数做二次实验
    • 更多 Cesium.js 实战案例见 three-cesium-examples 合集 与 GitHub 开源仓库
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/12 10:27:19

ADS131M02与PIC18F47K40的高精度数据采集方案

1. 为什么选择ADS131M02与PIC18F47K40这对组合 在工业测量和医疗设备领域&#xff0c;ADC&#xff08;模数转换器&#xff09;的性能往往决定了整个系统的精度上限。ADS131M02是TI推出的一款24位Δ-Σ型ADC&#xff0c;其关键特性包括&#xff1a; 真正差分输入通道&#xff0…

作者头像 李华
网站建设 2026/7/12 10:26:00

C++头文件循环包含:原理剖析与工程化解决方案

1. 项目概述&#xff1a;当头文件“相爱相杀”时&#xff0c;编译器为何会崩溃&#xff1f;在C项目开发中&#xff0c;尤其是随着项目规模扩大、类之间关系变得复杂时&#xff0c;一个让新手甚至老手都容易踩坑的经典问题就是“头文件循环包含”。想象一下&#xff0c;你正在设…

作者头像 李华
网站建设 2026/7/12 10:25:11

终极指南:用BetterJoy让Switch控制器在PC上焕发新生

终极指南&#xff1a;用BetterJoy让Switch控制器在PC上焕发新生 【免费下载链接】BetterJoy Allows the Nintendo Switch Pro Controller, Joycons and SNES controller to be used with CEMU, Citra, Dolphin, Yuzu and as generic XInput 项目地址: https://gitcode.com/gh…

作者头像 李华
网站建设 2026/7/12 10:23:53

2026济南黄金回收白银回收铂金回收靠谱临街实体公安备案支持到店核验门店联系方式推荐

济南黄金白银铂金回收2026实测榜单&#xff5c;公安备案临街实体门店推荐 济南黄金回收哪家靠谱&#xff5c;工商公安双备案中检认证实体门店 济南作为山东省会城市&#xff0c;贵金属回收店铺遍布历下、市中、槐荫、天桥、历城等各大城区。小编实地走访对比多家门店&#xff0…

作者头像 李华
网站建设 2026/7/12 10:20:51

BEV车道线4D自动标注:VMA轻量化标定与工程落地实践

1. 项目概述&#xff1a;为什么“BEV车道线4D AutoLabeling-VMA”不是又一个噱头&#xff0c;而是工程落地的临门一脚 你是不是也刷到过这类标题&#xff1a;“BEV车道线4D AutoLabeling-VMA复现”&#xff0c;点进去却发现通篇是论文截图、公式堆砌&#xff0c;或者干脆就是一…

作者头像 李华