目录一、问题从固定点到发射区域1.1 固定点发射的局限1.2 Emitter 默认的矩形区域1.3 探索路径需求递进二、开发环境与版本说明三、原理五种方案如何解决这个需求3.1 五种方案对比3.2 RectangleShape最基础的区域控制3.3 EllipseShape从矩形到曲线3.4 LineShape从面到线3.5 MaskShape从预定义到任意形状3.6 移动发射区域从静态到动态四、代码实现与运行效果4.1 Shape_Rectangle.qml矩形发射区域4.2 Shape_Ellipse.qml椭圆发射区域fill 对比4.3 Shape_Line.qml线性发射区域mirrored 对比4.4 Shape_Mask.qml图像遮罩发射区域4.5 Shape_Moving.qml移动发射区域五、运行效果六、适用边界与限制条件6.1 组合使用规则6.2 前置条件6.3 安全阀6.4 边界值6.5 性能建议七、总结一、问题从固定点到发射区域1.1 固定点发射的局限前面五篇中Emitter 的粒子都从一个固定位置或很小的矩形区域发射。这种方式适合简单的粒子源效果但真实场景往往需要更精确的控制雪花飘落——粒子应该从屏幕顶部的一条线上均匀落下光环扩散——粒子应该从圆环的边界向外喷射而不是从圆心Logo 动效——粒子应该从特定图案的轮廓中飞出固定点发射无法满足这些需求我们需要一种机制来定义粒子从哪里诞生。1.2 Emitter 默认的矩形区域其实在不设置 Shape 的情况下Emitter 已经有一种发射区域——它的整个矩形边界。粒子从这个矩形内的任意位置随机发射。但这个默认行为有一个明显的问题矩形太粗糙。圆形、椭圆形、线形、任意自定义形状矩形都表达不了。1.3 探索路径需求递进从矩形太粗糙出发我们可以沿着需求逐步探索矩形区域太粗糙需要曲线边界EllipseShape需要一条线LineShape需要任意形状MaskShape需要动态移动动画驱动 EmitterEllipseShapefill:false → 环形发射LineShapemirrored → 线段方向控制MaskShape图片遮罩 → 任意轮廓移动发射区域李萨如轨迹Qt Quick 粒子系统内置了四种 Shape 组件来覆盖这些需求RectangleShape矩形、EllipseShape椭圆、LineShape线段、MaskShape图像遮罩。加上通过动画驱动 Emitter 位置实现的第五种——移动发射区域。Shape 不决定粒子往哪飞那是 Direction 的事只决定粒子从哪里诞生。粒子诞生后Shape 就不再影响它了。二、开发环境与版本说明本文所有代码基于以下环境验证最后验证于 2026-06-10Qt 版本6.8.2编译器MinGW 64-bit操作系统Windows 11构建工具CMake 3.29Shape 组件的 API 从 Qt 5 起稳定Qt 6.5 均可直接运行本文代码。本文中的代码都只展示了核心配置部分为的是方便讲解完整代码见项目中的对应 QML 文件。三、原理五种方案如何解决这个需求3.1 五种方案对比方案发射区域关键属性适用需求RectangleShape矩形内部无额外属性通用背景粒子EllipseShape椭圆内部或边界fill: true/false环形粒子、光环效果LineShape线段上mirrored: true/false雨帘、激光、河流MaskShape图像轮廓source: 图片路径自定义形状发射移动区域动态位置Emitter 绑定动画跟随鼠标、运动轨迹3.2 RectangleShape最基础的区域控制RectangleShape 是最简单的方案没有额外属性。Emitter 的shape属性默认值就是一个填充的矩形——即 Emitter 的整个边界区域。它比固定点进步的地方在于你可以通过设置 Emitter 的width和height来控制发射区域的大小和形状。但本质上仍然是矩形无法表达曲线边界。3.3 EllipseShape从矩形到曲线当需要圆形或椭圆形的发射区域时EllipseShape 解决了矩形无法表达曲线的问题。核心属性fill控制粒子的发射位置fill: true默认粒子从椭圆内部任意位置发射像在椭圆区域内撒豆子fill: false粒子仅从椭圆边界发射像从圆环上喷射fill: false是关键——它让椭圆从面变成了环适用于光环效果、环形爆炸、漩涡边缘。3.4 LineShape从面到线当需要粒子从一条线上发射时比如雨帘从天空顶部落下LineShape 提供了线段发射区域。它继承自 ParticleExtruder在 Emitter 的宽度或高度范围内生成一条线段。核心属性mirrored控制线段方向mirrored: false默认线从左上(0,0)到右下(width, height)mirrored: true沿 y 轴镜像线从左下(0,height)到右上(width, 0)线段的具体位置和长度由 Emitter 的width和height共同决定——当width height时线段沿宽度方向延伸。3.5 MaskShape从预定义到任意形状当内置的矩形、椭圆、线段都无法满足需求时比如需要从一个五角星或文字轮廓中发射粒子MaskShape 提供了最终方案——用一张图片的轮廓作为发射区域。核心属性source指向一张图片图片中opacity 非零的像素都会发射粒子透明像素不发射。MaskShape 继承自 ParticleExtruder与 LineShape 相同的基类性能开销比其他 Shape 大——需要逐像素判断透明度。3.6 移动发射区域从静态到动态前四种 Shape 的发射区域都是静态的——粒子从固定位置的区域中诞生。但如果需要发射区域本身在移动比如跟随鼠标、沿路径运动就需要第五种方案通过动画驱动 Emitter 的位置。粒子诞生后独立于 Emitter 运动Emitter 的后续移动不影响已诞生的粒子。这与 TrailEmitter尾迹发射器的行为不同——TrailEmitter 会在运动路径上持续发射粒子。四、代码实现与运行效果4.1 Shape_Rectangle.qml矩形发射区域Emitter { anchors.centerIn: parent width: 200; height: 100 emitRate: 200 lifeSpan: 2000 size: 8 shape: RectangleShape {} velocity: PointDirection { y: -50; yVariation: 20 } }与不设 Shape的对比不设 Shape 时粒子从 Emitter 的整个矩形边界发射——如果 Emitter 填满父容器粒子会从整个页面随机位置飞出效果混乱。设置shape: RectangleShape {}并配合明确的width/height发射区域被限制在 200×100 的小矩形内效果可控。代码中用一个半透明的黄色边框 Rectangle 可视化了发射区域的范围。4.2 Shape_Ellipse.qml椭圆发射区域fill 对比这个页面用 Repeater 并排展示fill: true和fill: false的效果差异Repeater { model: [ { color: #4ECDC4, fill: true }, { color: #FF6B6B, fill: false } ] // ... ParticleSystem 内 Emitter { anchors.centerIn: parent width: 180; height: 120 emitRate: 150 lifeSpan: 3000 size: 10 shape: EllipseShape { fill: modelData.fill } velocity: AngleDirection { angle: 270; angleVariation: 30; magnitude: 60 } } }左栏fill: true青色星形粒子从椭圆内部任意位置发射向上扩散angle: 270。发射区域覆盖整个椭圆面积。右栏fill: false红色星形粒子仅从椭圆边界发射形成清晰的环形粒子源。发射区域只有椭圆的边缘线条。关键对比fill: true是面发射fill: false是线发射。同一个 EllipseShape仅通过一个属性就切换了发射模式——这是 EllipseShape 最实用的特性。两个象限都用半透明的椭圆边框可视化了发射区域。4.3 Shape_Line.qml线性发射区域mirrored 对比这个页面用 Repeater 并排展示mirrored: false和mirrored: true的效果差异Emitter { x: 50 y: parent.height / 2 - 75 width: parent.width - 100 height: 150 emitRate: 100 lifeSpan: 3000 size: 8 shape: LineShape { mirrored: modelData.mirrored } velocity: PointDirection { y: -80; yVariation: 30 } }Emitter 的width: parent.width - 100, height: 150定义了线段的范围。LineShape 在这个范围内生成一条对角线——mirrored: false时从左上到右下mirrored: true时从左下到右上。粒子从线段上的随机位置发射向上运动y: -80形成雨帘效果。代码中用一条半透明的彩色线条可视化了线段的位置和方向。与 EllipseShape fill:false 的区别两者都是线发射但 EllipseShape 是曲线环形LineShape 是直线对角线。需要圆形边界用 EllipseShape需要直线边界用 LineShape。4.4 Shape_Mask.qml图像遮罩发射区域Emitter { anchors.centerIn: parent width: 200; height: 200 emitRate: 100 lifeSpan: 3000 size: 10 shape: MaskShape { source: qrc:/images/mask.png } velocity: AngleDirection { angle: 270; angleVariation: 45; magnitude: 50 } }MaskShape 使用一张图片的非透明区域作为发射区域——任何 opacity 非零的像素都会发射粒子透明像素不发射。代码中用一个半透明的 Image 组件可视化了遮罩图片的内容。与前三种 Shape 的区别MaskShape 是唯一不受几何约束的方案——矩形、椭圆、线段都是数学定义的规则形状MaskShape 是像素定义的任意形状。代价是性能开销更大逐像素判断。注意事项MaskShape 的source必须是图片路径PNG 格式最佳支持 alpha 通道图片会被缩放到 Emitter 的width × height范围内MaskShape 继承自 ParticleExtruder与 LineShape 相同的基类不是 Shape4.5 Shape_Moving.qml移动发射区域这个页面展示了第五种方案——通过动画驱动 Emitter 的位置实现移动的发射源Emitter { id: movingEmitter width: 80; height: 80 emitRate: 80 lifeSpan: 1500 size: 10 shape: EllipseShape { fill: true } velocity: AngleDirection { angle: 0; angleVariation: 360; magnitude: 40 } SequentialAnimation on x { running: root.isCurrentItem loops: Animation.Infinite NumberAnimation { from: 40 to: parent.width - movingEmitter.width - 40 duration: 3000 easing.type: Easing.InOutQuad } NumberAnimation { from: parent.width - movingEmitter.width - 40 to: 40 duration: 3000 easing.type: Easing.InOutQuad } } SequentialAnimation on y { running: root.isCurrentItem loops: Animation.Infinite NumberAnimation { from: 40 to: parent.height - movingEmitter.height - 40 duration: 4000 easing.type: Easing.InOutSine } NumberAnimation { from: parent.height - movingEmitter.height - 40 to: 40 duration: 4000 easing.type: Easing.InOutSine } } }两个独立的 SequentialAnimation分别驱动 Emitter 的x和y坐标。x方向周期 6 秒3000×2y方向周期 8 秒4000×2两个方向的周期不同步形成类似李萨如曲线的运动轨迹。为什么 x 和 y 用不同的缓动曲线Easing.InOutQuad和Easing.InOutSine都是缓入缓出曲线但加速度曲线不同。两个方向使用不同的缓动让轨迹更自然、更有机避免机械的对称运动。running: root.isCurrentItem——动画和粒子系统同步启停。切换到其他页面时动画暂停粒子系统停止避免后台消耗。与前四种静态 Shape 的区别静态 Shape 的发射区域是固定的移动方案的发射区域在空间中运动。粒子诞生后独立于 Emitter——Emitter 的移动不会拖拽已发射的粒子。五、运行效果运行项目后点击左侧导航栏对应条目进入各示例页面。Shape_Rectangle.qml200×100 的矩形区域内黄色小点均匀向上发射半透明边框标示发射区域。Shape_Ellipse.qml左栏青色粒子从椭圆内部发射右栏红色粒子从椭圆边界发射。对比清晰展示fill属性对面发射和线发射的切换。Shape_Line.qml左栏粒子从左上到右下的斜线上发射右栏粒子从左下到右上的斜线上发射。粒子向上运动形成雨帘效果。Shape_Mask.qml蓝色星形粒子从 mask.png 图像的非透明区域发射半透明的遮罩图片叠加在背景上作为视觉参考。Shape_Moving.qml红色星形粒子从一个沿李萨如曲线运动的椭圆区域中持续发射形成运动轨迹上的粒子拖尾。六、适用边界与限制条件6.1 组合使用规则一个 Emitter 只能设置一个shape。如果需要多种形状同时发射使用多个 Emitter各自设置不同的 Shape。Shape 只决定粒子的出生位置Direction 决定运动方向两者独立配置、互不干扰。6.2 前置条件MaskShape 的source必须指向有效的图片文件。建议使用 PNG 格式以确保 alpha 通道正确。如果图片路径无效MaskShape 不会发射任何粒子。LineShape 的线段方向受 Emitter 的width和height比例影响。当width height时线段主要沿水平方向延伸反之沿垂直方向。6.3 安全阀MaskShape 的图片分辨率不宜过高建议 200×200 以内高分辨率会增加逐像素判断的开销。RectangleShape 性能最好MaskShape 性能相对最差。6.4 边界值移动发射区域中粒子诞生后就独立于 Emitter 运动——Emitter 的后续移动不影响已诞生的粒子。如果需要粒子跟随 Emitter 移动需要使用 TrailEmitter尾迹发射器第十二篇详解。6.5 性能建议如果存在多个页面尽量使用running: root.isCurrentItem控制启停矩形和椭圆 Shape 性能最好优先使用多个 Emitter 同时发射时注意总粒子数对帧率的影响七、总结本文从固定点发射不够用这个问题出发讲解了五种发射区域方案。选择策略矩形圆/椭圆直线任意轮廓动态移动是否需要定义发射区域区域形状RectangleShape需要环形LineShapeMaskShape动画驱动 EmitterEllipseShape fill:falseEllipseShape fill:true简单形状用内置 Shape复杂轮廓用 MaskShape动态位置用动画驱动。至此粒子发射区域的五种形态全部覆盖。下一篇讲解粒子的运动方向——AngleDirection、PointDirection、TargetDirection。资源下载qml_particlesystem —— 包含完整的、可运行的代码系列目录上一篇Qt Quick 粒子系统五粒子组与状态管理本文Qt Quick 粒子系统六五种发射区域的精确控制下一篇Qt Quick 粒子系统七扩散方向模型