Skip to content

弹跳粒子 (Bouncing Particles)

📖 简介

分形场景示例

弹跳粒子(Bouncing Particles)是一个实时物理模拟场景:数百万粒子被限制在圆形、椭圆或任意凸多边形边界内部运动,与边界发生弹性碰撞后沿反射方向继续飞行。粒子初始位置可以由 多种数学形状(螺旋、星形、玫瑰线、利萨如曲线等)采样生成,初始速度则支持均匀、径向、切向等方向模式。基于 GPU 上的碰撞求解与逐粒子着色,bouncing 能够呈现丝滑流畅、色彩绚丽的粒子碰撞艺术。

核心能力:

  • GPU 实时物理模拟:纯 GPU 双遍渲染管线,粒子状态(位置 + 速度)存储在纹理中,支持数百万粒子流畅碰撞
  • 多种边界容器:圆形、椭圆与任意凸多边形(3-64 顶点)三种容器,支持一键预设与自由拖拽编辑
  • 13 种初始位置布局:从 Box、圆形、心形到利萨如曲线、超椭圆,甚至支持公式自定义粒子布局
  • 6 种初始速度模式:均匀方向、径向内外、切向顺逆时针与完全随机,塑造多样的流动形态
  • 逐粒子速度着色:粒子的颜色与速度相关,配合调色板呈现动态绚丽的视觉效果
  • 弹性碰撞物理:基于反射定律的精确碰撞求解,每子步最多处理 4 次连续碰撞

🧮 数学背景

什么是弹跳粒子?

弹跳粒子模拟的核心是经典力学中的粒子 - 边界碰撞系统。大量互不碰撞的粒子在一个封闭的二维区域内做匀速直线运动,当粒子触及边界时,其速度按照镜面反射定律发生翻转:

其中 是边界在碰撞点处的单位外法向量。这个看似简单的规则,在圆形、椭圆和多边形等不同边界的组合下,会产生丰富多彩的轨迹图案。

粒子运动模型

每个粒子的状态由位置 和速度 组成。每帧按照时间步长 推进:

超出边界(且减去粒子碰撞半径 后仍然越界)时,系统会计算粒子与边界的精确交点,将粒子投影回边界内侧,并将速度沿碰撞点法线方向反射。

边界类型

边界类型数学描述碰撞求解方式
圆形解析求解射线与圆的二次方程交点
椭圆在归一化坐标空间(除以半轴)中退化为圆求解
凸多边形顶点序列 围成的凸区域逐边扫描检测穿出时刻 + 最近点投影回内部

子步与连续碰撞

为了在高速运动下保持碰撞精度,系统将每帧的时间步细分(Substeps,1-16),并在每个子步内至多处理 4 次连续碰撞(MAX_COLLISIONS_PER_SUBSTEP)。这意味着即使粒子在一帧内多次反弹(例如从尖角处高速飞出),也能获得正确的结果。


🖥️ 界面概览

所有控制项位于右侧的属性面板中,分为五个主要部分:

  1. Simulation(模拟):配置粒子数量、子步数、时间步长与碰撞参数
  2. Initial Position(初始位置):选择初始位置布局与形状参数
  3. Initial Velocity(初始速度):选择初始速度模式与速度参数
  4. Boundary(边界):配置边界容器形状、颜色与多边形顶点
  5. Gradient(渐变):调整渐变调色板

说明:弹跳粒子是纯实时物理模拟场景,不包含方程参数、相机、公式显示等面板。场景始终以 2D 平面渲染,录制通过配置的录制时长自动停止。


⚙️ 配置指南

1. Simulation(模拟设置)

模拟设置面板

模拟面板控制粒子系统的核心物理参数:

  • Particles(粒子数量):参与模拟的粒子总数

    • 范围:1 - 无限(步进 1000)
    • 默认值:2,000,000(约 200 万)
    • 建议
      • 快速预览:100,000 - 500,000
      • 实时交互:1,000,000 - 3,000,000
      • 高质量渲染:5,000,000+
    • 注意:粒子数越多,状态纹理越大,GPU 显存占用与计算量随之上升
  • Substeps(子步数):每帧将时间步细分的次数

    • 范围:1 - 16
    • 默认值:1
    • 作用:将每帧运动拆分为多个小步推进,提高高速粒子的碰撞精度
    • 建议:粒子速度快或碰撞频繁时适当增大(如 2-4),以获得更稳定的反弹轨迹
  • Step Size(时间步长):每个子步的物理时间步长

    • 范围:0.0001 - 0.25
    • 默认值:0.012
    • 作用:控制粒子的单步位移。步长越大粒子每帧移动越远,碰撞越频繁
  • Particle Size(粒子大小):粒子的屏幕像素直径

    • 范围:0.1 - 20.0
    • 默认值:1.25
    • 作用:仅影响视觉呈现,不影响碰撞物理。较大的粒子视觉上更醒目
  • Collision Radius(碰撞半径):粒子的物理碰撞半径

    • 范围:0.0 - 0.25
    • 默认值:0.006
    • 作用:碰撞检测时边界向内收缩该半径,使粒子在贴近边界时才发生反弹。增大此值会让粒子看起来"提前"反弹

提示:Particle Size(视觉)与 Collision Radius(物理)是相互独立的参数。若希望粒子视觉较大但不影响碰撞精度,可以只增大 Particle Size。


2. Initial Position(初始位置)

初始位置设置面板

初始位置决定粒子系统启动时粒子分布在何处。系统提供 13 种布局模式:

模式中文名称说明特有参数
Box矩形在矩形区域内均匀随机分布X Min/Max、Y Min/Max
Circle圆形在圆盘内均匀分布形状中心、形状半径
Heart心形沿心形线分布形状中心、形状半径
Infinity无穷沿无穷符号曲线分布形状中心、形状半径
Ring圆环在内外半径之间分布形状中心、形状半径、内径比
Spiral螺旋沿阿基米德螺旋分布形状中心、形状半径、圈数、紧密度
Star星形沿星形轮廓分布形状中心、形状半径、角数、内径比
Lissajous利萨如沿利萨如曲线分布形状中心、形状半径、A、B、相位差
Rose玫瑰线沿玫瑰曲线分布形状中心、形状半径、K
Superellipse超椭圆沿超椭圆曲线分布形状中心、形状半径、N
Hypocycloid内摆线沿内摆线分布形状中心、形状半径、K
Epicycloid外摆线沿外摆线分布形状中心、形状半径、K
Formula公式使用公式自定义布局形状中心、形状半径、公式

模式通用参数

  • Shape Center X/Y(形状中心):布局形状在场景中的中心位置
  • Shape Radius(形状半径):布局形状的缩放半径

形状特有参数

  • Inner Ratio(内径比,Ring/Star):内圈相对外圈的半径比例,控制环的厚度或星形凹陷程度
  • Points(角数,Star):星形的角数(≥ 3)
  • Turns(圈数,Spiral):螺旋的旋转圈数
  • Tightness(紧密度,Spiral):螺旋从中心向外扩散的紧密度
  • A / B(Lissajous):利萨如曲线的频率参数
  • Delta(Lissajous):利萨如曲线的相位差(角度制)
  • K(Rose):玫瑰线的花瓣数
  • N(Superellipse):超椭圆指数,决定形状从菱形(N=1)到圆角矩形(N=2)再到方形(N→∞)的过渡
  • K(Hypocycloid/Epicycloid):内摆线/外摆线的旋转点数

公式模式

  • Formula(公式):使用 xy 变量和 sincostansqrtabspowlogexp 等函数编写条件公式(如 Math.sin(x*5) + Math.cos(y*3) > 0),满足条件的点被采样为粒子初始位置
  • 使用 PI 常量与 Math.sin 等 Java 风格函数语法
  • 公式修改后在输入框失焦时自动生效

填充模式

非 Box 模式的形状布局支持两种填充方式:

  • Fill(填充):粒子分布在形状内部区域

  • Outline(轮廓):粒子仅分布在形状轮廓线上

  • Line Width(线宽):轮廓模式下粒子的分布线宽

提示:初始位置采样时,系统会自动丢弃落在边界容器之外的采样点(最多尝试 512 次),确保所有粒子都从容器内部开始运动。


3. Initial Velocity(初始速度)

初始速度设置面板

初始速度决定粒子启动时的运动方向与快慢,系统提供 6 种模式:

模式说明
Uniform(均匀)所有粒子沿同一方向运动
Out(径向向外)从速度中心向外辐射
In(径向向内)从外向内汇聚到速度中心
CW(切向顺时针)绕速度中心顺时针旋转
CCW(切向逆时针)绕速度中心逆时针旋转
Random(随机)每个粒子方向完全随机

速度参数

  • Speed(速度):粒子的初始速率(≥ 0)

    • 默认值:0.2
    • 作用:速度越大,粒子运动越快、碰撞越频繁
  • Direction(方向):仅 Uniform 模式可用

    • 范围:0° - 360°
    • 作用:所有粒子的统一运动方向
  • Vx / Vy(速度中心):仅径向/切向模式可用

    • 作用:定义径向发射或旋转运动的中心点位置
  • Spread(角度扩散):速度方向的角度散布范围

    • 范围:0° - 360°
    • 作用:为粒子速度方向叠加随机扰动,0° 时所有粒子方向一致
  • Noise(噪声):速度方向噪声强度

    • 范围:0.0 - 1.0
    • 作用:在角度扩散基础上叠加更强的随机抖动,模拟湍流效果
  • Seed(随机种子):随机数生成种子

    • 作用:相同的种子产生相同的随机分布,方便复现特定构图

4. Boundary(边界)

边界编辑面板

边界面板定义粒子被限制在其中的容器形状:

通用参数

  • Shape Center X/Y(形状中心):边界容器在场景中的中心位置
  • Boundary Color(边界颜色):边界描边的颜色(渲染时带半透明效果)

边界形状

系统提供四种预设形状与自由多边形编辑:

  • Circle(圆形):圆形边界,可调节半径
  • Ellipse(椭圆):椭圆边界,可分别调节长半轴与短半轴
  • Triangle(三角形):正三角形边界,可调节外接圆半径
  • Hex(六边形):正六边形边界,可调节外接圆半径

多边形编辑

除了预设形状,还可以在编辑画布上自由构建多边形边界:

  • 直接拖拽画布中的顶点调整位置
  • Add(添加):添加新顶点(最多 64 个)
  • Reset(重置):恢复默认的六边形顶点
  • 每个顶点可通过 X/Y 坐标精确输入,点击删除按钮移除顶点(最少保留 3 个)

注意:边界为多边形时,粒子碰撞基于凸多边形求解。使用预设三角形/六边形时,可通过半径滑块整体缩放。


5. Gradient(渐变调色板)

弹跳粒子使用逐粒子调色板着色:每个粒子根据其 ID 在调色板中采样颜色,并叠加速度着色,支持三种渐变模式:

  • Manual(手动模式)

    • 手动添加、删除和调整颜色节点
    • 支持拖拽重排颜色顺序
    • 四种随机策略:单色、类似色、互补色、分裂互补色
  • Cosine(余弦模式)

    • 使用 IQ 余弦调色板公式:color(t) = a + b · cos(2π(c·t + d))
    • 分别控制 R/G/B 三个通道的偏移、振幅、频率和相位
    • 支持一键随机化和应用
  • Curve(曲线模式)

    • 通过可编辑的贝塞尔曲线分别控制 R/G/B 三个通道
    • 提供最灵活的颜色控制
    • 支持一键随机化和应用

速度着色:粒子颜色会依据其瞬时速度产生亮度变化——运动较快的粒子更亮,慢的粒子更暗,从而强化动态感。


🎬 动画与录制

弹跳粒子是实时物理模拟场景,不支持参数振荡动画,但支持视频录制:

  • 实时演化:粒子持续运动与碰撞,无需时间线即可呈现动态效果
  • 录制时长控制:场景通过配置中的 record_duration(秒)控制录制停止时机,运行时间达到录制时长后自动结束录制
  • 时间线配置:场景的 timeline 通常只包含 wait 类型条目,用于等待粒子运动演化
json
{
  "timeline": [
    {
      "type": "wait",
      "duration": 10.0,
      "label": "Wait",
      "easing": "SINE_IN_OUT",
      "enabled": true
    }
  ]
}

🚀 性能与最佳实践

推荐配置

目标ParticlesSubstepsStep Size碰撞半径
快速预览100,000 - 500,00010.01 - 0.020.001 - 0.005
实时交互1,000,000 - 3,000,0001-20.010.002 - 0.006
高质量渲染5,000,000+2-40.008 - 0.0120.001 - 0.004

性能优化技巧

  1. 粒子数量是最关键的性能因素

    • 每帧所有粒子的碰撞求解都在 GPU 上并行完成,粒子数直接决定计算量
    • 预览阶段使用低粒子数(如 20 万)快速评估布局与颜色,最终渲染时再提高
  2. 子步数与时间步长的权衡

    • 增大 Substeps 或 Step Size 会显著增加每帧计算量
    • 高速粒子(Speed 大)建议增大 Substeps 保证碰撞精度,但避免过大
  3. 多边形边界的开销

    • 多边形碰撞需要逐边检测,顶点越多开销越大
    • 圆形与椭圆边界使用解析求交,计算量最小
  4. 视觉与物理分离

    • 调整 Particle Size 不影响物理模拟,适合低代价改善观感
    • 谨慎调节 Collision Radius,它会改变粒子的实际运动轨迹

❓ 常见问题

画面卡顿或掉帧

问题:粒子数量很大时渲染不流畅

解决方案

  • 降低 Particles 数量
  • 减小 Substeps 与 Step Size
  • 使用圆形/椭圆边界替代高顶点数多边形

粒子运动轨迹异常或"穿墙"

问题:高速粒子偶尔穿透边界

原因:单帧位移过大,碰撞求解未能捕获穿出时刻

解决方案

  • 增大 Substeps(如从 1 增加到 2-4)
  • 减小 Step Size
  • 适当增大 Collision Radius 提供缓冲

初始位置显示在边界之外

问题:部分粒子初始时出现在容器外部

原因:初始布局形状超出了容器边界

解决方案

  • 缩小 Shape Radius 使布局整体落入容器内
  • 调整 Shape Center 使布局居中
  • 使用与容器匹配的初始布局形状(如圆形容器搭配 Circle/Spiral 布局)

粒子全部静止不动

问题:画面没有任何运动

原因:初始速度为零或方向设置不当

解决方案

  • 增大 Speed(如 0.1 - 0.5)
  • 检查初始速度模式是否合理(Random 或 Uniform + Direction)
  • 检查时间步长是否过小

颜色过于单一或混乱

问题:粒子颜色缺乏层次

解决方案

  • 切换到 Cosine 或 Curve 渐变模式生成和谐配色
  • 调整调色板节点数量与分布
  • 速度着色会自动让快慢粒子呈现亮度差异

📐 经典示例

螺旋放射(圆形容器)

容器:Circle(半径 0.55)
初始位置:Spiral(圈数 5.5,紧密度 0.16)
初始速度:Uniform(速度 0.2)
粒子数:2,000,000,粒子大小 1.25,碰撞半径 0.006

星形放射(圆形容器)

容器:Circle(半径 0.55)
初始位置:Star(角数 5,内径比 0.62)
初始速度:Radial Out(速度 0.2,噪声 0.4)
粒子数:5,000,000,粒子大小 0.1

玫瑰绽放(圆形容器)

容器:Circle(半径 0.55)
初始位置:Rose(K = 7)
初始速度:Radial Out(速度 0.2,噪声 0.4)
粒子数:2,000,000,粒子大小 0.1

六边形漩涡(六边形容器)

容器:Hexagon(半径 0.62)
初始位置:Circle(半径 0.16)
初始速度:Uniform(速度 0.2)
粒子数:500,000,粒子大小 0.1

椭圆涡环(椭圆容器)

容器:Ellipse(长半轴 0.6,短半轴 0.55)
初始位置:Ring(内径比 0.57)
初始速度:Uniform(速度 0.2)
粒子数:2,000,000,粒子大小 1.25

🖼️ 更多效果展示

更多效果展示 1更多效果展示 2


🔧 技术细节

GPU 渲染管线

弹跳粒子使用纯 GPU 双遍渲染管线:

  1. 状态更新遍(Update Pass)

    • 读取当前粒子状态纹理(RGBA32F,R/G = 位置,B/A = 速度)
    • 按 Substeps 细分时间步,对每个子步执行边界碰撞求解(圆形/椭圆/多边形)
    • 每个子步内至多处理 4 次连续碰撞(MAX_COLLISIONS_PER_SUBSTEP
    • 使用 Ping-Pong 双缓冲技术实现状态纹理交替读写
  2. 渲染遍(Render Pass)

    • 将粒子位置乘以 Scale/Offset 变换后投影到屏幕
    • GL_POINTS 方式绘制,并在片元着色器中用 gl_PointCoord 裁剪为圆形
    • 粒子颜色按粒子 ID 从调色板采样,并依据瞬时速度叠加亮度着色
    • 粒子大小(Point Size)以屏幕像素为单位

粒子状态纹理

粒子的位置与速度被打包存储在一张 texSize × texSizeRGBA32F 纹理中:

每个纹素存储一个粒子的完整状态(4 个 float,共 16 字节),顶点着色器通过 gl_VertexID 解码粒子的纹理坐标。

碰撞求解算法

边界算法
圆形将粒子运动视为射线,解析求解射线与圆(半径减去碰撞半径)的二次方程,得到精确撞击时刻与法线
椭圆将坐标与位移按半轴归一化,退化为单位圆求交,再反归一化得到法线
凸多边形逐边计算粒子与每条边的穿出时刻,取最早撞击边;若粒子已越出边界,则投影到最近边上并沿法线反射

弹性反射

所有碰撞统一遵循镜面反射公式:

速度大小在碰撞前后保持不变(完全弹性碰撞),因此粒子能量守恒,运动永不衰减。


🎨 创作技巧

布局探索

  1. 从预设形状开始:先在圆形容器中尝试 Circle、Spiral、Star 等基础布局
  2. 组合容器与布局:让布局形状与容器形状呼应(如六边形容器 + 星形布局)
  3. 使用公式布局:熟悉基本模式后,编写 Math.sin(x*5) + Math.cos(y*3) > 0 之类公式构建独一无二的粒子图案

动态表现

  1. 速度模式塑造运动:Radial Out 呈现放射爆发,CW/CCW 呈现漩涡旋转,Uniform 呈现整齐流动
  2. 速度中心改变焦点:将速度中心偏离容器中心,可以创造出偏心旋转的动态美感
  3. 噪声与扩散:增大 Spread/Noise 让运动更狂野,保持 0 则获得纯净有序的轨迹

视觉调优

  1. 粒子大小与密度:小粒子(0.1)+ 高粒子数呈现细腻的沙粒质感,大粒子(1.25+)更醒目
  2. 速度着色:利用粒子速度带来的亮度差异强化运动方向感
  3. 边界颜色:深色背景 + 明亮边界 + 高饱和调色板是经典搭配

⚠️ 注意事项

  1. GPU 显存

    • 粒子状态纹理大小为 ⌈√N⌉ × ⌈√N⌉,采用 RGBA32F 格式,每粒子占用 16 字节
    • 例如 500 万粒子需要约 80 MB 显存存储状态纹理
  2. 子步数与性能

    • Substeps 每增大 1 倍,Update Pass 计算量近似翻倍
    • 高粒子数场景建议保持 Substeps 为 1-2
  3. 多边形边界限制

    • 顶点数量限制为 3-64 个
    • 边界必须是凸多边形,凹多边形会导致碰撞异常
  4. 粒子互不碰撞

    • 粒子之间不会相互碰撞,仅与边界发生碰撞
    • 这是刻意设计,以保持系统的确定性并聚焦于边界交互的视觉效果

📚 参考资源

数学理论

计算机图形学

All rights reserved.