5
votes

It seems to me that Qt3D cannot render 2D meshes well. To see what I mean open the shadow map QML example and change the camera controller from FirstPersonCameraController to OrbitCameraController. Run the program and attempt to view the ground plane from below, you will see it disappear. So QT3D just renders 2D meshes from one side and makes them transparent from the other side.

How can I fix this? i.e. render 2D meshes from both sides?

EDIT: Now I know that I have to disable culling for the rendering to work. I came up to this point:

//'this' refers to Qt3DWindow
rootEntity->addComponent(this->renderSettings());
QCullFace *face = new QCullFace();
QRenderStateSet *stateSet = new QRenderStateSet(this->renderSettings()->activeFrameGraph());
QRenderSurfaceSelector *selector = new QRenderSurfaceSelector(this->renderSettings());
face->setMode(QCullFace::NoCulling);
stateSet->addRenderState(face);
selector->setSurface(this);

but this still doesn't seem to change anything. Am I missing something?

1
This sound like culling. I've not used Qt3D but look if there's a way to disable culling for that mesh and try to see if that fixes it. en.wikipedia.org/wiki/Back-face_cullingBanex
Or create your own QGeometry and add faces for the backside, as well. Shouldn't be too difficult for a plane mesh I guess (or of course create a second plane mesh and flip it). This could be more appropriate because if you disable back-face culling it will get disabled for the whole scene.Florian Blume
@FlorianBlume I just used the plane mesh to explain the issue (I didn't know the technical terms), but I am inserting a complex object with some 2D mesh parts, so doing it manually would be nearly impossible. What would be the problem if culling is disabled for the whole scene? and can you tell me how it is done?Mariam
and thanks @Banex for your suggestion! It definitely gave me some direction in my thinking process.Mariam
@Mariam Culling is an optimization that avoids the need for the GPU to draw things that are not going to be in the scene. If your scene is not complex, I don't think disabling culling would incur a heavy performance penalty.Banex

1 Answers

8
votes

Here is a minimally working example:

main.cpp:

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

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    GraphicsWindow graphicsWindow;
    graphicsWindow.show();
    return a.exec();
}

graphicswindow.h:

#include <Qt3DExtras/Qt3DWindow>
#include <Qt3DCore/QEntity>
#include <Qt3DCore/QTransform>

class GraphicsWindow : public Qt3DExtras::Qt3DWindow {
public:
    GraphicsWindow();
    void wheelEvent ( QWheelEvent * event ) override;

private:
    Qt3DCore::QEntity *createScene();
    Qt3DCore::QTransform *planeTransform;
};

graphicswindow.cpp:

#include "graphicswindow.h"
#include <QMouseEvent>
#include <Qt3DRender/QViewport>
#include <Qt3DRender/QClearBuffers>
#include <Qt3DRender/QRenderSurfaceSelector>
#include <Qt3DRender/QRenderStateSet>
#include <Qt3DRender/QCullFace>
#include <Qt3DRender/QCameraSelector>
#include <Qt3DRender/QCamera>
#include <Qt3DRender/QMaterial>
#include <Qt3DExtras/QGoochMaterial>
#include <Qt3DExtras/QPlaneMesh>
#include <Qt3DRender/QDepthTest>

GraphicsWindow::GraphicsWindow() : Qt3DExtras::Qt3DWindow() {
    Qt3DRender::QCamera *camera = this->camera();
    camera->lens()->setPerspectiveProjection(45.0f, 16.0f/9.0f, 0.1f, 1000.0f);
    camera->setPosition(QVector3D(20.0, 20.0, 20.0f));
    camera->setViewCenter(QVector3D(0, 0, 0));

    Qt3DRender::QRenderSurfaceSelector *surfaceSelector = new Qt3DRender::QRenderSurfaceSelector;
    surfaceSelector->setSurface(this);
    Qt3DRender::QViewport *viewport = new Qt3DRender::QViewport(surfaceSelector);
    viewport->setNormalizedRect(QRectF(0, 0, 1.0, 1.0));
    Qt3DRender::QCameraSelector *cameraSelector = new Qt3DRender::QCameraSelector(viewport);
    cameraSelector->setCamera(camera);
    Qt3DRender::QClearBuffers *clearBuffers = new Qt3DRender::QClearBuffers(cameraSelector);
    clearBuffers->setBuffers(Qt3DRender::QClearBuffers::ColorDepthBuffer);
    clearBuffers->setClearColor(Qt::white);
    Qt3DRender::QRenderStateSet *renderStateSet = new Qt3DRender::QRenderStateSet(clearBuffers);
    Qt3DRender::QCullFace *cullFace = new Qt3DRender::QCullFace(renderStateSet);
    cullFace->setMode(Qt3DRender::QCullFace::NoCulling);
    renderStateSet->addRenderState(cullFace);
    Qt3DRender::QDepthTest *depthTest = new Qt3DRender::QDepthTest;
    depthTest->setDepthFunction(Qt3DRender::QDepthTest::Less);
    renderStateSet->addRenderState(depthTest);
    setActiveFrameGraph(surfaceSelector);

    Qt3DCore::QEntity *root = createScene();
    setRootEntity(root);
}

void GraphicsWindow::wheelEvent(QWheelEvent *event) {
    planeTransform->setRotationZ(planeTransform->rotationZ() + event->delta() / 40.f);
}


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

    Qt3DCore::QEntity *planeEntity = new Qt3DCore::QEntity(rootEntity);
    Qt3DRender::QMaterial *meshMaterial = new Qt3DExtras::QGoochMaterial;
    Qt3DExtras::QPlaneMesh *planeMesh = new Qt3DExtras::QPlaneMesh;
    planeMesh->setHeight(10);
    planeMesh->setWidth(10);
    planeTransform = new Qt3DCore::QTransform;

    planeEntity->addComponent(planeTransform);
    planeEntity->addComponent(planeMesh);
    planeEntity->addComponent(meshMaterial);

    return rootEntity;
}

Keep in mind that the setActiveFramegraph function of the Qt3DWindow automatically adds the QRenderSettings returned by the renderSettings() function of the window on the frame graph node that you set as the active frame graph. If you are implementing your own 3D window or create and offscreen renderer you have to use QRenderSettings as the root node of your framegraph (the window sets its render settings as the parent of the root frame graph node that you set) and add the render settings to the actual root node, i.e. the node that is the parent of the frame graph and the scene graph.