为什么在 CPU 循环中更新粒子位置会导致严重掉帧
很多前端开发者在用 Three.js 开发粒子效果时,习惯在 requestAnimationFrame 的循环中使用 JavaScript 逐个遍历 100,000 个粒子的 $(x, y, z)$ 坐标。
这种做法会瞬间撞上两堵性能铁墙:
- CPU 单核计算瓶颈:JavaScript 单线程需要对几十万个浮点数进行三角函数运算;
- CPU 到 GPU 内存传输带宽耗尽:每一帧都需要将庞大的顶点缓冲区(VBO)重新上传至 GPU 显存,导致 Draw Call 延迟爆炸。
真正高性能的 WebGL 3D 粒子系统,必须做到几何体实例化(InstancedMesh)并将运动方程全量交给 GPU 顶点着色器(Vertex Shader)。
GLSL 顶点着色器与基于时间的解析运动方程
让数百万粒子在 GPU 中并行舞动的标准方案:
- 单次 Draw Call 实例化:利用
THREE.InstancedMesh或带实例化属性的BufferGeometry,将 100 万粒子的绘制调用合并为单次glDrawElementsInstanced; - GPU 并行求值:在 GLSL Vertex Shader 内部传入统一时间变量
uniform float uTime,利用内置并行算子在 GPU Core 上瞬间计算出每个粒子的螺旋、星云或引力形态:vec3 pos = position; pos.x += sin(pos.y * 3.0 + uTime) * 0.2; gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0); - 视锥体剔除优化 (Frustum Culling):根据粒子群外包围球(Bounding Sphere)动态跳过不可见视野的渲染。
纯 JS 模拟顶点着色器时间参数更新
import assert from "node:assert/strict";
function updateUniformTime(prev, dt) {
return (prev + dt) % 1000;
}
assert.equal(updateUniformTime(10, 0.016), 10.016);原始资料与溯源链接
-
Chen Tech Studio 3D 粒子与手势交互系统:站内基于 WebGL 着色器与 MediaPipe 的生产级高帧率手势粒子场。
感谢阅读本文
如果你觉得内容有帮助,欢迎点赞支持或分享给同行开发者。
0 次阅读0 人赞过