Qt Quick 3D - Particles 3D Testbed Example

 // Copyright (C) 2023 The Qt Company Ltd.
 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause

 import QtQuick
 import QtQuick3D
 import QtQuick3D.Particles3D
 import QtQuick3D.Helpers

 Item {
     anchors.fill: parent

     View3D {
         anchors.fill: parent

         environment: SceneEnvironment {
             clearColor: "#101010"
             backgroundMode: SceneEnvironment.Color
             antialiasingMode: AppSettings.antialiasingMode
             antialiasingQuality: AppSettings.antialiasingQuality
         }
         PerspectiveCamera {
             id: camera
             position: Qt.vector3d(0, 100, 600)
             clipFar: 2000
         }
         WasdController {
             controlledObject: camera
         }
         PointLight {
             id: pointLight
             position.y: 100
             brightness: 100
             quadraticFade: 50
         }

         Model {
             source: "#Cube"
             position.y: -100
             scale: Qt.vector3d(20, 1, 20)
             materials: PrincipledMaterial {
                 baseColor: Qt.rgba(1.0, 0.8, 0.8, 1.0)
             }
         }
         Node {
             id: spheres
             property real angle: 0.0
             NumberAnimation {
                 target: spheres
                 property: "angle"
                 from: 0.0
                 to: 360.0
                 duration: 5000
                 loops: Animation.Infinite
                 running: true
             }
             eulerRotation.y: angle
             Model {
                 id: sphere1
                 source: "#Sphere"
                 position.y: -50
                 position.x: -100
                 scale: Qt.vector3d(1.8, 1.8, 1.8)
                 materials: PrincipledMaterial {
                     baseColor: Qt.rgba(0.8, 1.0, 0.8, 1.0)
                 }
             }
             Model {
                 id: sphere2
                 source: "#Sphere"
                 position.y: 0
                 position.x: 300
                 scale: Qt.vector3d(0.9, 0.9, 0.9)
                 materials: PrincipledMaterial {
                     baseColor: Qt.rgba(0.8, 1.0, 0.8, 1.0)
                 }
             }
         }

         ParticleSystem3D {
             id: psystem

             property real particleScaleFactor : 1.0 + Math.abs(Math.cos(2.0 * Math.PI * scaleTemp))
             property real scaleTemp: 0.0
             NumberAnimation {
                 target: psystem
                 property: "scaleTemp"
                 from: 0.0
                 to: 1.0
                 duration: 400
                 loops: Animation.Infinite
                 running: true
             }


             LineParticle3D {
                 id: particle
                 sprite: Texture {
                     source: "images/qt_logo.png"
                 }
                 maxAmount: 200 + emitter.emitRate * emitter.lifeSpan / 1000
                 color: Qt.rgba(1.0, 1.0, 1.0, sliderOpacity.sliderValue * 0.01)
                 colorVariation: Qt.vector4d(0.6, 0.6, 0.6, 0.0)
                 fadeInDuration: 500
                 fadeOutDuration: 500
                 segmentCount: sliderSegmentCount.sliderValue
                 alphaFade: sliderOpacityFade.sliderValue * 0.01
                 scaleMultiplier: sliderSizeFactor.sliderValue
                 texcoordMultiplier: sliderTexcoordFactor.sliderValue
                 particleScale: sliderSize.sliderValue
                 eolFadeOutDuration: 500
                 texcoordMode: LineParticle3D.Relative
                 billboard: billboardCheckBox.checked
                 length: lengthCheckBox.checked ? lengthSlider.sliderValue : -1.0
                 lengthVariation: lengthVariationSlider.sliderValue
                 lengthDeltaMin: lengthDeltaSlider.sliderValue
                 sortMode: LineParticle3D.SortDistance
             }

             ParticleEmitter3D {
                 id: emitter
                 particle: particle
                 position: Qt.vector3d(-550, 0, 0)
                 scale: Qt.vector3d(2.0, 0.5, 2.0)
                 shape: ParticleShape3D {
                     type: ParticleShape3D.Sphere
                 }
                 velocity: VectorDirection3D {
                     direction: Qt.vector3d(sliderVelocityY.sliderValue * 40, 0, 0)
                     directionVariation: Qt.vector3d(sliderVelocityY.sliderValue * 20, 15, 0)
                 }
                 emitRate: sliderEmitRate.sliderValue
                 lifeSpan: 500 * 1000 / (sliderVelocityY.sliderValue * 40)
             }

             ParticleEmitter3D {
                 id: emitter2
                 particle: particle
                 position: Qt.vector3d(-550, 0, 60)
                 scale: Qt.vector3d(2.0, 0.5, 2.0)
                 shape: ParticleShape3D {
                     type: ParticleShape3D.Sphere
                 }
                 velocity: VectorDirection3D {
                     direction: Qt.vector3d(sliderVelocityY.sliderValue * 40, 0, 0)
                     directionVariation: Qt.vector3d(sliderVelocityY.sliderValue * 20, 15, 0)
                 }
                 emitRate: sliderEmitRate.sliderValue
                 lifeSpan: 500 * 1000 / (sliderVelocityY.sliderValue * 40)
             }
             ParticleEmitter3D {
                 id: emitter3
                 particle: particle
                 position: Qt.vector3d(-550, 0, 120)
                 scale: Qt.vector3d(2.0, 0.5, 2.0)
                 shape: ParticleShape3D {
                     type: ParticleShape3D.Sphere
                 }
                 velocity: VectorDirection3D {
                     direction: Qt.vector3d(sliderVelocityY.sliderValue * 40, 0, 0)
                     directionVariation: Qt.vector3d(sliderVelocityY.sliderValue * 20, 15, 0)
                 }
                 emitRate: sliderEmitRate.sliderValue
                 lifeSpan: 500 * 1000 / (sliderVelocityY.sliderValue * 40)
             }

             Repeller3D {
                 particles: [particle]
                 position: sphere1.scenePosition
                 outerRadius: sliderRadius.sliderValue
                 strength: sliderRepelStrength.sliderValue
             }
             Repeller3D {
                 particles: [particle]
                 position: sphere2.scenePosition
                 outerRadius: sliderRadius.sliderValue * 0.5
                 strength: sliderRepelStrength.sliderValue
             }
         }
     }

     SettingsView {
         CustomLabel {
             text: "Billboard particle"
         }
         CustomCheckBox {
             id: billboardCheckBox
             checked: true
         }
         CustomLabel {
             text: "Line Segment Count"
         }
         CustomSlider {
             id: sliderSegmentCount
             sliderValue: 10
             fromValue: 1
             toValue: 250
             sliderStepSize: 1
         }
         CustomLabel {
             text: "Line minimum length"
         }
         CustomSlider {
             id: lengthDeltaSlider
             sliderValue: 10.0
             fromValue: 0.0
             toValue: 50.0
         }
         CustomLabel {
             text: "Line Opacity Fade"
         }
         CustomSlider {
             id: sliderOpacityFade
             sliderValue: 0
             fromValue: 0
             toValue: 100
             sliderStepSize: 1
         }
         CustomLabel {
             text: "Size"
         }
         CustomSlider {
             id: sliderSize
             sliderValue: 1
             fromValue: 0.1
             toValue: 20.0
         }
         CustomLabel {
             text: "Line Size Modifier"
         }
         CustomSlider {
             id: sliderSizeFactor
             sliderValue: 1
             fromValue: 0.1
             toValue: 2.0
         }
         CustomLabel {
             text: "Line Texcoord Modifier"
         }
         CustomSlider {
             id: sliderTexcoordFactor
             sliderValue: 1
             fromValue: 0.01
             toValue: 20.0
         }
         CustomLabel {
             text: "Emit Rate"
         }
         CustomSlider {
             id: sliderEmitRate
             sliderValue: 50
             fromValue: 1
             toValue: 200
         }
         CustomLabel {
             text: "Start Velocity"
         }
         CustomSlider {
             id: sliderVelocityY
             sliderValue: 10
             fromValue: 0.1
             toValue: 50
         }
         CustomLabel {
             text: "Opacity"
         }
         CustomSlider {
             id: sliderOpacity
             sliderValue: 30.0
             fromValue: 0.0
             toValue: 100.0
         }
         CustomLabel {
             text: "Repel Radius"
         }
         CustomSlider {
             id: sliderRadius
             sliderValue: 1000
             fromValue: 1
             toValue: 2000
         }
         CustomLabel {
             text: "Repel Strength"
         }
         CustomSlider {
             id: sliderRepelStrength
             sliderValue: 50.0
             fromValue: 0.0
             toValue: 400.0
         }
         CustomLabel {
             text: "Fixed Length"
         }
         CustomCheckBox {
             id: lengthCheckBox
             checked: false
         }
         CustomLabel {
             text: "Line Length"
         }
         CustomSlider {
             id: lengthSlider
             sliderValue: 50.0
             fromValue: 10.0
             toValue: 200.0
         }
         CustomLabel {
             text: "Line Length Variation"
         }
         CustomSlider {
             id: lengthVariationSlider
             sliderValue: 0.0
             fromValue: 0.0
             toValue: 100.0
         }
     }

     LoggingView {
         anchors.bottom: parent.bottom
         particleSystems: [psystem]
     }
 }