Qt Quick 3D - 3D粒子测试平台示例
// 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] } }