Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Qt3D not deleting Qt3DRender::QBuffer (screen goes to black)



  • Hello!

    I'm posting to act some questions about Qt3D.

    I'm trying to show some information for my program. This information consist
    on a regular grid (I'm painting the lines that define the voxels), a distance
    map (in each voxel vertex I store a distance value) and the sources for the
    distance (zones where distance is 0)

    The software supports resizing the grid or changing the sources so the views
    must be updated accordingly. To achieve that, I emit a signal when a change in
    the distance or the grid is done and connect that signal to a slot that
    performs the scene preparation. It isn't the best solution but for now is
    enough.

    The scene preparation slots cleans the previously allocated scene
    (m_rootEntity->deleteLater()) and reconstructs the scene.

    The reconstruction generates the geometry data for the different things I want
    to view, creates the renderer and the materials and adds this components to
    different entities. Finally, this entities are added to the root entity.

    To reduce code paths, the first view also performs this steps (removes the
    previously scene, which is null) and creates the new one. This works well.

    My problem is when trying to delete an existing scene. I have been debugging
    with gDEBugger and I have seen that buffers are not deleted (I imagine that VAO
    are also kept) though the buffers are constructed with the geometry as parent,
    and the geometry es an entity children (the entity is delete when I delete
    m_rootEntity).

    After 2 or 3 remeshing steps, the screen goes black and I cant see any
    information.

    I'm using the Qt3D version shipped with Qt 5.7.

    Any idea what I'm doing wrong? I can provide some code if you ask for it, but
    as the software I'm developing is big, I prefer to show the code when you ask
    for it, so I don't fill this question with a lot of code that wouldn't be
    necessary.

    Thanks!



  • Ive prepared a little example to show the problem I'm having. The buffer problem is not shown, but the screen going black is shown.

    SceneManager.h

    #ifndef SCENE_MANAGER
    #define SCENE_MANAGER
    
    #include <Qt3DCore>
    #include <Qt3DRender>
    #include <Qt3DExtras>
    
    class SceneManager : public QObject
    {
        Q_OBJECT
    public:
        explicit SceneManager(QObject *parent = nullptr);
    
    public slots:
        void changeScene();
    
        Qt3DRender::QGeometry *createGridGeometry();
    
    protected:
        Qt3DCore::QEntity *m_rootEntity;
        Qt3DCore::QEntity *m_gridViewer;
        Qt3DCore::QEntity *m_cellViewer;
    
        Qt3DExtras::Qt3DWindow *m_window;
    
        uint nbX;
        uint nbY;
    };
    
    
    #endif //SCENE_MANAGER
    

    SceneManager.cpp

    #include "SceneManager.h"
    #include <iostream>
    
    SceneManager::SceneManager(QObject *parent) :
        QObject(parent)
    {
        m_window = new Qt3DExtras::Qt3DWindow();
    
        QSurfaceFormat format;
        format.setMajorVersion( 4 );
        format.setMinorVersion( 5 );
        format.setProfile(QSurfaceFormat::CoreProfile);
        QSurfaceFormat::setDefaultFormat(format);
        m_window->setFormat(format);
        m_window->defaultFramegraph()->setClearColor(QColor(0,0,0));
    
    
        m_rootEntity = new Qt3DCore::QEntity();
        m_window->setRootEntity(m_rootEntity);
    
        nbX = 10;
        nbY = 10;
    
        changeScene();
    
        m_window->show();
    }
    
    void SceneManager::changeScene()
    {
        std::cout << "Change" << std::endl;
        nbX *= 2;
        nbY *= 2;
        m_rootEntity->deleteLater();
    
        m_rootEntity = new Qt3DCore::QEntity;
    
        m_window->setRootEntity(m_rootEntity);
    
        auto entity = new Qt3DCore::QEntity(m_rootEntity);
        auto geometry = createGridGeometry();
        auto renderer = new Qt3DRender::QGeometryRenderer(entity);
        renderer->setGeometry(geometry);
        geometry->setParent(entity);
        auto mat = new Qt3DExtras::QPerVertexColorMaterial(entity);
    
        entity->addComponent(renderer);
        entity->addComponent(mat);
    
        auto camera = m_window->camera();
        camera->setPosition(QVector3D(0,0,10));
        camera->setViewCenter(QVector3D(0,0,0));
        camera->setUpVector(QVector3D(0,1,0));
        camera->lens()->setOrthographicProjection(0, nbX,
                0,nbY, 0, 1000);
    }
    
    Qt3DRender::QGeometry *SceneManager::createGridGeometry()
    {
        Qt3DRender::QGeometry *geometry = new Qt3DRender::QGeometry;
    
        Qt3DRender::QAttribute *m_positionAttr = new Qt3DRender::QAttribute(geometry);
        Qt3DRender::QAttribute *m_colorAttr    = new Qt3DRender::QAttribute(geometry);
        Qt3DRender::QAttribute *m_indexAttr    = new Qt3DRender::QAttribute(geometry);
    
        Qt3DRender::QBuffer *m_positionBuffer = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::VertexBuffer, geometry);
        Qt3DRender::QBuffer *m_colorBuffer    = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::VertexBuffer, geometry);
        Qt3DRender::QBuffer *m_indexBuffer    = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::IndexBuffer , geometry);
    
        //Configure the attributes access
        m_positionAttr->setName(Qt3DRender::QAttribute::defaultPositionAttributeName());
        m_positionAttr->setDataType(Qt3DRender::QAttribute::Float);
        m_positionAttr->setDataSize(3);
        m_positionAttr->setAttributeType(Qt3DRender::QAttribute::VertexAttribute);
        m_positionAttr->setBuffer(m_positionBuffer);
        m_positionAttr->setCount(nbX*nbY);
    
    
        m_colorAttr->setName(Qt3DRender::QAttribute::defaultColorAttributeName());
        m_colorAttr->setDataType(Qt3DRender::QAttribute::Float);
        m_colorAttr->setDataSize(3);
        m_colorAttr->setAttributeType(Qt3DRender::QAttribute::VertexAttribute);
        m_colorAttr->setBuffer(m_colorBuffer);
        m_colorAttr->setCount(nbX*nbY);
    
    
        m_indexAttr->setAttributeType(Qt3DRender::QAttribute::IndexAttribute);
        m_indexAttr->setDataType(Qt3DRender::QAttribute::UnsignedInt);
        m_indexAttr->setBuffer(m_indexBuffer);
        m_indexAttr->setCount(2*3*(nbX-1)*(nbY-1));
    
        //Fill the buffers
        //Position data buffer
        QByteArray positionData;
        QByteArray colorData;
        positionData.resize(nbX*nbY*sizeof(QVector3D));
        colorData.resize(nbX*nbY*sizeof(QVector3D));
        QVector3D *v = reinterpret_cast<QVector3D*>(positionData.data());
        QVector3D *c = reinterpret_cast<QVector3D*>(colorData.data());
        for (uint i = 0; i < nbX; ++i)
        {
            for (uint j = 0; j < nbY; ++j)
            {
                v[j*nbX+i] = QVector3D(i,j,0);
                c[j*nbX+i] = QVector3D(1,0,0);
            }
        }
    
        m_positionBuffer->setData(positionData);
        m_colorBuffer->setData(colorData);
    
        QByteArray indexData;
        indexData.resize(2*3*(nbX-1)*(nbY-1)*sizeof(uint));
        uint *index = reinterpret_cast<uint*>(indexData.data());
        for (uint i = 0; i < nbX-1; ++i)
        {
            for (uint j = 0; j < nbY-1; ++j)
            {
                *index++ = j*nbX + i;
                *index++ = (j)*nbX + i+1;
                *index++ = (j+1)*nbX + i+1;
    
                *index++ = j*nbX + i;
                *index++ = (j+1)*nbX + i+1;
                *index++ = (j+1)*nbX + i;
            }
        }
    
        m_indexBuffer->setData(indexData);
    
        geometry->addAttribute(m_positionAttr);
        geometry->addAttribute(m_colorAttr);
        geometry->addAttribute(m_indexAttr);
    
        return geometry;
    }
    
    

    main.cpp

    #include <iostream>
    
    #include <Qt3DRender>
    #include <QApplication>
    #include <QTimer>
    
    #include "SceneManager.h"
    
    int main(int argc, char **argv)
    {
        QApplication app(argc, argv);
    
        SceneManager scene;
    
        QTimer t;
        QObject::connect(&t, SIGNAL(timeout()),
                         &scene, SLOT(changeScene()));
        t.setInterval(4000);
        t.start();
    
        return app.exec();
    }
    
    

    When the timer timeouts, triggers the changeScene slot, and after this slots, the screen goes black and I don't understand why...

    Any ideas?



  • Hi,
    can you try to run it without index attribute. I am not sure, of course, but having indices without texture seems unnecessary to me, as you have one color per vertex.
    On the other hand you did not define normals. Maybe the system computes its own normals which may point away from the camera. Then you would only see a black plane on a black background. So you can also use a gray background to test that this is not your problem.
    -Michael.



  • I dont really understand what you mean.

    The indices are there to define the different triangles in the mesh, it has nothing to do with textures (as far as I know).

    The material I'm using if QPerVertexColorMaterial. The fragment stage doesn't need normals, as it only set the fragment color to the rasterized vertex color (there is not lighting).

    Even more, the example first shows a red rectangle, which is correct, as I have set all the vertex to have a red color, but after the timer timeouts and recreates the scene, screen goes black.



  • Reading the Qt3D source I have found that the root entity is only set before the windows is exposed. If I try to change it after the expose event, it has no effect. As I'm destroying the previous root and no other one is taking its place, the screen goes black.


  • Qt Champions 2017

    Hi,
    As Sean said in the mailing list, you should file a bug report here (that's what "file a JIRA" means, it's slang term because they use JIRA to track the bugs). You can log into the bug tracker with your forum username and password.

    Kind regards.


Log in to reply