Irrlicht in Qt5 is very slow

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
Post Reply
Necris
Posts: 8
Joined: Tue Sep 17, 2013 4:31 pm

Irrlicht in Qt5 is very slow

Post by Necris »

A couple of years ago I started a Irrlicht project, but as it came to GUI I lost my interest in it. Now I have learned a bit Qt and wanted to revive my old project with a nice Qt GUI. I started to port everything, but I have now the big problem, that it is horribly slow. Before, I got like 100Fps and now I am lucky if I get 20Fps. I created 2500 cubes, which was no big deal for pure Irrlicht, but it is when it is embedded into a Qt window.

I have created a Testproject, with Qt5.4 where this is shown. It is based on the code of Egon Rath: http://www.matrix44.net/blog/?p=389
In this Example, I get 36 Fps, but if I add a texture to the cubes, the framerate drops by 10Fps. Adding one or two more different models, will drop the Framerate again.

main.cpp

Code: Select all

 
#include "testobjects.h"
#include <QtWidgets/QApplication>
 
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    TestObjects w;
    w.show();
    return a.exec();
}
 
testobjects.h

Code: Select all

 
#pragma once
 
#include <QtWidgets/QMainWindow>
#include <QtCore/QTimer>
#include <irrlicht.h>
 
using namespace irr;
using namespace irr::video;
using namespace irr::core;
using namespace irr::scene;
 
class TestObjects : public QMainWindow
{
    Q_OBJECT
 
public:
    TestObjects(QWidget *parent = 0);
    ~TestObjects();
    virtual void paintEvent(QPaintEvent *event);
    virtual void resizeEvent(QResizeEvent *event);
    virtual QPaintEngine * paintEngine() const;
 
    public slots:
    void onUpdateTimerTimeout();
 
private:
    IrrlichtDevice *m_Device;
    ISceneManager *m_Scene;
    IVideoDriver *m_Driver;
    QTimer* mpUpdateTimer;
 
    void createIrrlichtDevice();
    void buildIrrlichtScene();
    void drawIrrlichtScene();
};
 
testobjects.cpp

Code: Select all

 
#include "testobjects.h"
#include <QPushButton>
#include <QDebug>
 
TestObjects::TestObjects(QWidget *parent)
    : QMainWindow(parent)
    , m_Device(nullptr)
    , m_Scene(nullptr)
    , m_Driver(nullptr)
    , mpUpdateTimer(new QTimer(this))
{
    this->resize(640, 480);
    this->setAttribute(Qt::WA_PaintOnScreen, true);
 
    connect(mpUpdateTimer, SIGNAL(timeout()), this, SLOT(onUpdateTimerTimeout()));
 
    createIrrlichtDevice();
}
 
TestObjects::~TestObjects()
{
 
}
 
void TestObjects::createIrrlichtDevice()
{
    dimension2d<u32> windowSize(this->geometry().width(), this->geometry().height());
 
    qDebug() << "MainWindow::createIrrlichtDevice, width = " << windowSize.Width << " height = " << windowSize.Height;
 
    SIrrlichtCreationParameters createParams;
    createParams.WindowId = (void *) this->winId();
 
    m_Device = createDeviceEx(createParams);
    if (m_Device == 0)
        qDebug() << "failed to create irrlicht device";
 
    m_Driver = m_Device->getVideoDriver();
    m_Scene = m_Device->getSceneManager();
 
    buildIrrlichtScene();
}
 
void TestObjects::buildIrrlichtScene()
{
    irr::scene::ICameraSceneNode* cam = m_Scene->addCameraSceneNode(0, vector3df(26.001, 20, 25), vector3df(25, 0, 25));
 
    irr::scene::IMetaTriangleSelector* metaSelector = m_Device->getSceneManager()->createMetaTriangleSelector();
 
 
    for (irr::f32 x = 0; x <= 49; x++){
        for (irr::f32 z = 0; z <= 49; z++){
            irr::scene::IMeshSceneNode* node = m_Device->getSceneManager()->addCubeSceneNode(1, 0, -1, irr::core::vector3df(x, 0, z), core::vector3df(0, 0, 0), core::vector3df(1, 1, 1));
            //node->setMaterialTexture(0, m_Driver->getTexture("models/white.png"));        
            //node->setMaterialFlag(video::EMF_LIGHTING, false);
            //node->setMaterialFlag(video::EMF_BACK_FACE_CULLING, false);
            node->setMaterialFlag(video::EMF_FRONT_FACE_CULLING, false);
        }
    }
    //irr::scene::IMeshSceneNode* node = m_Device->getSceneManager()->addCubeSceneNode(1, 0, -1, irr::core::vector3df(26, 0, 26), core::vector3df(0, 0, 0), core::vector3df(1, 1, 1));
    ILightSceneNode *light = m_Scene->addLightSceneNode();
    light->setLightType(ELT_DIRECTIONAL);
    light->setRotation(vector3df(45.0f, 45.0f, 0.0f));
    light->getLightData().AmbientColor = SColorf(0.2f, 0.2f, 0.2f, 1.0f);
    light->getLightData().DiffuseColor = SColorf(0.8f, 0.8f, 0.8f, 1.0f);
 
    mpUpdateTimer->setInterval(1);
    mpUpdateTimer->start();
}
 
void TestObjects::paintEvent(QPaintEvent *event)
{
    qDebug() << "MainWindow::paintEvent()";
 
    drawIrrlichtScene();
}
 
void TestObjects::resizeEvent(QResizeEvent *event)
{
    qDebug() << "MainWindow::resizeEvent()";
}
 
QPaintEngine * TestObjects::paintEngine() const
{
    qDebug() << "MainWindow::paintEngine()";
 
    return 0;
}
 
void TestObjects::drawIrrlichtScene()
{
    //qDebug() << "MainWindow::drawIrrlichtScene()";
 
    if (m_Device && m_Scene && m_Device)
    {
        m_Driver->beginScene(true, false, SColor(255, 128, 128, 128));
        m_Scene->drawAll();
        m_Driver->endScene();
    
        core::stringw caption = L"";
        caption += " FPS:";
        caption += m_Driver->getFPS();
        m_Device->setWindowCaption(caption.c_str());
    }
}
  
void TestObjects::onUpdateTimerTimeout()
{
    drawIrrlichtScene();
}
 
Has someone faced a similar problem? Does somenone know why this happens? This amount of objects was no big deal without Qt, why is it now?
Escen
Competition winner
Posts: 167
Joined: Sun Jul 19, 2009 11:27 am
Location: the Netherlands
Contact:

Re: Irrlicht in Qt5 is very slow

Post by Escen »

Did you try other para settings?

params.DriverType = irr::video::EDT_OPENGL;
params.DeviceType =EIDT_WIN32;
params.WindowId = (HWND)this->winId();
params.WindowSize = core::dimension2d<u32>(1920, 1080);
params.Vsync=false;
params.AntiAlias=8;
params.HandleSRGB=true;
params.ZBufferBits=24;

setAttribute(Qt::WA_StaticContents);
setAttribute(Qt::WA_OpaquePaintEvent);
Necris
Posts: 8
Joined: Tue Sep 17, 2013 4:31 pm

Re: Irrlicht in Qt5 is very slow

Post by Necris »

Thanks for your response.
The driver seems the be the cause. But unfortunately I get a grey screen, when I change it to OpenGL or Direct3d9.
Did i forget something?

EDIT: I know where the grey is coming from. It comes from the beginScene(). But why is the driver not drawing my objects?
Escen
Competition winner
Posts: 167
Joined: Sun Jul 19, 2009 11:27 am
Location: the Netherlands
Contact:

Re: Irrlicht in Qt5 is very slow

Post by Escen »

Your were close... Z-Buffer should be cleared:

m_Driver->beginScene(true, true, SColor(255, 128, 128, 128));
Necris
Posts: 8
Joined: Tue Sep 17, 2013 4:31 pm

Re: Irrlicht in Qt5 is very slow

Post by Necris »

Thank you, that solved it.
Necris
Posts: 8
Joined: Tue Sep 17, 2013 4:31 pm

Re: Irrlicht in Qt5 is very slow

Post by Necris »

It turns out, that there is another problem hiding here. I dont know if this should be in a new thread.
If I use now an ui file, with GUI elements in it, the elements are all in the background, behind the irrlicht scene. How can I move the UI to the foreground?
There is also a strange behaviour, when I insert a button the constructor function, like in the original example:

Code: Select all

 
QPushButton *button = new QPushButton(this);
button->setText("Quit!");
button->move(20, 20);
connect(button, SIGNAL(clicked()), this, SLOT(quit()));
 
Now there is a hole in the window.
Escen
Competition winner
Posts: 167
Joined: Sun Jul 19, 2009 11:27 am
Location: the Netherlands
Contact:

Re: Irrlicht in Qt5 is very slow

Post by Escen »

It's better to move your irrlicht stuff into a separated QWidget class. Then it can be treated as an ordinary widget, avoiding paint issues etc.
Made some modifications based on your above code, this should work better.
Added a 'resizeEvent' function as an extra bonus.

irrlichtView.h:

Code: Select all

#ifndef IRRLICHTVIEW_H
#define IRRLICHTVIEW_H
 
#include <QtWidgets/QWidget>
#include <QtGui/QResizeEvent>
#include <irrlicht.h>
 
using namespace irr;
using namespace irr::video;
using namespace irr::core;
using namespace irr::scene;
 
 
class irrlichtView: public QWidget
{
  Q_OBJECT
    public:
        irrlichtView(QWidget *parent = 0);
        void drawIrrlichtScene();
        virtual ~irrlichtView();
    protected:
        virtual void paintEvent(QPaintEvent *event);
        virtual void resizeEvent(QResizeEvent *event);
 
    private:
        IrrlichtDevice *m_Device;
        ISceneManager *m_Scene;
        IVideoDriver *m_Driver;};
 
#endif // IRRLICHTVIEW_H

irrlichtView.cpp:

Code: Select all

#include "irrlichtView.h"
 
 
irrlichtView::irrlichtView(QWidget *parent): QWidget(parent)
{
 
    SIrrlichtCreationParameters createParams;
    createParams.WindowId = (void *) this->winId();
    createParams.DriverType = irr::video::EDT_OPENGL;
    createParams.DeviceType =EIDT_WIN32;
    createParams.WindowSize = core::dimension2d<u32>(640, 480);
    createParams.Vsync=false;
    createParams.AntiAlias=8;
    createParams.HandleSRGB=true;
    createParams.ZBufferBits=24;
 
    m_Device = createDeviceEx(createParams);
    m_Driver = m_Device->getVideoDriver();
    m_Scene = m_Device->getSceneManager();
 
    irr::scene::ICameraSceneNode* cam = m_Scene->addCameraSceneNode(0, vector3df(26, 15, 25), vector3df(25, 0, 25));
    irr::scene::IMetaTriangleSelector* metaSelector = m_Device->getSceneManager()->createMetaTriangleSelector();
 
 
    for (irr::f32 x = 0; x <= 49; x++){
        for (irr::f32 z = 0; z <= 49; z++){
            irr::scene::IMeshSceneNode* node = m_Device->getSceneManager()->addCubeSceneNode(1, 0, -1, irr::core::vector3df(x, 0, z), core::vector3df(0, 0, 0), core::vector3df(1, 1, 1));
            node->setMaterialTexture(0, m_Driver->getTexture("Models/automaat4F.jpg"));
            node->setMaterialFlag(video::EMF_LIGHTING, false);
            node->setMaterialFlag(video::EMF_BACK_FACE_CULLING, false);
            node->setMaterialFlag(video::EMF_FRONT_FACE_CULLING, false);
        }
    }
 
    ILightSceneNode *light = m_Scene->addLightSceneNode();
    light->setLightType(ELT_DIRECTIONAL);
    light->setRotation(vector3df(45.0f, 45.0f, 0.0f));
    light->getLightData().AmbientColor = SColorf(0.2f, 0.2f, 0.2f, 1.0f);
    light->getLightData().DiffuseColor = SColorf(0.8f, 0.8f, 0.8f, 1.0f);
 
}
 
irrlichtView::~irrlichtView()
{
    //dtor
}
void irrlichtView::drawIrrlichtScene()
{
    if (m_Device && m_Scene && m_Device)
    {
        m_Driver->beginScene(true, true, SColor(255, 128, 128, 128));
        m_Scene->drawAll();
        m_Driver->endScene();
 
        core::stringw caption = L"";
        caption += " FPS:";
        caption += m_Driver->getFPS();
        m_Device->setWindowCaption(caption.c_str());
    }
 
}
void irrlichtView::paintEvent(QPaintEvent *event)
{
 
     QWidget::paintEvent(event);
}
 
void irrlichtView::resizeEvent(QResizeEvent *event)
{
    if ( m_Device != 0)
    {
        irr::core::dimension2d<u32> size;
        size.Width = event->size().width();
        size.Height = event->size().height();
        m_Device->getVideoDriver()->OnResize( size );
    }
    QWidget::resizeEvent(event);
}
 
testobjects.h

Code: Select all

#pragma once
 
#include <QtWidgets/QMainWindow>
#include <QtCore/QTimer>
#include <QtWidgets/QGridLayout>
#include <QPushButton>
#include <irrlicht.h>
#include "irrlichtView.h"
 
using namespace irr;
using namespace irr::video;
using namespace irr::core;
using namespace irr::scene;
 
class TestObjects : public QMainWindow
{
    Q_OBJECT
 
public:
    TestObjects(QWidget *parent = 0);
    ~TestObjects();
    virtual void paintEvent(QPaintEvent *event);
    virtual void resizeEvent(QResizeEvent *event);
    virtual QPaintEngine * paintEngine() const;
 
    public slots:
        void onUpdateTimerTimeout();
private:
        QTimer* mpUpdateTimer;
 
        void drawIrrlichtScene();
 
        irrlichtView* m_IrrDisplay;
};
testobjects.cpp

Code: Select all

#include "testobjects.h"
 
TestObjects::TestObjects(QWidget *parent) : QMainWindow(parent)
    , mpUpdateTimer(new QTimer(this))
{
    this->resize(640, 480);
    this->setAttribute(Qt::WA_PaintOnScreen, false);
 
    dimension2d<u32> windowSize(this->geometry().width(), this->geometry().height());
 
    connect(mpUpdateTimer, SIGNAL(timeout()), this, SLOT(onUpdateTimerTimeout()));
 
    mpUpdateTimer->setInterval(1);
    mpUpdateTimer->start();
 
    QWidget *centralwidget;
    QGridLayout *gridLayout_2;
    QGridLayout *gridLayout;
 
        centralwidget = new QWidget(this);
        centralwidget->setObjectName(QStringLiteral("centralwidget"));
        gridLayout_2 = new QGridLayout(centralwidget);
        gridLayout_2->setObjectName(QStringLiteral("gridLayout_2"));
        gridLayout = new QGridLayout();
        gridLayout->setObjectName(QStringLiteral("gridLayout"));
 
        gridLayout_2->addLayout(gridLayout, 0, 0, 1, 1);
        this->setCentralWidget(centralwidget);
 
        QPushButton *button = new QPushButton(centralwidget);
        button->setText("Quit!");
        button->setGeometry(QRect(220, 158, 75, 23));
 
        m_IrrDisplay =new irrlichtView(this);
        gridLayout->addWidget(m_IrrDisplay,0,0);
 
        QObject::connect(button, SIGNAL(clicked()), this, SLOT(close()));
        QMetaObject::connectSlotsByName(this);
}
 
TestObjects::~TestObjects()
{
 
}
 
void TestObjects::paintEvent(QPaintEvent *event)
{
 
     QWidget::paintEvent(event);
}
 
void TestObjects::resizeEvent(QResizeEvent *event)
{
 
    QWidget::resizeEvent(event);
}
 
QPaintEngine * TestObjects::paintEngine() const
{
    return 0;
}
 
void TestObjects::drawIrrlichtScene()
{
 
    m_IrrDisplay->drawIrrlichtScene();
 
}
 
void TestObjects::onUpdateTimerTimeout()
{
    drawIrrlichtScene();
}
 
Necris
Posts: 8
Joined: Tue Sep 17, 2013 4:31 pm

Re: Irrlicht in Qt5 is very slow

Post by Necris »

Thank you very much again for your solution and your time.
Are the window captions working for you, if you post them from irrlicht? I guess they wont work, since irrlicht isn´t using the whole window.
As a workaround I have put this into the drawIrrlichtScene method of the testobjects.cpp, after adding a method to irrlichtView, for getting the FPS:

Code: Select all

 
QString caption = " FPS:";
caption += QString::number(m_IrrDisplay->getFPS());
this->setWindowTitle(caption);
 


And just for understanding, why are two stacked gridLayouts needed? When I try it with one gridLayout, it still works, or am I missing a disadvantage here?
Escen
Competition winner
Posts: 167
Joined: Sun Jul 19, 2009 11:27 am
Location: the Netherlands
Contact:

Re: Irrlicht in Qt5 is very slow

Post by Escen »

Are the window captions working for you
I didn't give any attention...nice workaround.
why are two stacked gridLayouts needed?
Only needed if you want to insert more widgets and spanning multiple rows/columns [addLayout(gridLayout, 0, 0, 1, 1)]... just preparing.
Basically there's no need in this example.
Necris
Posts: 8
Joined: Tue Sep 17, 2013 4:31 pm

Re: Irrlicht in Qt5 is very slow

Post by Necris »

Ah Ok. One (hopefully) last question:
Now there is a grey border around the widget inside the window, even on fullscreen. How is it possible to remove this thing and have a fullsized rendering view?
Escen
Competition winner
Posts: 167
Joined: Sun Jul 19, 2009 11:27 am
Location: the Netherlands
Contact:

Re: Irrlicht in Qt5 is very slow

Post by Escen »

gridLayout->setContentsMargins (0,0,0,0);

And all other you can found here:
http://qt.apidoc.info/5.1.1/qtdoc-online/classes.html
Necris
Posts: 8
Joined: Tue Sep 17, 2013 4:31 pm

Re: Irrlicht in Qt5 is very slow

Post by Necris »

Oh sorry, at this question I really forgot looking into the documentation. Thank you for it.

Just for others, who will come over this thread: The resize method is nearly perfect, but the view looked a bit weired after a fresh start. It was stretched a little, because the camera was not adjusted to the new resolution.
Add this to the resizeEvent of irrlichtView.cpp, after resizing the videoDriver

Code: Select all

 
irr::scene::ICameraSceneNode* camera = mpDevice->getSceneManager()->getActiveCamera();
if (camera)
{
    camera->setAspectRatio((float)size.Width / size.Height);
}
 
Post Reply