QT 3D NodeInstantiator performance issue - c++

I want to visualize x,y,z points as cubic blocks. I use C++ for backend and qtquick/javascript for frontend. I have implemented QAbstractListModel in C++ side and exposing to qml (qtquick) with QQmlApplicationEngine rootContext. Data include only x,y,z points and color codes. Data have arround 500 thousand coordinate points. I'm trying to visualize this data with NodeInstantiator dynamically. But it takes too much time to create objects, and ram usage increasing rapidly to 5-6 GB. If I solve the performance issue, I will try to add border lines to blocks. And I don't know how to do it aswell.
OS: Windows 10
Ram: 8 GB max
GPU: Nvidia 970 GTX
QT Creator 7.0.0
Kit: Desktop Qt 5.15.2 MinGW 64 Bit
import QtQuick 2.15
import QtQuick.Window 2.15 as W
import QtQuick.Scene3D 2.15
import Qt3D.Core 2.15
import Qt3D.Render 2.15
import Qt3D.Extras 2.15
import Qt3D.Input 2.15
import QtQuick.Controls 2.5
Page {
Rectangle {
id: rect1
x:0
y:0
width: 100
height: 100
color: "red"
}
Scene3D {
id: scene3dId
anchors.top: rect1.bottom
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.left: parent.left
//anchors.fill: parent
aspects: ["input", "logic"]
Entity {
id: scene
property color baseColor
property real metalness
property real roughness
property real exposure
property real gamma
components: [
RenderSettings {
activeFrameGraph: ForwardRenderer {
camera: mainCamera
clearColor: "white"
gamma: scene.gamma
}
},
// Event Source will be set by the Qt3DQuickWindow
InputSettings { }
]
Camera {
id: mainCamera
position: Qt.vector3d(0, 0, 12)
viewCenter: Qt.vector3d(0, 0, 0)
fieldOfView: 60
exposure: scene.exposure
}
OrbitCameraController {
camera: mainCamera
linearSpeed: 1000
lookSpeed: 240
}
CuboidMesh{
id: cubeMesh
xExtent: 1
yExtent: 1
zExtent: 1
}
NodeInstantiator {
id: grid
model: BM
delegate:
Entity {
Transform {
id: transformId
translation: Qt.vector3d(model.X, model.Y, model.Z)
}
PhongMaterial {
id: cubeMaterial
ambient: model.Color
}
components: [transformId, cubeMesh, cubeMaterial]
}
}
}
}
}
An example of what I want to do

Related

Retrieve center of QML map in C++

I've the following QML that shows a map:
import QtQuick 2.0
import QtQuick.Window 2.14
import QtPositioning 5.15
import QtLocation 5
Item {
width: Qt.platform.os == "android" ? Screen.width : 512
height: Qt.platform.os == "android" ? Screen.height : 512
visible: true
property double center_latitude: 59.91
property double center_longitude: 10.75
Plugin {
id: mapPlugin
name: "osm"
}
Map {
anchors.fill: parent
plugin: mapPlugin
center: QtPositioning.coordinate(center_latitude, center_longitude)
zoomLevel: 14
copyrightsVisible: false
}
}
I set int in a QQuickWidget and everything seems ok:
m_quickWidget->setSource(QUrl(QStringLiteral("qrc:/qml/map.qml")));
I can see the map correctly. Now I want to retrieve the coordinates of the center of the map, that should be retrieved with the map center property. The problem is that I don't know how to access to that property with C++.
I've tried
auto mp = m_quickWidget->rootObject()->findChild<QQuickItem*>("Map");
auto items = m_quickWidget->rootObject()->childItems();
auto center = mp->property("center").value<QGeoCoordinate>();
extent.setCenter(LLA{ center.latitude(), center. Longitude(), 0.0 });
center = m_quickWidget->rootObject()->property("center").value<QGeoCoordinate>();
but mp gives me a nullptr, while items is a vector of only one element, and I don't know how to handle it. The last row gives me a QGeoCoordiante with NaN, so it's not correct.
How can I retrieve the center from the QQuickWidget?
findChild() is searching for items via the objectName. So you need to add an objectName to your Map.
Map {
objectName: "testmap"
center: QtPositioning.coordinate(59.91, 10.75)
...
}
and then you can search for it.
auto map = view->rootObject()->findChild<QQuickItem *>("testmap");
if (map) {
auto center = map->property("center").value<QGeoCoordinate>();
qDebug() << map << center;
}
The above code returns the following.
QDeclarativeGeoMap(0x55fc0d7de000, name="testmap", parent=0x55fc0d746940, geometry=0,0 800x600)
QGeoCoordinate(59.91, 10.75)

QML object from C++ class not being destructed?

I've encountered an unexpected behavior (for my point of view) of objects from C++ classes created in QML part of application. An example to be clear:
The starting point is empty QML application.
After that TestEntity class is added:
#ifndef TESTENTITY_H
#define TESTENTITY_H
#include <Qt3DCore>
#include <Qt3DExtras>
class TestEntity : public Qt3DCore::QEntity
{
Q_OBJECT
public:
TestEntity(QNode *parent = nullptr);
~TestEntity();
};
#endif // TESTENTITY_H
#include <QDebug>
#include "testentity.h"
TestEntity::TestEntity(QNode *parent) : Qt3DCore::QEntity(parent)
{
Qt3DExtras::QCuboidMesh *mesh = new Qt3DExtras::QCuboidMesh();
Qt3DCore::QTransform *transform = new Qt3DCore::QTransform();
mesh->setXExtent(12);
mesh->setYExtent(6);
mesh->setZExtent(6);
Qt3DExtras::QDiffuseSpecularMaterial *material = new Qt3DExtras::QDiffuseSpecularMaterial();
material->setAmbient(QColor(Qt::black));
material->setSpecular(QColor(Qt::white));
material->setShininess(4);
this->addComponent(material);
this->addComponent(mesh);
this->addComponent(transform);
}
TestEntity::~TestEntity()
{
qDebug() << "TestEntity destroyed";
}
TestEntity is registered in main.cpp:
qmlRegisterType<TestEntity>("testEntity", 1, 0, "TestEntity");
main.qml:
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import Qt3D.Core 2.15
import QtQuick.Scene3D 2.15
import Qt3D.Render 2.15
import Qt3D.Extras 2.15
import QtQuick3D.Materials 1.15
import testEntity 1.0
ApplicationWindow {
width: 640
height: 480
visible: true
title: qsTr("Hello World")
Scene3D {
anchors.fill: parent
Entity {
id: rootEntity
RenderSettings {
activeFrameGraph: ForwardRenderer {
camera: camera
clearColor: "transparent"
}
}
Entity {
components: [
PointLight {
color: "#ffffff"
intensity: 0.5
enabled: true
},
Transform {
translation: Qt.vector3d(15, 0, 15)
}
]
}
Camera {
id: camera
projectionType: CameraLens.PerspectiveProjection
fieldOfView: 45
nearPlane : 0.1
farPlane : 150
aspectRatio: 1
position: Qt.vector3d(0.0, -20.0, 20.0)
upVector: Qt.vector3d(0.0, 0.0, 1.0)
viewCenter: Qt.vector3d(0.0, 0.0, 0.0)
}
TestEntity {
id: testEntity
}
}
}
}
Everything works as expected except the destruction of TestEntity object - destructor is not called for some reason...
So the question is what is the proper way to add testEntity in QML, so that it'll be rendered and destroyed without any problems?
Thank in advance!

Black screen after existing FullScreen mode

I am trying to make a such thing:
I have a main window with a single button.
After pressing this button two semi transparent windows appear on all screens. They are in a FullScreen mode.
After 4 seconds screens dissapear.
Everything is ok. But when I cklick one of the screens, during process of disappearing, it becomes totaly black. How can I fix it?
// main.qml
import QtQuick 2.10
import QtQuick.Window 2.10
import QtQuick.Controls 2.2
Window {
id: main
visible: true
width: 100
height: 50
title: "Hello Splash World"
Button {
anchors.fill: parent
text: "Show splash"
onClicked: {
for (var i = 0; i < Qt.application.screens.length; ++i) {
var component = Qt.createComponent("SplashScreen.qml");
var window = component.createObject(main, {screen: Qt.application.screens[i]});
window.height = Qt.application.screens[i].height
window.width = Qt.application.screens[i].width
window.showSplash()
}
}
}
}
// SplashScreen.qml
import QtQuick 2.10
import QtQuick.Controls 2.2
ApplicationWindow {
id: splash
flags: Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint | Qt.WA_TranslucentBackground
color: "transparent"
Timer {
running: true
interval: 4000
onTriggered: hideSplash()
}
function showSplash() {
appearAnimation.start()
}
function hideSplash() {
disappearAnumation.start()
}
background: Rectangle {
id: bg
color: "black"
opacity: 0.8
}
SequentialAnimation {
id: appearAnimation
PropertyAction { target: splash; property: "visibility"; value: ApplicationWindow.FullScreen }
NumberAnimation { target: bg; property: "opacity"; duration: 1000; to: 0.8 }
}
SequentialAnimation {
id: disappearAnumation
NumberAnimation { target: bg; property: "opacity"; duration: 2000; to: 0 }
PropertyAction { target: splash; property: "visibility"; value: ApplicationWindow.Hidden }
}
}
I've come across some strange problems with repainting during further development of my program. For example, changing the size of the main form led to black form to. The solution I've found is to use OpenGL for rendering. You can do it by inserting this code:
QCoreApplication::setAttribute(Qt::AA_UseSoftwareOpenGL);
Denis Popov answer is correct, but in this mode my application was a bit laggy. Problem wasn't occuring if mode was set to:
QCoreApplication::setAttribute(Qt::AA_UseOpenGLES);
From the other hand this time I was getting following warning in the output everytime I was creating window:
DXGI WARNING: IDXGIFactory::CreateSwapChain: Blt-model swap effects (DXGI_SWAP_EFFECT_DISCARD and DXGI_SWAP_EFFECT_SEQUENTIAL) are legacy swap effects that are predominantly superceded by their flip-model counterparts (DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL and DXGI_SWAP_EFFECT_FLIP_DISCARD). Please consider updating your application to leverage flip-model swap effects to benefit from modern presentation enhancements. More information is available at http://aka.ms/dxgiflipmodel. [ MISCELLANEOUS WARNING #294: ]
Best solution I come up with so far is to run application in debug mode with one flag and in release/deployment with another:
#ifdef QT_DEBUG
QCoreApplication::setAttribute(Qt::AA_UseSoftwareOpenGL);
#else
QCoreApplication::setAttribute(Qt::AA_UseOpenGLES);
#endif

Basic QML layout for Concentration game

I'm trying to improve my QML skills, by creating a memory game as a multiplayer application. (also known as Concentration).
I created already c++ classes like Player, Game and Card. The Game class holds a vector of a vector of Cards (QVector< QVector< Card*>> m_field;), which represents the field of all cards. The Game class is registered to the QML engine as singleton type, using "qmlRegisterSingletonType(..)".
For now I'm creating the UI, using repeaters as shown in the code below.
Is there a more convenient way to create such a UI? Can I somehow attach an instance of the c++ class Card to the QML instance of Card?
import QtQuick 2.11
import QtQuick.Window 2.11
import de.memory.game_instance 1.0
Window {
id: root
visible: true
width: 450
height: 700
title: qsTr("Memory Game")
Column {
id: col
Repeater {
id: rows
model: Constants.GAME_FIELD_HEIGHT
delegate: Row {
property int row_idx: modelData
Repeater {
id: cells
model: Constants.GAME_FIELD_WIDTH
delegate: Card {
height: root.height / Constants.GAME_FIELD_HEIGHT
width: root.width / Constants.GAME_FIELD_WIDTH
img_source: Game.getImageAt(row_idx, modelData);
img_shown: false
}
}
}
}
}
}

QtQuick: QQmlApplicationEngine failed to load component qrc:/main.qml:23 Invalid attached object assignment

Given my thoughts below am I barking up the wrong tree? Or provided the information below am I misusing Qt API to get the error in the title?
I am trying to modify the sample at http://doc.qt.io/qt-5/qtquick-scenegraph-openglunderqml-example.html to work with the default QtQuick project generated with Qt Creator 3.3.0 (opensource)
Based on Qt 5.4.0 (GCC 4.6.1, 64 bit).
After looking through the code the first thing that stands out to me is:
The samples main.cpp uses:
qmlRegisterType<Squircle>("OpenGLUnderQML", 1, 0, "Squircle");
QQuickView view;
view.setResizeMode(QQuickView::SizeRootObjectToView);
view.setSource(QUrl("qrc:///scenegraph/openglunderqml/main.qml"));
view.show();
With some renaming my main.cpp uses
qmlRegisterType<MainScreen>("OpenGLUnderQML", 1, 0, "MainScreen");
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
I am not sure if the difference in using a QQmlApplicationEngine over a QuickView could be causing my error:
QQmlApplicationEngine failed to load component qrc:/main.qml:23
Invalid attached object assignment
Where my main.qml looks like:
import QtQuick 2.4
import QtQuick.Window 2.2
import OpenGLUnderQML 1.0
import "qmlmodel"
Window {
id: mainWindow
width: 800
height: 600
visible: true
color: "black"
title: "Army Calculator"
objectName: "mainWindow"
ListView {
id: mainListView
anchors.fill: parent
objectName: "mainListView"
}
MainScreen {
SequentialAnimation on DeltaT {
NumberAnimation { to: 1; duration: 2500; easing.type: Easing.InQuad }
NumberAnimation { to: 0; duration: 2500; easing.type: Easing.OutQuad }
loops: Animation.Infinite
running: true
}
}
}
and the sample uses:
import QtQuick 2.0
import OpenGLUnderQML 1.0
Item {
width: 320
height: 480
Squircle {
SequentialAnimation on t {
NumberAnimation { to: 1; duration: 2500; easing.type: Easing.InQuad }
NumberAnimation { to: 0; duration: 2500; easing.type: Easing.OutQuad }
loops: Animation.Infinite
running: true
}
}
Rectangle {
color: Qt.rgba(1, 1, 1, 0.7)
radius: 10
border.width: 1
border.color: "white"
anchors.fill: label
anchors.margins: -10
}
Text {
id: label
color: "black"
wrapMode: Text.WordWrap
text: "The background here is a squircle rendered with raw OpenGL using the 'beforeRender()' signal in QQuickWindow. This text label and its border is rendered using QML"
anchors.right: parent.right
anchors.left: parent.left
anchors.bottom: parent.bottom
anchors.margins: 20
}
}
As per request in comment below MainScreen.h is
#ifndef MAINSCREEN_H
#define MAINSCREEN_H
#include <QQuickItem>
class MainScreenRenderer;
class QQuickWindow;
class MainScreen : public QQuickItem
{
Q_OBJECT
Q_PROPERTY(qreal DeltaT READ getDeltaT WRITE setDeltaT NOTIFY deltaTChanged)
public:
MainScreen();
~MainScreen();
qreal getDeltaT() const;
void setDeltaT(qreal deltaT);
signals:
void deltaTChanged();
public slots:
void sync();
void cleanup();
private slots:
void handleWindowChanged(QQuickWindow *win);
private:
qreal m_DeltaT;
MainScreenRenderer *m_Renderer;
};
#endif // MAINSCREEN_H
Property name should start with lowercase letter. You need to change DeltaT to deltaT.
MainScreen.h
Q_PROPERTY(qreal deltaT READ getDeltaT WRITE setDeltaT NOTIFY deltaTChanged)
main.qml
MainScreen {
SequentialAnimation on deltaT {
}
}