I made this simple snowfall animation in QML and it looks pretty good except I noticed it takes too much CPU. It constantly takes around ~9% of my Ubuntu laptop CPU and about ~34% on my imx8mm embedded device. Why is it taking so much CPU and how can I reduce CPU usage?
import QtQuick 2.15
import QtQuick.Window 2.2
import QtQuick.Controls 2.15
import QtQuick.Particles 2.0
Window {
id: root
width: 1024
height: 600
visible: true
Rectangle {
anchors.fill: parent
color: "black"
}
Rectangle {
id: snowfallEmittorArea
anchors.top: parent.top
width: parent.width
color: "black"
z:2
ParticleSystem {
id: particleSystem
}
Emitter {
id: emitter
anchors.fill: parent
system: particleSystem
emitRate: 10
lifeSpan: 4000
sizeVariation: 5
lifeSpanVariation: 500
velocity: AngleDirection {
angle: 90
angleVariation: 10
magnitude: 100
magnitudeVariation: 50
}
}
ItemParticle {
system: particleSystem
delegate: Rectangle {
height: 8
width: 8
radius: 5
color: "white"
}
}
}
}
I'm open to exploring other less CPU-intensive ways to implementing this animation.
I think the ImageParticle is a good suggestion especially if you mix it with SVG. This gives QML the opportunity to compile and cache the SVG image for reuse, whereas with ItemParticle I think there is the burden of dynamic creation of the Item.
I also did a minor refactor to place the UI Rectangle/Item and Emitter at the top and the non-UI declaration ParticleSystem and ItemParticle at the bottom.
import QtQuick
import QtQuick.Controls
import QtQuick.Particles
Page {
background: Rectangle { color: "black" }
Item {
anchors.top: parent.top
width: parent.width
Emitter {
id: emitter
anchors.fill: parent
system: particleSystem
emitRate: 10
lifeSpan: 4000
sizeVariation: 5
lifeSpanVariation: 500
velocity: AngleDirection {
angle: 90
angleVariation: 10
magnitude: 100
magnitudeVariation: 50
}
}
}
ParticleSystem {
id: particleSystem
}
ImageParticle {
system: particleSystem
source: "Particle.qml"
}
}
// Particle.qml
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 8 8">
<circle cx="4" cy="4" r="4" stroke="none" fill="white"/>
</svg>
You can Try it Online!
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 days ago.
Improve this question
I developed software with python and Qml and I want to display a sequence of 2D images (100 slices) in a 3D space with Qml in this software. I think Qt3D or QtQuick 3D modules are proper for that purpose because the following code displays an image in 3D space but cannot figure out how to display a sequence of images.
import QtQuick 2.14
import QtQuick.Window 2.14
import QtQuick3D 1.14
Window {
id: window
width: 640
height: 640
visible: true
color: "black"
Rectangle {
id: qt_logo
width: 230
height: 230
anchors.top: parent.top
anchors.left: parent.left
anchors.margins: 10
color: "black"
property int angle: 0
layer.enabled: true
Image {
anchors.fill: parent
source: "qt_logo.png"
}
}
View3D {
id: view
anchors.fill: parent
camera: camera
renderMode: View3D.Overlay
PerspectiveCamera {
id: camera
position: Qt.vector3d(0, 200, -300)
rotation: Qt.vector3d(30, 0, 0)
}
DirectionalLight {
rotation: Qt.vector3d(30, 0, 0)
}
Model {
id: cube
visible: true
position: Qt.vector3d(0, 0, 0)
source: "#Rectangle"
materials: [ DefaultMaterial {
diffuseMap: Texture {
id: texture
sourceItem: qt_logo
flipV: true
}
}
]
rotation: Qt.vector3d(0, 0, 0)
}
}
}
Edit: I searched a little more and I found the texture3D in the Qt3d module could be a better option for my purpose. But I can't find any example of texture3D in qml. Now the following questions are my problems? 1. How I can generate a texture3D from a stack of 2D images? 2. How I can display a texture3D in qml. 3. Can I generate input data manually for Texture3D (Like 3D array)?
Thank you for your help.
If you're using Texture you can set sourceItem to place any 2D component, including, Rectangle and Image onto a 3D object, such as a "#Cube".
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import QtQuick3D
Page {
background: Rectangle { color: "#848895" }
Node {
id: standAloneScene
DirectionalLight { ambientColor: Qt.rgba(1.0, 1.0, 1.0, 1.0) }
Node {
id: node
Model {
source: "#Cube"
materials: [
DefaultMaterial {
diffuseMap: Texture {
sourceItem: MyItem { }
}
}
]
}
}
OrthographicCamera {
id: cameraOrthographicFront
lookAtNode: node
y: 800; z: 1000
}
}
View3D {
anchors.fill: parent
importScene: standAloneScene
camera: cameraOrthographicFront
}
NumberAnimation {
target: node
property: "eulerRotation.y"
loops: Animation.Infinite
running: true
from: 720; to: 0
duration: 10000
}
}
// MyItem.qml
import QtQuick
import QtQuick.Controls
Rectangle {
width: 256
height: 256
color: "#78a"
Repeater {
model: 5
Image {
x: index * 20 + 20
y: index * 20 + 20
width: 128
height: 128
source: "https://stephenquan.github.io/images/qt/madewithqt.png"
}
}
}
You can Try it Online!
So I'm trying to create an application in QML, and doing so by using an ApplicationWindow. The following code is in main.qml, where some of the components are defined in other files (they are not essential for this problem):
import QtQuick 2.12
import QtQuick.Extras 1.4
import QtQuick.Controls 2.5
import QtQuick.Controls.Styles 1.4
import QtQuick.Window 2.3
import QtDataVisualization 1.3
import Qt3D.Core 2.9
import Qt3D.Render 2.9
import QtCharts 2.3
ApplicationWindow {
id: window
width: 1280
height: 720
//visibility: ApplicationWindow.FullScreen
visible: true
color: "#444444"
Speedometer {
id: speedometer
x: 49
y: 144
width: 306
height: 320
minValue: 0
maxValue: 600
visible: true
}
Thermometer {
id: thermometer
x: 1170
y: 233
scale: 2
minValue: 0
maxValue: 50
visible: true
}
Slider {
id: slider
from: 0
to: 100
x: 28
y: 594
width: 1224
height: 98
font.pointSize: 14
hoverEnabled: false
enabled: false
live: true
snapMode: Slider.NoSnap
value: 0
visible: true
Behavior on value {
NumberAnimation {
duration: 200
}
}
background: Rectangle {
x: slider.leftPadding
y: slider.topPadding + slider.availableHeight / 2 - height / 2
implicitWidth: 200
implicitHeight: 4
width: slider.availableWidth
height: implicitHeight
radius: 2
color: "#999999"
}
handle: Rectangle {
x: slider.leftPadding + slider.visualPosition * (slider.availableWidth - width)
y: slider.topPadding + slider.availableHeight / 2 - height / 2
implicitWidth: 26
implicitHeight: 26
radius: 13
color: "#0099ff"
}
}
Timer {
interval: 200
running: true
repeat: true
property var distance: Math.random
onTriggered: update()
}
function update(){
var distance = (Math.random() * 0.03) + 0.1;
var speed = (distance * 50) / 0.02;
slider.value = slider.value + distance;
speedometer.value = speed;
thermometer.value = Math.random() * 25 + 25;
}
DataManager {
id: manager
onNewVelocity: {
lineSeries.append(velocity.x, velocity.y)
chartView.title = name
}
}
Timer {
id: timer
repeat: true
interval: 1
onTriggered: {
manager.dummyData();
}
}
Chart {
id: chart
height: 250
width: 250
x: 1000
}
Text {
id: labelText
color: "white"
width: 300
height: 100
}
Button {
id: startThread
text: "Start"
onClicked: {
timer.start()
}
}
Button {
id: stopThread
text: "Stop"
x: 200
onClicked: {
timer.stop()
}
}
Button {
id: clearGraph
text: "Clear"
x: 100
onClicked: {
lineSeries.clear()
}
}
}
The content itself isn't that important, but the thing that is, is the fact that when I personally run the project, the application window doesn't show what it is supposed to. And I'd like to emphasize: I'm collaborating with others on this exact project, and when they run the exact same code as me, they get different results.
The first image is what I get when running the code:
The second image is what they get, and what is actually supposed to show when running the code:
So I've been trying to search Google for every possible solution, but have found nothing. I've reinstalled Qt and QtCreator, but to no prevail. We are running the exact same thing, but I'm the only one that don't see all components show up. The first image is way more zoomed in than the latter, and I'd really like if anyone knew how to fix this. I've struggled to find anything that could help so far
(Extra note: the code I ran didn't include the graph as it wasn't up to date with current version on git, but the other things remain the same. So the bar below and the thermometer component on the right SHOULD be visible, but they're not).
I eventually found a solution to what seems to be a bug from Qt's end. I had to launch QtCreator via a qtcreator.bat file in the same directory as qtcreator.exe with the following content:
#echo off
set QT_SCALE_FACTOR_ROUNDING_POLICY=Round
set QT_AUTO_SCREEN_SCALE_FACTOR=0
qtcreator.exe
When I now run the project, it shows the correct scale :)
I am using QML's inbuilt DropShadow type (import QtGraphicalEffects) to generate a shadow of some rectangles that are contained within an Item. The DropShadow is also a child of said Item. But sometimes the shadow is rendered very badly. I am dynamically creating the screen and adding it to a SwipeView; the code is as follows:
swipeView.addItem(tasksScreen.createObject(swipeView))
swipeView.incrementCurrentIndex()
"tasksScreen" is the screen that the rectangles and DropShadow are part of.
The following video depicts the issue and the code that generates this behavior:
https://yadi.sk/i/mwl_8IZmm_jetQ
I believe the issue is you are making the DropShadow a child of its source - which is creating a looping dependency.
Instead, try making it a sibling of your Item or even better, set it up as your Item's layer.effect.
You can see these different techniques in the DropShadow documentation:
https://doc.qt.io/qt-5/qml-qtgraphicaleffects-dropshadow.html
The problem is the source property in your code you have set the source as the parent item in your code. Give the source as your visual object(Rectangle). I have attached the code for your reference.
import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 2.2
import QtGraphicalEffects 1.0
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Component {
id: swipeviewComponentId
Item {
id: itemId
Rectangle {
id: rectangleId
anchors.fill: parent
anchors.margins: 10
radius: 10
}
DropShadow {
anchors.fill: source
horizontalOffset: 3
verticalOffset: 3
radius: 8.0
samples: 17
color: "#80000000"
source: rectangleId
}
}
}
Column {
anchors.fill: parent
anchors.margins: 10
spacing: 10
SwipeView {
id: swipeViewId
width: parent.width
height: parent.height - addButtonId.height - (2 * parent.spacing) - pageIndicatorId.height
}
PageIndicator {
id: pageIndicatorId
currentIndex: swipeViewId.currentIndex
count: swipeViewId.count
anchors.horizontalCenter: parent.horizontalCenter
}
Button {
id: addButtonId
width: parent.width
height: 40
text: "Add item"
onClicked: {
swipeViewId.addItem(swipeviewComponentId.createObject(swipeViewId,
{height: swipeViewId.height, width: swipeViewId.width}))
swipeViewId.incrementCurrentIndex()
}
}
}
}
I am working with the particle system in qml, but I want my particles originating from the center of my rectangle.
The foregoing I can tell you that it is already done, but what I do not like is that the particles emerge in disorder and without direction.
I would like the particles to spread evenly from the center to the ends, but I do not know how to do it.
If someone I could suggest some idea.
I annex my code.
Corrections, ideas or suggestions that solve my problem are accepted.
import QtQuick 2.0
import QtQuick.Particles 2.0
Rectangle {
id: bg
width: 360
height: 360
color: "black"
ParticleSystem {
id: particleSys
}
Emitter{
id: emitter
anchors.centerIn: parent
height: 14; width: 16
system: particleSys
emitRate: 80
lifeSpan: 4000
lifeSpanVariation: 500
maximumEmitted: 1000
size: 5
endSize: 40
velocity: TargetDirection{
targetX: 0; targetY: 0
targetVariation: 360
magnitude: 250
}
}
ImageParticle{
source: "images/blueBlip.png" //My image
system: particleSys
}
}
Thanks.
I am the person who asked the question.
I found a solution to my question.
To emit ordered particles you can make use of the burst() method.
This event allows us to emit a certain number of particles from our emitter. You can manipulate it according to what you need.
I implemented it through a Timmer:
Timer{
interval: 500; running: true; repeat: true
onTriggered: particles.burst(particles.emitRate)
}
The code would look like this:
import QtQuick 2.0
import QtQuick.Particles 2.0
Rectangle {
id: bg
width: 360
height: 360
color: "black"
ParticleSystem {
id: particleSys
}
Emitter{
id: particles
anchors.centerIn: parent
height: 14; width: 16
system: particleSys
emitRate: 80
lifeSpan: 4000
lifeSpanVariation: 500
maximumEmitted: 1000
size: 5
endSize: 40
velocity: TargetDirection{
targetX: 0; targetY: 0
targetVariation: 360
magnitude: 250
}
Timer{
interval: 500; running: true; repeat: true
onTriggered: particles.burst(particles.emitRate)
}
}
ImageParticle{
source: "images/blueBlip.png" //My image
system: particleSys
}
}
If someone knows a more efficient way or someone can improve it ... contribute your answer.
Thanks.
Thanks for this!
You don’t need a timer though! You only need to call particles.burst() once to get it started. Calling it every half a second could slow things down; instead you should set the Emitter start time to 0.
import QtQuick 2.0
import QtQuick.Particles 2.0
Rectangle {
id: bg
width: 360
height: 360
color: "black"
ParticleSystem {
id: particleSys
}
Emitter{
id: particles
startTime: 0
anchors.centerIn: parent
height: 14; width: 16
system: particleSys
emitRate: 80
lifeSpan: 4000
lifeSpanVariation: 500
maximumEmitted: 1000
size: 5
endSize: 40
velocity: TargetDirection{
targetX: 0; targetY: 0
targetVariation: 360
magnitude: 250
}
}
ImageParticle {
source: "images/blueBlip.png" //My image
system: particleSys
}
}
Or you could call particles.burst() on a specific event such as Component.onCompleted:
Emitter{
id: particles
anchors.centerIn: parent
height: 14; width: 16
system: particleSys
emitRate: 80
lifeSpan: 4000
lifeSpanVariation: 500
maximumEmitted: 1000
size: 80
endSize: 100
velocity: TargetDirection{
targetX: 0; targetY: 0
targetVariation: 360
magnitude: 250
}
Component.onCompleted: {
particles.burst(particles.emitRate)
}
}
I have frameless main window, created by qml ( ApplicationWindow {..} in my main.qml file)
I instantiate qml by QQmlApplicationEngine::load (class introduced in Qt5.1).
If I set the Qt.FramelessWindowHint flag, the window is frameless, but loses shadow (in Windows).
How to add shadow to my window?
My window listing:
ApplicationWindow {
id: rootWindow
color : "#f8f8f8"
maximumHeight: 445
minimumHeight: 445
minimumWidth: 730
maximumWidth: 730
flags : Qt.FramelessWindowHint | Qt.Window
Component.onCompleted: {
setHeight(455)
setWidth(740)
}
MainObject{
id:mainObject1
anchors.fill: parent
height:445
width:730
}
}
The solution is to implement the shadow part integral to the application, this way you can disable WM decoration and still have decoration, and have it consistent across different platforms.
In the following example the window has a shadow that even animates to create the effect of lifting the window up when moving it. And when the window is maximized, the margins are removed and the shadow is thus no longer visible.
import QtQuick 2.7
import QtQuick.Controls 2.1
import QtGraphicalEffects 1.0
import QtQuick.Window 2.3
ApplicationWindow {
id: main
visible: true
width: 300
height: 200
color: "#00000000"
flags: Qt.FramelessWindowHint | Qt.Window
Rectangle {
id: rect
anchors.fill: parent
anchors.margins: main.visibility === Window.FullScreen ? 0 : 10
MouseArea {
id: ma
anchors.fill: parent
property int dx
property int dy
onPressed: { dx = mouseX; dy = mouseY }
onPositionChanged: {
main.x += mouseX - dx
main.y += mouseY - dy
}
onDoubleClicked: main.visibility = main.visibility === Window.FullScreen ? Window.AutomaticVisibility : Window.FullScreen
}
}
DropShadow {
anchors.fill: rect
horizontalOffset: 1
verticalOffset: 1
radius: ma.pressed ? 8 : 5
samples: 10
source: rect
color: "black"
Behavior on radius { PropertyAnimation { duration: 100 } }
}
}
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12
import QtGraphicalEffects 1.0
ApplicationWindow{
id: window
visible: true
width: 640
height: 480
title: qsTr("Hello World")
flags: Qt.Window | Qt.FramelessWindowHint
color: "#00000000"
Rectangle {
id: rect
anchors.fill: parent
anchors.margins: 10
radius: 5
}
DropShadow {
anchors.fill: rect
samples: 20
source: rect
color: "gray"
}
}
If you mean the drop shadow effect, that is not quite so.
We have no control over the WM decoration in Qt besides the frameless window flag you have just used. It is pretty much WM specific. Windows (TM) WM applies shadow effect to decorate windows, but this is a Windows (TM) choice. Also, you have just hinted that it should not decorate.