WebGPU N 体模拟(N-body)

GPU 计算 5,000 ~ 20,000 个粒子 —— 初始数据由 Rust WASM 生成

🖱️ 单击 添加粒子团  |  O(n²) WGSL 计算着色器  |  对比 CPU 粒子物理

📖 原理说明

与「粒子物理」相同的 N 体引力模拟,但物理计算和渲染都放到 GPU 上完成,可以实时模拟成千上万个粒子。Rust/WASM 只负责生成粒子的初始位置和速度。

🧮算法原理

工作组数 = ⌈粒子数 / 256⌉每个线程负责 1 个粒子
计算着色器(Compute Shader)
用 WGSL 编写。每个 GPU 线程负责一个粒子,遍历所有其他粒子累加引力,然后更新自己的速度和位置。每个工作组 256 个线程,每帧派发 ⌈粒子数 / 256⌉ 个工作组。
同样是 O(n²)
算法复杂度和 CPU 版一样,但 GPU 有成百上千个核心同时计算,所以能处理的粒子数多出一两个数量级。
数据不回传
粒子状态 [x, y, vx, vy] 始终保存在 GPU 的存储缓冲区里。顶点着色器直接按 vertex_index 从同一个缓冲区读取位置,以点的形式绘制,全程不回到 CPU。
加色混合
渲染管线使用 src-alpha + one 的混合方式,粒子重叠的地方会叠加变亮,形成发光效果。
简化处理
为了代码简洁,计算着色器直接原地读写同一个缓冲区,没有使用双缓冲。同一帧里有些粒子可能读到已经更新过的位置,这对视觉效果的影响可以忽略。

🔄Rust 与 JavaScript 的分工

  1. JS页面加载时逐项检测 WebGPU 环境(API、浏览器版本、适配器、设备、Canvas 上下文),全部通过才开始运行。
  2. RustJS 调用 Rust 的 gen_gpu_particles(数量, 900, 600),得到扁平的 Float32 初始数据,一次性上传到 GPU 缓冲区。
  3. GPU每帧 JS 只把引力等参数写入一个 28 字节的 uniform 缓冲区,然后提交一个计算通道和一个渲染通道,其余工作全部由 GPU 完成。

⚡性能要点

  • CPU 与 GPU 之间每帧几乎没有数据传输,这是 GPU 计算能获得高性能的关键。
  • 可以把粒子数量调到 20,000,再与 CPU 粒子物理(300 个粒子)对比两者的差距。
  • 需要 Chrome / Edge 113+ 和可用的 GPU。虚拟机或没有硬件加速的环境会显示检测失败的原因。

源码crates/simulation/webgpu/src/lib.rswww/webgpu/index.js内含 WGSL 着色器