Rain effect with Quick3D Particles
February 16, 2026 by Antti Määttä | Comments
Here is an overview on the new features added to the Quick3D.Particles module for Qt 6.10 and 6.11. The goal was to support effects that look like they are interacting with the scene and to do this without expensive simulations/calculations. Specifically we'll be using rain effect as an example when going trough the new features.
The rain effect consists of the rain particles hitting the scene and a splash particle effect after they hitting the scene models.
So how are we going to get the particles to hit a model without expensive ray-model intersection calculations? Well there is a type called ParticleModelShape3D, which emits particles in a shape of the specified model. It can emit them to a specific direction by setting the velocity in the emitter. If one then set the velocity towards the sky and runs the particle system time in reverse, it appears as if the particles are hitting the model.

Snow accumulation using trail emitter with zero velocity.
ParticleEmitter3D.reversed property
Running the whole system in reverse makes it cumbersome to add other particle effects to the same system so we added a new property to the emitter: reversed. This allows only this one emitter to run in reverse, while the other particle emitters can run forward in time.
Here is how we implement the rain with line particles, model shape and trail emitter to implement the splash effect.
// Rain particle
LineParticle3D {
id: rainParticle
...
}
Component {
id: modelComponent
Model {
// The mesh containing only the top parts of the sphere
source: "meshes/sphere_top.mesh"
}
}
// Rain particle emitter
ParticleEmitter3D {
id: emitter
particle: rainParticle
reversed: true
shape: ParticleModelShape3D {
model: modelComponent
fill: false
}
velocity: VectorDirection3D {
direction: Qt.vector3d(0, 800, 0)
directionVariation: Qt.vector3d(2, 0, 2)
}
}
// Splash particle
SpriteParticle3D {
id: splashParticle
...
}
// Splash particle trail emitter following the rain particle
TrailEmitter3D {
follow: rainParticle
DynamicBurst3D {
id: splashBurst
amount: 20
amountVariation: 2
triggerMode: DynamicBurst3D.TriggerEnd
}
emitBursts: splashBurst
particle: splashParticle
velocity: VectorDirection3D {
direction: Qt.vector3d(0, 0, 10)
directionVariation: Qt.vector3d(50, 50, 1)
}
}
So now we can have rain that can hit a model and create splashes to a specific direction, but wouldn't it be nice if the splash would follow the shape of the model i.e. when the rain particle hits a surface with a certain angle, it would then splash towards the reflected angle.
ParticleEmitter3D.EmitMode
The emit mode of the emitter allows more fine grained control of the emitted particles. It adds two modes of controlling the direction based on the model shape(in addition to the default).
ParticleEmitter3D.SurfaceNormal changes the emit direction to follow the surface normal. When the emit velocity is towards the z-axis, the particles are emitted to the direction of the surface normal.
ParticleEmitter3D.SurfaceReflected is used with trail emitters and the emit directions is towards the reflected vector calculated from surface normal and the velocity of the followed particle.

Default and SurfaceNormal emit modes on suzanne mesh.
Setting the emit mode of the trail emitter to ParticleEmitter3D.SurfaceReflected, the splash particles are now reflected from the surface.
TrailEmitter3D {
...
emitMode: ParticleEmitter3D.SurfaceReflected
}

Particles bouncing off of a sphere using SurfaceReflected mode.
So now we have building blocks for the rain effect for one model, how do we add it for the scene with multiple models. If we add it separately for each model, this would have side effects: the models that have rain effect would have their own rain density so the scene wouldn't have uniform rain. The rain would also pass trough models that are above each other e.g. ground would have rain underneath a model on top of it. To workaround there issues one could precalculate a mesh for the whole scene, but this would be static mesh so models couldn't move in the scene.
ParticleSceneShape3D
The scene shape dynamically calculates a shape for the whole scene based on the models in the scene.
The shape is calculated as a grid placed on top of the scene, where each vertex in the grid is on the top-most point on it's models polygons. Holes are created to the grid when the height between neighboring vertices is too great or if there are no model polygons below the grid vertex.
The shape is recalculated when models move in the scene so it can also be used with dynamic scenes. One can set the resolution of the grid, the extents of the grid to set the size of the shape, it's center and also specify nodes that should be excluded in the calculation of the shape. One can also get the geometry as a property to use e.g. for debugging purposes.
ParticleEmitter3D {
id: emitter
shape: ParticleSceneShape3D {
id: sceneShape
scene: sceneRoot
sceneCenter: Qt.vector3d(0, 0, 0)
sceneExtents: Qt.vector3d(1000, 500, 1000)
excludedNodes: [debugNode]
shapeResolution: 50
}
}
Model {
id: debugNode
geometry: sceneShape.geometry
}

Rain effect in car-configurator demo.
The rain effect has been added to the car-configurator demo in Qt 6.11 along with a snow effect.
Blog Topics:
Comments
Subscribe to our newsletter
Subscribe Newsletter
Try Qt 6.10 Now!
Download the latest release here: www.qt.io/download.
Qt 6.10 is now available, with new features and improvements for application developers and device creators.
We're Hiring
Check out all our open positions here and follow us on Instagram to see what it's like to be #QtPeople.