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
anchors.fill: parent
View3D {
anchors.fill: parent
camera: camera
environment: SceneEnvironment {
clearColor: "#000000"
backgroundMode: SceneEnvironment.Color
antialiasingMode: settings.antialiasingMode
antialiasingQuality: settings.antialiasingQuality
}
// Particles light
PointLight {
property real animatedBrightness: 1.0
position: psystemStar.position
brightness: sliderLightBrightness.sliderValue * animatedBrightness
// Add some liveness to the light
SequentialAnimation on animatedBrightness {
loops: Animation.Infinite
NumberAnimation {
to: 1.2
duration: 1200
easing.type: Easing.OutElastic
}
NumberAnimation {
to: 1.0
duration: 1600
easing.type: Easing.OutElastic
}
}
}
// General light to the scene
PointLight {
position: Qt.vector3d(300, 500, 600)
// Brigness coming from the amount of trail particles
brightness: 0.1 + sliderSmokeEmitRate.sliderValue * 0.4 + sliderStardustEmitRate.sliderValue * 0.1
ambientColor: Qt.rgba(0.4, 0.1, 0.1, 1.0)
color: "#ff8080"
}
// Animate the camera position & rotation
Node {
PerspectiveCamera {
id: camera
position: Qt.vector3d(0, 300, 800)
eulerRotation.x: -20
SequentialAnimation on z {
loops: Animation.Infinite
NumberAnimation {
to: 500
duration: 4000
easing.type: Easing.InOutQuad
}
NumberAnimation {
to: 800
duration: 4000
easing.type: Easing.InOutQuad
}
}
}
SequentialAnimation on eulerRotation.y {
loops: Animation.Infinite
NumberAnimation {
to: -20
duration: 2000
easing.type: Easing.InOutQuad
}
NumberAnimation {
to: 20
duration: 2000
easing.type: Easing.InOutQuad
}
}
}
// Background wall
Model {
source: "#Rectangle"
scale: Qt.vector3d(80, 50, 0)
z: -500
y: -600
materials: DefaultMaterial {
diffuseColor: "#201010"
}
}
// Qt Cube model
Model {
source: "#Cube"
z: 10
y: 20
scale: Qt.vector3d(2.0, 2.0, 2.0)
NumberAnimation on eulerRotation.y {
loops: Animation.Infinite
from: 0
to: 360
duration: 5000
}
materials: PrincipledMaterial {
baseColorMap: Texture {
source: "images/qt_logo2.png"
}
normalMap: Texture {
source: "images/qt_logo2_n.png"
}
}
}
// System for the trail particles
ParticleSystem3D {
id: psystemTrail
SpriteParticle3D {
id: smokeParticle
sprite: Texture {
source: "images/smoke_sprite.png"
}
maxAmount: 600
spriteSequence: SpriteSequence3D {
frameCount: 15
interpolate: true
}
billboard: true
blendMode: SpriteParticle3D.Screen
colorTable: Texture {
source: "images/color_table2.png"
}
colorVariation: Qt.vector4d(0.0, 0.0, 0.0, 0.8)
fadeInEffect: Particle3D.FadeScale
fadeInDuration: 100
fadeOutEffect: Particle3D.FadeOpacity
fadeOutDuration: 1500
}
ParticleEmitter3D {
id: smokeEmitter
particle: smokeParticle
position: psystemStar.position
particleScale: 20
particleScaleVariation: 5
particleEndScale: 30
particleEndScaleVariation: 10
particleRotationVariation: Qt.vector3d(0, 0, 180)
particleRotationVelocityVariation: Qt.vector3d(0, 0, 40)
emitRate: sliderSmokeEmitRate.sliderValue
lifeSpan: sliderSmokeLifeSpan.sliderValue
lifeSpanVariation: 1000
}
SpriteParticle3D {
id: dustParticle
sprite: Texture {
source: "images/dust.png"
}
maxAmount: 600
blendMode: SpriteParticle3D.Screen
color: "#ff8080"
colorVariation: Qt.vector4d(0.2, 0.4, 0.4, 0.6)
billboard: true
fadeInDuration: 200
fadeOutDuration: 1500
}
ParticleEmitter3D {
id: dustEmitter
particle: dustParticle
position: psystemStar.position
emitRate: sliderStardustEmitRate.sliderValue
lifeSpan: sliderStardustLifeSpan.sliderValue
lifeSpanVariation: 1000
particleScale: 20.0
particleScaleVariation: 10.0
particleRotationVariation: Qt.vector3d(40, 40, 180)
particleRotationVelocityVariation: Qt.vector3d(0, 0, 10)
}
Wander3D {
uniqueAmount: Qt.vector3d(40, 40, 0)
uniqueAmountVariation: 0.8
uniquePace: Qt.vector3d(0.1, 0.1, 0)
uniquePaceVariation: 0.8
fadeInDuration: 3000
}
}
// System for the star sphere particles
ParticleSystem3D {
id: psystemStar
position: Qt.vector3d(0, -200, 0)
// Animate x & y in a heart shape
// This could be done also with Timeline & Keyframes
SequentialAnimation on x {
running: true
loops: Animation.Infinite
NumberAnimation {
to: -300
duration: 1500
easing.type: Easing.OutSine
}
NumberAnimation {
to: 300
duration: 3000
easing.type: Easing.InOutQuad
}
NumberAnimation {
to: 0
duration: 1500
easing.type: Easing.InSine
}
}
SequentialAnimation on y {
running: true
loops: Animation.Infinite
NumberAnimation {
to: 300
duration: 2250
easing.type: Easing.OutSine
}
NumberAnimation {
to: 150
duration: 750
easing.type: Easing.InQuad
}
NumberAnimation {
to: 300
duration: 750
easing.type: Easing.OutQuad
}
NumberAnimation {
to: -300
duration: 2250
easing.type: Easing.InSine
}
}
Vector3dAnimation {
running: true
loops: Animation.Infinite
target: psystemStar
property: "eulerRotation"
from: Qt.vector3d(0, 0, 0)
to: Qt.vector3d(0, 360, -720)
duration: 4000
}
SpriteParticle3D {
id: dotParticle
sprite: Texture {
source: "images/sphere.png"
}
maxAmount: 200
color: Qt.rgba(1.0, 0.8, 0.8, sliderLightBrightness.sliderValue / 300)
colorVariation: Qt.vector4d(0.0, 0.4, 0.4, 0.2)
blendMode: SpriteParticle3D.Screen
}
ParticleEmitter3D {
id: dotParticleEmitter
particle: dotParticle
scale: Qt.vector3d(0.8, 0.8, 0.8)
particleScale: 2.5
particleScaleVariation: 2.0
emitRate: 200
lifeSpan: 1000
shape: ParticleShape3D {
type: ParticleShape3D.Sphere
fill: false
}
}
}
}
SettingsView {
CustomLabel {
text: "Smoke emitrate"
}
CustomSlider {
id: sliderSmokeEmitRate
sliderValue: 50
fromValue: 0
toValue: 100
}
CustomLabel {
text: "Smoke lifeSpan"
}
CustomSlider {
id: sliderSmokeLifeSpan
sliderValue: 3000
fromValue: 1000
toValue: 5000
}
CustomLabel {
text: "Stardust emitrate"
}
CustomSlider {
id: sliderStardustEmitRate
sliderValue: 50
fromValue: 0
toValue: 100
}
CustomLabel {
text: "Stardust lifeSpan"
}
CustomSlider {
id: sliderStardustLifeSpan
sliderValue: 4000
fromValue: 1000
toValue: 5000
}
CustomLabel {
text: "Star brightness"
}
CustomSlider {
id: sliderLightBrightness
sliderValue: 50
fromValue: 1
toValue: 200
}
}
LoggingView {
anchors.bottom: parent.bottom
particleSystems: [psystemStar, psystemTrail]
}
}