基于 Q3DScatter 的自定义图表,QCustom3DItem 变慢

Posted

技术标签:

【中文标题】基于 Q3DScatter 的自定义图表,QCustom3DItem 变慢【英文标题】:Custom chart based on Q3DScatter with QCustom3DItem going slow 【发布时间】:2020-01-05 05:06:49 【问题描述】:

我想制作一个带有条形的 3D 图表,条形颜色取决于它的大小。 Qt bar and scatter graph types 都接近我正在寻找的东西。我最终基于Q3DScatter 创建了一个图表并添加了QCustom3DItem 来绘制条形图,这样我就可以为每个项目设置一个网格项目和颜色。我在图表的每个位置都有一个项目。假设这是一个 100x100 的图表,这意味着有 10 000 个条形图(自定义项)。

我想每秒多次重绘整个图表。重绘我的意思是每个项目都会改变它的大小和颜色。要设置项目大小,我调用setScalling()。因为缩放通过保持项目中心位置(并且我想保持条基本位置)来工作,所以我必须在缩放之后调用setPosition。为了设置颜色,我打电话给setTextureImage()。因此,每秒多次调用如下 get 代码:

for (int col = 0; col < 100; col++)
  for (int row = 0; row < 100; row++) 
    items[row*COLS+col]->setScalling(scale);
    items[row*COLS+col]->setPosition(position);
    items[row*COLS+col]->setTextureImage(image);
  

这几乎可以按预期工作。问题是不够快。有关如何使其更快的任何提示?

我试图将自定义项目移动到另一个线程。

为了将QCustom3DItem 的处理(即缩放)移出主(gui)线程,我这样做:

项目.pro

QT += core gui widgets datavisualization
TEMPLATE = app
CONFIG += c++11
SOURCES += main.cpp mainwindow.cpp graphdata.cpp
HEADERS += mainwindow.h graphdata.h

RESOURCES += mesh.qrc

CONFIG(debug, debug|release) 
    DESTDIR = debug
 else 
    DESTDIR = release

OBJECTS_DIR = $$DESTDIR/
MOC_DIR = $$DESTDIR/
RCC_DIR = $$DESTDIR/
UI_DIR = $$DESTDIR/

main.cpp

#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[]) 
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();

主窗口.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

#include "graphdata.h"

class MainWindow : public QMainWindow 
    Q_OBJECT
    QThread thread;
public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
signals:
    void start();
;

#endif // MAINWINDOW_H

主窗口.cpp

#include "mainwindow.h"

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)

    resize(400,300);

    auto graph = new Q3DScatter;
    auto container = QWidget::createWindowContainer(graph);
    setCentralWidget(container);

    auto data = new GraphData(graph);
    data->moveToThread(&thread);
    connect(this, &MainWindow::start, data, &GraphData::start);
    thread.start();
    emit start();


MainWindow::~MainWindow() 
    thread.quit();
    thread.wait();

图形数据.h

class GraphData : public QObject 
    Q_OBJECT
    Q3DScatter* m_graph;
    QCustom3DItem* item;
public:
    explicit GraphData(Q3DScatter* m_graph);

public slots:
    void start();
    void setData(int scale);
;

#endif // GRAPHDATA_H

图形数据.cpp

#include "graphdata.h"

GraphData::GraphData(Q3DScatter* graph) : m_graph(graph)

void GraphData::start() 
    item = new QCustom3DItem;
    item->setMeshFile(QStringLiteral(":mesh.obj"));
    m_graph->addCustomItem(item);


void GraphData::setData(int scale) 
//    item->setScaling();

网格.qrc

<!DOCTYPE RCC><RCC version="1.0">
    <qresource>
        <file>mesh.obj</file>
    </qresource>
</RCC>

网格.obj

# Blender v2.80 (sub 75) OBJ File: ''
# www.blender.org
o Cube
v 1.000000 1.000000 -1.000000
v 1.000000 -1.000000 -1.000000
v 1.000000 1.000000 1.000000
v 1.000000 -1.000000 1.000000
v -1.000000 1.000000 -1.000000
v -1.000000 -1.000000 -1.000000
v -1.000000 1.000000 1.000000
v -1.000000 -1.000000 1.000000
vt 0.625000 0.000000
vt 0.375000 0.250000
vt 0.375000 0.000000
vt 0.625000 0.250000
vt 0.375000 0.500000
vt 0.375000 0.250000
vt 0.625000 0.500000
vt 0.375000 0.750000
vt 0.625000 0.750000
vt 0.375000 1.000000
vt 0.375000 0.500000
vt 0.125000 0.750000
vt 0.125000 0.500000
vt 0.875000 0.500000
vt 0.625000 0.500000
vt 0.625000 0.250000
vt 0.625000 0.750000
vt 0.625000 1.000000
vt 0.375000 0.750000
vt 0.875000 0.750000
vn 0.0000 1.0000 0.0000
vn 0.0000 0.0000 1.0000
vn -1.0000 0.0000 0.0000
vn 0.0000 -1.0000 0.0000
vn 1.0000 0.0000 0.0000
vn 0.0000 0.0000 -1.0000
s off
f 5/1/1 3/2/1 1/3/1
f 3/4/2 8/5/2 4/6/2
f 7/7/3 6/8/3 8/5/3
f 2/9/4 8/10/4 6/8/4
f 1/11/5 4/12/5 2/13/5
f 5/14/6 2/9/6 6/15/6
f 5/1/1 7/16/1 3/2/1
f 3/4/2 7/7/2 8/5/2
f 7/7/3 5/17/3 6/8/3
f 2/9/4 4/18/4 8/10/4
f 1/11/5 3/19/5 4/12/5
f 5/14/6 1/20/6 2/9/6

这看起来有效,QCustom3DItem 在另一个线程上,尽管有警告:

QObject::setParent: Cannot set parent, new parent is in a different thread

我的理解是 m_graph-&gt;addCustomItem(item) 正在尝试更改 item 父级并且失败了。我该如何处理?

我是否应该通过在另一个线程上处理自定义项目来获得更好的性能?

【问题讨论】:

protip:如果您更改立方体网格,使原点 (0,0,0) 位于其底面的中间,则无需调用 setPosition 【参考方案1】:

Qt 适用于原型设计或非性能关键代码。但是,其面向对象的方法与硬件的工作方式不一致,因此很难编写高性能代码。

最好的办法是覆盖绘图代码以在一次调用中呈现所有条形图。如果需要支持旧硬件,请生成一个包含所有顶点的 VBO,并在一个 glDrawArrays 调用中发送它。如果最近的硬件没问题,那么您可以通过实例化在 GPU 上生成所有网格,并从纹理中获取条形高度。在后一种情况下,您只需要每帧发送 10,000 个浮点数,这在带宽方面不算什么。

底线:实时渲染 10,000 个立方体对于现代 GPU 来说是小菜一碟。 Qt 是你的瓶颈。

【讨论】:

以上是关于基于 Q3DScatter 的自定义图表,QCustom3DItem 变慢的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Azure Devops 中添加我们自己的自定义图表

甜甜圈(仪表)的自定义背景限制

推动视图表的自定义 sql

图表上 y 轴的自定义数字格式

关于 Q3DScatter嵌套进设置了Qt::FramelessWindowHint(触摸自定义标题栏)时进行演示时出现渲染黑色区域 的解决方法

Google Colaboratory matplotlib 图表中的自定义字体