Qt Quick 3D - Particles 3D Testbed Example
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
import QtQuick
import QtQuick3D
import QtQuick3D.Particles3D
Item {
id: mainWindow
readonly property real fireStrength: sliderFireStrength.sliderValue
readonly property real smokeStrength: sliderSmokeStrength.sliderValue
readonly property real sparklesStrength: sliderSparklesStrength.sliderValue
anchors.fill: parent
View3D {
anchors.fill: parent
environment: SceneEnvironment {
clearColor: "#000000"
backgroundMode: SceneEnvironment.Color
antialiasingMode: settings.antialiasingMode
antialiasingQuality: settings.antialiasingQuality
}
PerspectiveCamera {
id: camera
position: Qt.vector3d(0, 100, 300)
}
// Light following the fire
PointLight {
property real animatedBrightness: 0.1
position: fireEmitter.position
brightness: 0.04 * smokeStrength + 0.4 * fireStrength + animatedBrightness * sparklesStrength;
// Add some liveness to the light
SequentialAnimation on animatedBrightness {
loops: Animation.Infinite
NumberAnimation {
to: 0.12
duration: 1000
easing.type: Easing.OutElastic
}
NumberAnimation {
to: 0.05
duration: 1500
easing.type: Easing.InOutQuad
}
NumberAnimation {
to: 0.1
duration: 2500
easing.type: Easing.InElastic
}
}
}
// Background walls & floor
Node {
id: background
visible: checkBoxBackground.checked
Model {
source: "#Rectangle"
position: Qt.vector3d(200, 0, -300)
scale: Qt.vector3d(10.0, 10.0, 0.0)
materials: DefaultMaterial {
diffuseColor: "#204020"
}
}
Model {
source: "#Rectangle"
position: Qt.vector3d(200, -100, -300)
eulerRotation.x: -90
scale: Qt.vector3d(10.0, 10.0, 0.0)
materials: DefaultMaterial {
diffuseColor: "#204020"
}
}
Model {
source: "#Rectangle"
position: Qt.vector3d(-300, 0, -200)
eulerRotation.y: 90
scale: Qt.vector3d(10.0, 10.0, 0.0)
materials: DefaultMaterial {
diffuseColor: "#204020"
}
}
}
ParticleSystem3D {
id: psystem
SpriteParticle3D {
id: particleFire
sprite: Texture {
source: "images/sphere.png"
}
colorTable: Texture {
source: "images/colorTable.png"
}
maxAmount: 300
color: "#ffffff"
colorVariation: Qt.vector4d(0.0, 0.6, 0.8, 0.0)
billboard: true
blendMode: SpriteParticle3D.Screen
fadeInDuration: 100
}
ParticleEmitter3D {
id: fireEmitter
particle: particleFire
particleScale: 4
particleEndScale: 12
particleScaleVariation: 3
particleEndScaleVariation: 5
velocity: VectorDirection3D {
direction: Qt.vector3d(0, 20 + fireStrength, 0)
directionVariation: Qt.vector3d(10 + fireStrength * 0.2, 10, 0)
}
emitRate: fireStrength * 2
lifeSpan: 1000
lifeSpanVariation: 500
// Animate the fire position
SequentialAnimation on x {
paused: !checkBoxAnimate.checked
loops: Animation.Infinite
NumberAnimation {
to: 100
duration: 2500
easing.type: Easing.InOutQuad
}
NumberAnimation {
to: -100
duration: 2500
easing.type: Easing.InOutQuad
}
}
}
SpriteParticle3D {
id: particleSparkle
sprite: Texture {
source: "images/sphere.png"
}
colorTable: Texture {
source: "images/color_table3.png"
}
maxAmount: 400
colorVariation: Qt.vector4d(0.0, 0.0, 0.0, 0.4)
blendMode: SpriteParticle3D.Screen
}
ParticleEmitter3D {
id: sparklesEmitter
particle: particleSparkle
position: fireEmitter.position
particleScale: 1.0
particleEndScale: 0
particleScaleVariation: 0.5
particleRotationVariation: Qt.vector3d(180, 180, 0)
particleRotationVelocityVariation: Qt.vector3d(400, 400, 0)
velocity: VectorDirection3D {
direction: Qt.vector3d(0, 50 + sparklesStrength, 0)
directionVariation: Qt.vector3d(50, 10 + sparklesStrength * 0.5, 0)
}
emitRate: sparklesStrength * 4
lifeSpan: 500
lifeSpanVariation: 500
}
SpriteParticle3D {
id: smokeParticle
sprite: Texture {
source: "images/smoke_sprite.png"
}
maxAmount: 200
spriteSequence: SpriteSequence3D {
frameCount: 15
interpolate: true
}
billboard: true
color: "#40ffffff"
colorVariation: Qt.vector4d(0.5, 0.5, 0.5, 0.2)
unifiedColorVariation: true
fadeOutEffect: Particle3D.FadeOpacity
fadeOutDuration: 1500
}
ParticleEmitter3D {
id: smokeEmitter
particle: smokeParticle
// Smoke always behind the fire & sparkles
position: Qt.vector3d(fireEmitter.position.x, fireEmitter.position.y, fireEmitter.position.z - 2)
particleScale: 6
particleScaleVariation: 4
particleEndScale: 35
particleEndScaleVariation: 15
particleRotationVariation: Qt.vector3d(0, 0, 180)
particleRotationVelocityVariation: Qt.vector3d(0, 0, 40)
emitRate: smokeStrength * 0.5
lifeSpan: 3000
lifeSpanVariation: 1000
velocity: VectorDirection3D {
direction: Qt.vector3d(0, 50 + smokeStrength * 0.1, 0)
directionVariation: Qt.vector3d(20, 20, 0)
}
}
Gravity3D {
// Add gravity to sparkles
particles: particleSparkle
magnitude: 200
}
}
}
SettingsView {
CustomLabel {
text: "Fire Strength"
}
CustomSlider {
id: sliderFireStrength
sliderValue: 50
fromValue: 0
toValue: 100
}
CustomLabel {
text: "Smoke Strength"
}
CustomSlider {
id: sliderSmokeStrength
sliderValue: 50
fromValue: 0
toValue: 100
}
CustomLabel {
text: "Sparkles Strength"
}
CustomSlider {
id: sliderSparklesStrength
sliderValue: 50
fromValue: 0
toValue: 100
}
CustomCheckBox {
id: checkBoxBackground
text: "Show Background"
checked: true
}
CustomCheckBox {
id: checkBoxAnimate
text: "Animate Position"
checked: true
}
}
LoggingView {
anchors.bottom: parent.bottom
particleSystems: [psystem]
}
}