2026-09-07 / 9 min

模型解构为粒子:交互、释放与自适应性能

从模型表面采样粒子,组织排斥、释放和回归状态,并根据设备条件分配粒子预算。

粒子系统Shader性能优化指针交互

系统拆分

模型粒子化可以拆成四个相互独立的部分:

  • 采样:从模型表面取得粒子的初始位置和颜色。
  • 状态:根据滚动进度计算实体、柔化、静止和释放阶段。
  • 交互:把指针命中、距离和运动速度转换为局部影响。
  • 渲染:使用 GPU 侧位移和透明度变化绘制粒子。

这种拆分让“粒子在哪里”“粒子现在处于什么阶段”和“粒子如何被指针影响”不会混在同一个循环里。调节视觉效果时,也不必重新组织模型载入和缓冲区创建。

从模型表面取得粒子

使用 MeshSurfaceSampler 采样模型表面,可以让粒子初始状态天然对应实体模型。每个粒子至少需要保存初始位置、随机相位、颜色和用于释放的方向或权重。初始位置作为回归目标,随机相位则用于避免所有粒子以相同节奏运动。

位置数据写入 BufferGeometry 后,运行时尽量保持缓冲区结构稳定。连续变化的部分交给 shader,通过 uniform 传递时间、滚动阶段、指针位置和释放强度,减少 JavaScript 逐粒子写入带来的 CPU 压力。

排斥不是瞬移

指针排斥可以按距离衰减计算:距离越近,位移越强;超过影响半径后,粒子回到原来的状态。为了让动作有重量,还需要把指针运动速度作为额外输入,让快速划过产生短暂的方向性反馈。

实际体验中,排斥和回归需要同时存在。排斥力负责表达“用户碰到了这里”,回归力负责保持模型的整体可读性。如果只增加排斥,不设置稳定的回归目标,粒子场会逐渐漂移;如果回归过强,用户又会感觉粒子没有被真正推动。

释放与反向恢复

释放状态不应只是把所有粒子乘以一个越来越大的坐标系数。更完整的过程通常包含:

  1. 从实体模型过渡到可分辨的粒子形态。
  2. 在释放前短暂收束,形成一个可感知的蓄力阶段。
  3. 沿各自方向展开,同时保留少量旋转和噪声差异。
  4. 进入稳定的扩散状态。

滚动驱动的状态必须可逆。向上滚动时,释放进度应回退,粒子重新接近采样位置,而不是继续沿上一次的速度向外飞行。这样用户可以把滚动当成探索,而不是只能观看一次的动画。

自适应粒子预算

粒子数量采用自适应策略,不在所有设备上使用同一个固定值。预算可以由设备类型、视口尺寸和像素比共同决定:移动端优先保证触控反馈和稳定帧率,桌面端在剩余性能允许时增加粒子密度。

NAIWA 的基础预算约为移动端 12,000 个、桌面端 22,000 个粒子,并同时限制高密度屏幕的渲染像素比。预算调整的优先级是:先保留轮廓,再保留释放动作,最后才增加细节密度。这样即使减少粒子,用户仍能理解页面正在发生什么。

命中检测和性能边界

实体阶段需要知道指针是否命中真实模型,不能只依据屏幕中心或一个固定圆形区域判断。复杂网格的 raycast 可以使用 three-mesh-bvh 加速;粒子阶段则可以使用模型空间或屏幕空间的影响范围,避免为每个粒子执行昂贵的完整几何检测。

性能检查应覆盖载入、实体展示、粒子展开、指针快速移动和移动端滚动。重点观察主线程任务、GPU 帧时间、内存增长和移动端像素比。粒子系统的目标不是“永远最大”,而是在完整体验中保持可预测的成本。

相关项目:NAIWA / 奶蛙。