Particles

Overview

Qt Quick 2 comes with the Particles module for making nice visual particle effects, which can be used by many applications that require a lot of tiny moving particles such as fire simualtion, smoke, stars, music visualization, and so on.

The Particles [http://qt-project.org/doc/qt-5.0/qtquick/qtquick-particles2-qtquick-effects-particles.html] module is based on four major components:

Basic Setup

Let’s start with a simple example that illustrates how we can use those different elements together to make particle effects.

The following example implements a simple rectangle with a ParticleSystem type that contains an ImageParticle [http://qt-project.org/doc/qt-5.0/qtquick/qml-qtquick-particles2-imageparticle.html] to render particles based on an image, and an Emitter to create and emit particles.

// particles_example_02.qml

import QtQuick 2.0
import QtQuick.Particles 2.0

Rectangle {

    width: 360
    height: 600
    color: "black"

    ParticleSystem {
        anchors.fill: parent

        // renders a tiny image
        ImageParticle {
            source: "resources/particle.png"
        }

        // emit particle object with a size of 20 pixels
        Emitter {
            anchors.fill: parent
            size: 20
        }
    }
}

If you run the code shown above, you will see a couple of tiny particles (based on the image source) blinking on a black background.

_images/particles-1.png

The particles are emitted all over the entire area of the parent because we set the emitter’s anchors to fill the entire area of the root element (that is, the rectangle).

To make the animation more intersting, we may want to make all particles emit from the bottom of the window and spread out with an increased lifeSpan [http://qt-project.org/doc/qt-5.0/qtquick/qml-qtquick-particles2-emitter.html#lifeSpan-prop].

First we set the emitter’s anchors and specify where we want the particles to be emitted from.

Emitter {
    height: 10; width: 10
    anchors.bottom: parent.bottom
    anchors.horizontalCenter: parent.horizontalCenter
}

Then we set the trajectory and speed of the particles using AngleDirection [http://qt-project.org/doc/qt-5.0/qtquick/qml-qtquick-particles2-angledirection.html] QML type.

Emitter {
    ...
    velocity:  AngleDirection {
        // Make particles spread out vertically from the bottom
        angle: 270
        // make the movement of the particles slighly different from
        // one another
        angleVariation: 10
        // set speed to 150
        magnitude: 100
        }
    ...
}

As the default lifeSpan for a particle is one second, we will increase its value so that we can visualize the particles path:

Emitter {
    ...
    // 8 seconds may be enough
    lifeSpan: 8000
}

We can also set the particles to emit in various sizes by using the sizeVariation [http://qt-project.org/doc/qt-5.0/qtquick/qml-qtquick-particles2-emitter.html#sizeVariation-prop] property in the Emitter component:

Emitter {
    ...
    // set the variation up to 5 pixels bigger or smaller
    sizeVariation: 5
}

The colorVariation [http://qt-project.org/doc/qt-5.0/qtquick/qml-qtquick-particles2-imageparticle.html#colorVariation-prop] property in the ImageParticle type enables us to apply color variation to the particles:

ImageParticle {
    ...
    //Color is measured, per channel, from 0.0 to 1.0.
    colorVariation: 1.0
}

Then we can use the Gravity [http://qt-project.org/doc/qt-5.0/qtquick/qml-qtquick-particles2-gravity.html] affector to make our particles fall back down.

ParticleSystem {
    ...
    Gravity {
        anchors.fill: parent
        // apply an angle of acceleration when the particles hit
        // the affector
        angle: 90
        // accelerate with 15  pisxels/second
        acceleration: 15
    }
    ...
}

If you now run the code, you will see an animation displaying particles of different sizes and colors spreading out from the bottom to the top of the window and then falling back down.

_images/particles-2.png

Note

The complete code is available in the particles_example_02.qml file.

ParticleGroups and Transitions

The Particles module also provides a ParticleGroup [http://qt-project.org/doc/qt-5.0/qtquick/qml-qtquick-particles2-particlegroup.html] type that enables us to set timed transitions on particle groups. This could be very helpful if we want to implement animations with special behavior that require many transitions.

To illusrate how we can use ParticleGroup, let’s implement a simple fireworks animation. The particles should be emitted from the bottom of the window. We’ll also add some TrailEmitters [http://qt-project.org/doc/qt-5.0/qtquick/qml-qtquick-particles2-trailemitter.html] that simulates smoke produced by flames as well as explosions in mid-air.

In our fireworks animation we proceed as follows:

Within the main Rectangle, we add a ParticleSystem that will be used by all components to run the animation.

Add the main Emitter that emits firework particles from the buttom to the top of the window and specify a logical group identifier so that we can later assign an ImageParticle to render the flame particles.

Add a TrailEmitter that will simulate the smoke produced by the flame. We also specify a logical group so that we can later assign the corresponding ParticlePainter to the emitter.

Add a ParticleGroup to simulate the explosion using a TrailEmitter type.

Add a GroupGoal in the main Emitter to tell where or when to apply the transition we define in the ParticleGroup.

Note

A logical group enables us to paint particles emitted by different Emitters using different ImagePartilces within the same ParticleSystem as we will see later in the four seasons demo application.

So first, we declare one main Emitter that emits firework particles from the bottom to the top:

import QtQuick 2.0
import QtQuick.Particles 2.0

Rectangle {

    width: 360
    height: 600
    color: "black"


    // main particle system
    ParticleSystem {id: particlesSystem}

    // firework emitter
    Emitter {
        id: fireWorkEmitter
        system: particlesSystem
        enabled: true
        lifeSpan: 1600
        maximumEmitted: 6
        // Specify the logical group that
        // the emitter belongs to
        group: "A"
        // we want to emit particles
        // from the bottom of the window
        anchors{
            left: parent.left
            right: parent.right
            bottom: parent.bottom
        }

        velocity:  AngleDirection {
                    angle: 270
                    angleVariation: 10
                    magnitude: 200
                }
    }
}

Then we add a TrailEmitter type to simulate the smoke produced by the firework before exploding in the air.

TrailEmitter {
    system: particlesSystem
    group: "B"
    // follow particle emitted by fireWorkEmitter
    follow: "A"
    size: 12
    emitRatePerParticle: 50
    velocity: PointDirection {yVariation: 10; xVariation: 10}
    acceleration: PointDirection {y:  10}
}

Then we add a ParticleGroup type to set a transition and simulate the explosion of particles in the air. We will be using a TrailEmitter with an AngleDirection to display the exploding effect.

ParticleGroup {
    name: "exploding"
    duration: 500
    system: particlesSystem

    TrailEmitter {
        group: "C"
        enabled: true
        anchors.fill: parent
        lifeSpan: 1000
        emitRatePerParticle: 80
        size: 10
        velocity: AngleDirection {angleVariation: 360; magnitude: 100}
        acceleration: PointDirection {y:  20}
    }
}

In order to know exactly where to apply the transition, we add a GroupGoal [http://qt-project.org/doc/qt-5.0/qtquick/qml-qtquick-particles2-groupgoal.html] type inside the fireWorkEmitter that tells the emitter what the aimed state is and when/where the particles should switch to it.

Emitter {
    id: foreWorkEmitter
    ...
    GroupGoal {
        // on which group to apply
        groups: ["A"]
        // the goalState
        goalState: "exploding"
        system: particlesSystem
        // switch once the particles reach the window center
        y: - root.height / 2
        width: parent.width
        height: 10
        // make the particles immediately move to the goal state
        jump: true
    }
}

Next, we just add the ImageParticle types to visualize particles for each group defined above.

// ParticlePainter for the main emitter
ImageParticle {
    source: "resources/particle.png"
    system: particlesSystem
    color: "red"
    groups: ["A"]
}

//  ParticlePainter for the trailEmitter smoke
ImageParticle {
    source: "resources/smoke_particle.png"
    system: particlesSystem
    groups: ["B"]
    color: "white"
}

// ParticlePainter for the trailEmitter in the ParticleGroup
ImageParticle {
    source: "resources/smoke_particle.png"
    system: particlesSystem
    groups: ["C"]
    color: "red"
    colorVariation: 1.2
}

And now if you run the code, you should have a simple animation that displays particles emitted from the window bottom and exploding once they reach the window center:

_images/fireworks.png

what’s next?

In the next article, we introduce the ShaderEffect type used for more advanced graphic effects. We will also implement a demo application that uses Particles and Shaders.