一、让粒子各有特色

上一篇讲解了位置、速度、角度三个"发射随机性"参数,解决了粒子"从哪来、往哪飞"的自然感问题。但粒子的外观同样需要随机性——如果所有粒子大小相同、颜色一致、同时消亡,看起来仍然像复制粘贴。

本文讲解三个"外观随机性"参数:大小随机性(sizeVariation)、生命周期随机性(lifeSpanVariation)、颜色随机性(colorVariation)。它们控制粒子"长什么样、活多久"的随机程度。

读完本文后,你将理解 sizeVariationendSize 的区别、lifeSpanVariation 的边界行为、以及 colorVariation 在 HSV 色彩空间中的工作原理。


二、开发环境与版本说明

本文所有代码基于以下环境验证(验证日期:2026-06-15):

  • Qt 版本:6.8.2
  • 编译器:MinGW 64-bit
  • 操作系统:Windows 11
  • 构建工具:CMake 3.29

Variation 参数的 API 从 Qt 5 起稳定,Qt 6.5+ 均可直接运行本文代码。


三、原理分析:外观随机性

3.1 大小随机性:sizeVariation

sizeVariation 控制粒子初始大小的随机范围。数学模型与其他 Variation 一致:

实际大小 = size + random(-sizeVariation, +sizeVariation)
属性 含义 典型值
size 基础大小(像素) 10-20
sizeVariation 大小随机偏移 size 的 30-60%
endSize 消亡时的大小 0(渐消效果)

sizeVariation vs endSize 的区别

这两个属性经常被混淆,但它们控制的是完全不同的维度:

  • sizeVariation:控制粒子诞生时的大小随机性。每个粒子诞生时,大小在 [size - sizeVariation, size + sizeVariation] 范围内随机。之后粒子的大小按照从初始大小到 endSize 线性变化。
  • endSize:控制粒子消亡时的大小。粒子在整个生命周期内,大小从诞生时的值线性变化到 endSize

endSize 的作用

诞生: size=20

中段: size=10

消亡: endSize=0

sizeVariation 的作用

粒子1: size=10

粒子2: size=20

粒子3: size=30

组合使用sizeVariation 让不同粒子有不同的初始大小,endSize 让每个粒子在生命周期内大小渐变。两者叠加产生丰富的视觉层次。

3.2 生命周期随机性:lifeSpanVariation

lifeSpanVariation 控制粒子存活时间的随机范围:

实际寿命 = lifeSpan + random(-lifeSpanVariation, +lifeSpanVariation)
属性 含义 典型值
lifeSpan 基础寿命(毫秒) 2000-5000
lifeSpanVariation 寿命随机偏移 lifeSpan 的 20-40%

边界行为:当 lifeSpanVariation > lifeSpan 时,实际寿命可能为负值。负值会被 clamp 到 0,粒子立即消亡——视觉上表现为"有些粒子刚出生就消失了"。在 Variation_Lifespan.qml 的示例中,lifeSpan: 2000, lifeSpanVariation: 4000,实际寿命范围为 [-2000, 6000],负值部分全部 clamp 到 0。这意味着大约 25% 的粒子会立即消亡。

设计意图:大 lifeSpanVariation 制造"有的粒子长寿、有的粒子短命"的效果。短命粒子快速出现又消失,长寿粒子飘得更远,形成丰富的层次感。

3.3 颜色随机性

颜色随机性有两种实现方式,分别适用于不同的渲染器:

ImageParticle 的 colorVariation

colorVariationredVariationgreenVariationblueVariation 的快捷属性——设置 colorVariation 等同于将三个 RGB 通道的变化量设为相同值:

实际红色 = color.red + random(-colorVariation, +colorVariation)
实际绿色 = color.green + random(-colorVariation, +colorVariation)
实际蓝色 = color.blue + random(-colorVariation, +colorVariation)

每个颜色通道在粒子之间的变化量最多为 colorVariation,范围是 0 到 1。0 表示所有粒子颜色完全一致,1 表示每个通道完全随机。一般 0.2-0.5 为自然变化。

ItemParticle 的自定义颜色

ItemParticle 的 delegate 可以用 Qt.rgba()Qt.hsla() 实现更灵活的颜色随机:

ItemParticle {
    delegate: Rectangle {
        color: Qt.rgba(Math.random(), Math.random(), Math.random(), 1)
    }
}

每个粒子实例化独立的 delegate,Math.random() 在实例化时求值,所以每个粒子有不同的颜色。这种方式比 colorVariation 更灵活——可以控制随机的色相范围、固定饱和度和明度等。


四、代码实现

4.1 Variation_Size.qml:大小随机性

Emitter {
    id: emitter
    system: particleSystem
    anchors.centerIn: parent
    width: 1; height: 1
    emitRate: 20
    lifeSpan: 4000
    size: 16
    sizeVariation: 30

    velocity: AngleDirection {
        angle: 0
        angleVariation: 360
        magnitude: 100
    }
}

size: 16, sizeVariation: 30 ——基础大小为 16 像素,随机偏移范围 ±30。实际大小在 [-14, 46] 范围内随机。负值被 clamp 到 0(不可见),所以大部分粒子大小在 0-46 之间。这产生了极大的大小差异——有些粒子很小(接近 0),有些粒子很大(46 像素)。

emitRate: 20 ——每秒只发射 20 个粒子,数量不多但每个粒子都很大,强调大小差异的视觉效果。

lifeSpan: 4000 ——4 秒的长寿命让粒子有足够的时间扩散到整个页面,大小差异在扩散过程中更加明显。

4.2 Variation_Lifespan.qml:生命周期随机性

Emitter {
    anchors.centerIn: parent
    width: 1; height: 1
    emitRate: 20
    lifeSpan: 2000
    lifeSpanVariation: 4000
    size: 24

    velocity: AngleDirection {
        angle: 0
        angleVariation: 360
        magnitude: 100
    }
}

lifeSpan: 2000, lifeSpanVariation: 4000 ——基础寿命 2 秒,随机偏移 ±4 秒。实际寿命范围为 [-2000, 6000],其中负值部分(约 25%)被 clamp 到 0。

视觉效果

  • 约 25% 的粒子立即消亡(寿命为 0),在中心点一闪即逝
  • 约 75% 的粒子存活 0-6 秒,扩散到不同距离后消亡
  • 长寿粒子飞得更远,短命粒子在近处消亡,形成明显的"距离层次"

size: 24 ——所有粒子大小相同(无 sizeVariation),强调生命周期差异的效果。

4.3 Variation_Color.qml:颜色随机性

ItemParticle {
    delegate: Rectangle {
        width: 16; height: 16; radius: 8
        color: Qt.rgba(Math.random(), Math.random(), Math.random(), 1)
    }
}

这个示例使用 ItemParticle 而不是 ImageParticle,因为 ItemParticle 的 delegate 可以用 Math.random() 实现完全随机的 RGB 颜色。

Qt.rgba(Math.random(), Math.random(), Math.random(), 1) ——每个通道独立随机,产生全色域的随机颜色。alpha 固定为 1(不透明)。

为什么不用 ImageParticle 的 colorVariation?

colorVariation 是在基础颜色的 HSV 空间中偏移,颜色变化范围受限于基础色。如果基础色是红色(hue=0),colorVariation: 0.5 只会让颜色在红色到橙色/品红之间变化,不会出现蓝色或绿色。

Qt.rgba(Math.random(), ...) 产生真正的全色域随机颜色,不受基础色限制。这种灵活性是 ItemParticle 的独特优势。

替代方案:如果想在 ImageParticle 上实现全色域随机,可以用 color: "white" 配合 colorVariation: 1。白色在 HSV 空间中 hue 为 0、saturation 为 0,colorVariation: 1 会让 hue 完全随机,实现全色域变化。但效果不如 Math.random() 精确。


五、运行效果

Variation_Size.qml:红色星形粒子从中心向四面八方扩散,大小差异极大——有的粒子很小(接近不可见),有的粒子很大(46 像素)。大小差异让粒子群有了"远近层次"的错觉。
在这里插入图片描述

Variation_Lifespan.qml:青色星形粒子从中心扩散,但消亡时间差异很大。部分粒子在中心点一闪即逝(立即消亡),部分粒子飞到页面边缘后才消亡(长寿)。形成"中心密集、边缘稀疏"的密度梯度。
在这里插入图片描述

Variation_Color.qml:全色域的彩色圆形粒子从中心向四面八方扩散,每个粒子颜色各异——红、绿、蓝、黄、紫……形成彩虹般的粒子流。
在这里插入图片描述


六、适用边界与限制条件

  • colorVariation 范围是 0 到 1:0 表示所有粒子颜色完全一致,1 表示 HSV 空间中完全随机。一般 0.2-0.5 为自然变化
  • sizeVariation 大于 size 时:实际大小可能为负值,被 clamp 到 0——粒子不可见。如果不想出现不可见粒子,确保 sizeVariation < size
  • lifeSpanVariation 大于 lifeSpan 时:部分粒子立即消亡(寿命 clamp 到 0)。如果是期望的效果(如闪烁光点),大值合适;否则建议 lifeSpanVariation < lifeSpan
  • endSize 和 sizeVariation 可以同时用sizeVariation 控制初始大小的随机性,endSize 控制消亡时的大小。两者叠加:不同粒子有不同的初始大小,但都渐变到同一个 endSize
  • ItemParticle 的 Math.random() 在 delegate 实例化时求值:每个粒子拥有独立的 delegate 实例,所以结果各不相同

七、常见误区

“粒子大小差异不明显”——检查 sizeVariation 是否太小。设为 size 的 30-60% 才有明显差异,10% 以下几乎看不出区别。

“粒子刚出生就消失了”——检查 lifeSpanVariation 是否大于 lifeSpan。负值寿命被 clamp 到 0,部分粒子立即消亡。如果不需要这个效果,减小 lifeSpanVariation

“颜色变化太单调,只有深浅不同”——colorVariation 同时偏移 RGB 三个通道,但如果基础色的各通道值接近(如灰色),偏移后颜色差异不大。用高对比度的基础色(如纯红、纯蓝)效果更明显。

“想让每个粒子颜色完全不同,但 colorVariation 不够”——colorVariation 受基础色限制。需要全色域随机时,用 ItemParticle 的 delegate + Qt.rgba(Math.random(), ...) 或 ImageParticle 的 color: "white" + colorVariation: 1

八、总结

回到开头的问题:如何让粒子各有特色?三个 Variation 参数分别控制大小(sizeVariation)、生命周期(lifeSpanVariation)、颜色(colorVariation 或 Math.random())。核心公式不变:适中的 Variation + 合理的基础值 = 自然效果

至此,粒子的"出生"参数(发射器、区域、方向、随机性)全部讲解完毕。下一篇进入粒子的"死后"环节——讲解物理影响器,如何在粒子发射后施加重力、摩擦和吸引等力场效果。


资源下载qml_particlesystem —— 包含完整的、可运行的代码

系列目录

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐