Problem creating multiple viewports in Qt3D using C++
Asked Answered
S

1

1

I am trying to setup a Qt3DWindow with multiple viewports using C++. According to the documentation and the provided QML example, all I need to do is create a framegraph, where a main QViewport object branches into several RenderViews. The first RenderView contains a QClearBuffers object, and the remaining ones contain the tiled viewports and their corresponding camera selectors. Therefore, if I want N viewports, I need to create N+1 RenderViews.

However, if I follow that procedure, the main viewport displays some sort of "default" view, which appears on top of the window, spanning all the viewports. I don't know where this view comes from, since it doesn't correspond to any camera. Here is the output from the code posted below.

I found a solution, but I am not comfortable with it since it feels like some kind of hack: instead of making all the RenderViews branch from the main viewport, I attach one of the child viewports to the ClearBuffers object itself. Thus, for N viewports, I have N RenderViews instead of N+1. I don't quite understand the internals of the framegraph, so I would like to know if this solution is only wrong from an OCD perspective, or it can actually backfire at some point.

Here is a minimal example with two viewports sharing the default camera. If I make either viewPort1 or viewPort2 branch from clearBuffers instead of mainViewPort, everything works as expected:

#include <QGuiApplication>

#include <Qt3DCore/QTransform>

#include <Qt3DExtras/Qt3DWindow>
#include <Qt3DExtras/QTorusMesh>
#include <Qt3DExtras/QPhongMaterial>

#include <Qt3DRender/QCamera>
#include <Qt3DRender/QRenderSurfaceSelector>
#include <Qt3DRender/QViewport>
#include <Qt3DRender/QClearBuffers>
#include <Qt3DRender/QCameraSelector>

Qt3DCore::QEntity *createScene()
{
    // Root entity
    auto rootEntity = new Qt3DCore::QEntity;

    // Torus
    auto torusEntity = new Qt3DCore::QEntity(rootEntity);

    auto torusMesh = new Qt3DExtras::QTorusMesh;
    torusMesh->setRadius(0.5f);
    torusMesh->setMinorRadius(0.1f);
    torusMesh->setRings(100);
    torusMesh->setSlices(20);

    auto torusTransform = new Qt3DCore::QTransform;
    torusTransform->setScale3D(QVector3D(1.2f, 1.f, 0.8f));
    torusTransform->setRotation(QQuaternion::fromAxisAndAngle(QVector3D(1, 0, 0), 45.0f));

    torusEntity->addComponent(torusMesh);
    torusEntity->addComponent(torusTransform);
    torusEntity->addComponent(new Qt3DExtras::QPhongMaterial(rootEntity));

    return rootEntity;
}

int main(int argc, char* argv[])
{
    QGuiApplication app(argc, argv);
    Qt3DExtras::Qt3DWindow view;

    // Set camera transform
    view.camera()->setPosition(QVector3D(0, 4.0f, 0));
    view.camera()->setViewCenter(QVector3D(0, 0, 0));

    // Framegraph root node
    auto surfaceSelector = new Qt3DRender::QRenderSurfaceSelector();
    auto mainViewPort = new Qt3DRender::QViewport(surfaceSelector);

    // First RenderView: clear buffers
    auto clearBuffers = new Qt3DRender::QClearBuffers(mainViewPort);
    clearBuffers->setBuffers(Qt3DRender::QClearBuffers::ColorDepthBuffer);
    clearBuffers->setClearColor(Qt::white);

    // Second RenderView: left viewport
    auto viewPort1 = new Qt3DRender::QViewport(mainViewPort);
    viewPort1->setNormalizedRect(QRectF(0.0f, 0.0f, 0.5f, 1.0f));
    auto cameraSelector1 = new Qt3DRender::QCameraSelector(viewPort1);
    cameraSelector1->setCamera(view.camera());

    // Third RenderView: right viewport
    auto viewPort2 = new Qt3DRender::QViewport(mainViewPort);
    viewPort2->setNormalizedRect(QRectF(0.5f, 0.0f, 0.5f, 1.0f));
    auto cameraSelector2= new Qt3DRender::QCameraSelector(viewPort2);
    cameraSelector2->setCamera(view.camera());

    // Add framegraph and scenegraph to viewer
    view.setActiveFrameGraph(surfaceSelector);
    view.setRootEntity(createScene());

    view.show();

    return app.exec();
}

Solecism answered 6/7, 2020 at 10:23 Comment(0)
N
2

I still think it's kind of a bug that it draws ontop of the viewports but you can put a QNoDraw node in your framegraph as a child of the QClearBuffers:

auto noDraw = new Qt3DRender::QNoDraw(clearBuffers);

That solves the rendering issue.

Nedry answered 8/7, 2020 at 15:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.