2D meshes in QT3D
Asked Answered
T

1

5

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?

Tews answered 13/8, 2018 at 8:55 Comment(19)
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_cullingInstancy
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.Velocipede
@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?Tews
and thanks @Instancy for your suggestion! It definitely gave me some direction in my thinking process.Tews
@Tews 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.Instancy
@Instancy I see! Then I'll try to find a way to disable it in Qt3D.Tews
Back face culling might be enabled by default assuming that the general use case is solid objects which can be only seen from outside. So, the optimization makes sense. If your use case is different (e.g. you want to render sheet metal) it's reasonable to disable back-face culling for those meshes. IMHO, rendering doesn't become faster with duplicated geometry for front and back side but this may even depend on H/W.Cowrie
Thank you guys for the useful information! I updated my question.Tews
Well, now you get to the tricky (and especially not well documented) part of Qt3D. You have to make this part of your framegraph. You can either do this by adding a QRenderStateSet, which you have to add the QCullFace to (in this case, omit the QRenderPass). But then you have to add a QRenderSurfaceSelector that has the Qt3DWindow (that I assume you're using) set as the surface. You have to make the surface selector a child of the QRenderSettings of the Qt3DWindow. The render settings also have to be set as a componen on the root node.Velocipede
If you don't want to do it via a render state set, you can create a custom material with a QTechnique and add your render pass to it. I think it would be best to have a look at this repository: github.com/alpqr/q3dpostprocVelocipede
Or have a look at my Qt3D offscreen renderer repository (which has cost me more than a nerve to create): github.com/Sonnentierchen/Qt3D-OffscreenRenderer. If you look at the OffscreenSurfaceFramegraph class you could add a QRenderState set with your culling as a child of the camera selector. This is where it would belong. Then you could "reverse engineer" where to add the cull face in your case.Velocipede
@FlorianBlume thank you for your suggestions. It's all quite new to me, so I'm trying my best to follow. I'm trying to implement the first suggestion (after failing to create a custom material) and the only missing point is how to link the QRenderStateSet to the rest?Tews
Do you have a Qt3DWindow? If so, the QRenderStateSet has to be a child of the node returned by window->renderSettings()->activeFramegraph(). This should actually be enough, to make it part of the framegraph that the window uses to render entities.Velocipede
@FlorianBlume I updated my question with the code snippet. Everything still looks the same with these changes.Tews
I think you don't need to have the render surface selector there, as the default framegraph of the window has one already. Sorry, that was my mistake.Velocipede
@FlorianBlume it still did not change the rendering..Tews
Maybe this can helpl you. Apparently I was wrong again, and you have to add the render state set to the last node of the active framegraph, which is the clear buffers of the forward renderer used by the 3D window.Velocipede
In the QML version this worked for me: RenderStateSet { renderStates: [CullFace { mode: CullFace.NoCulling }] } after the CameraSelector in the forward pass of the shadow map frame graph. So if you're doing this in C++, use the camera selector as the parent for the render state set and construct the rest in the way I posted in this comment.Velocipede
Unfortunately, until now I haven't been successful.. I have tried reproducing the code in the thread you posted as it is. and then I modified it to add the QRenderStateSet directly to the camera selector, but unitl now all my trials did not produce any different results.. @FlorianBlumeTews
V
8

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.

Velocipede answered 14/8, 2018 at 10:59 Comment(5)
Thank you so much for your answer! It definitely answers the question and works on the 2D plane! However, disabling culling somehow messes up the 3D objects :/ If you insert a 3D sphere mesh in the scene, the renderer shows black stripes on it from some angles.. and with more complex meshes some parts become transparent and things like that. It is very weird.. maybe I need to think of something else to display both 2D and 3D.Tews
You have to add a depth test, as it is not part of the framegraph, yet. I edited my answer.Velocipede
You are the best!! Thanks a lot for your time and patience with me!Tews
You're welcome :) I had so many troubles working with this framework, that's why I'm always happy to help others.Velocipede
This is great spirit! I definitely still have a lot to learn.Tews

© 2022 - 2024 — McMap. All rights reserved.