Cesium中实现三维风场粒子效果

三维风场

三维风场通常指的是在三维空间中,记录每一点的风速和风向分布情况的数据。它不再像地面天气预报那样只描述一个二维平面(例如地面以上10米)的风,而是完整地描述了风在水平方向(东-西,南-北)垂直方向(上-下) 上的运动。

简单来说,这个数据是一个三维矢量场,空间中的每一个点都有一个风速和风向确定的矢量箭头。

风场示例

通常,三维风场数据包含三个重要的分量:

  1. U 分量:表示东西方向的风速。

    • 正值:西风(风从西边吹来,向东吹)。
    • 负值:东风(风从东边吹来,向西吹)。
  2. V 分量:表示南北方向的风速。

    • 正值:南风(风从南边吹来,向北吹)。
    • 负值:北风(风从北边吹来,向南吹)。
  3. W 分量:表示垂直方向的风速。

    • 正值:上升气流。
    • 负值:下沉气流。

我们日常感知的风主要是U和V分量(水平风),而W分量(垂直风)通常非常微弱(除了一些特殊天气系统外),但它在天气系统的形成和发展中起着至关重要的作用。

三维风场粒子

用粒子展示风场是三维风场其中一种展示手段。

粒子的计算方式从本质上分为两种,一种CPU计算,一种GPU计算。

CPU计算实现起来比较简单,但是无法承载大量的粒子同时计算,加上js是单线程语言,容易阻塞主线程的其他计算。

GPU计算稍微复杂一点,但是得益于GPU并行计算的优势,GPU计算能支持海量的粒子同时更新位置,很适合来做三维风场粒子这种简单而重复的计算。

本文实现的粒子效果,就是通过GPU的方式来进行计算的。

GPU粒子实现思路

粒子计算

利用WebGL来使用GPU计算三维粒子的位置思路比较简单:

  1. 我们首先需要在着色器中弄两个随机数算子:
    • 用于生成粒子位置的随机数算子,生成一个 vec3(0,0,0) 到 vec3(1,1,1) 的三维随机数。
    • 用于生成粒子的生命值的随机数算子,这个随机数算子的生成范围我设定在 [0.3, 1] 之间。
  2. 利用上面的随机数算子生成一张记录初始粒子状态的纹理,这张纹理的每个像素记录了一个粒子的位置和当前生命值(RGB三个通道存储粒子位置,A通道存储生命值)。
  3. 根据三维风场数据生成一张三维纹理,存储UVW信息。
  4. 根据粒子的位置采样UVW纹理,获取当前位置风的“方向”和“风速”,根据这些信息计算当前粒子在下一帧的位置,并且每次更新都减少粒子的生命值。如果生命值小于或者等于0,那么重新根据随机数算子,计算粒子重生的位置和新生命值。

实际的计算流程图如下:

粒子计算流程图

粒子展示

到这里我们已经完成了三维粒子的位置计算,但是怎么展示呢?

正常的思路我们可能会想到,既然粒子的位置信息都记录在了纹理上,那么我们读取纹理,然后利用 PointPrimitiveCollection 绘制出来不就行了吗。

实际上这种做法效率并不高,因为要涉及将GPU里面的纹理信息提取到CPU,再通过CPU组织粒子坐标信息发送到GPU进行渲染。会存在GPU和CPU之间信息传递的消耗。

更高级的做法是直接在GPU当中对纹理的每个像素进行解析和渲染,那么怎么才能做到渲染一堆点,但是每个点分别采样不同的粒子纹理像素呢?

我们可以使用实例化渲染的技术来实现这一步骤,关于Cesium的实例化渲染,大家可以看这篇文章
Cesium 高性能扩展之 DrawCommand(四):阴影和实例化

具体做法是在VertexArrayAttribute中我们传每个点的索引值(用来获取当前点应该采样粒子纹理上的第几个像素),然后在顶点着色器中将这个索引值换算成uv坐标,来采样粒子纹理,并计算粒子的实际位置,以此来作为当前点的位置。

实际效果展示


Cesium中实现三维风场粒子效果
https://www.liaomz.top/2025/09/11/cesium-zhong-shi-xian-san-wei-feng-chang-li-zi-xiao-guo/
作者
发布于
2025年9月11日
许可协议