Search code examples
c++qt3dqt3dqt5.12

Disable all light sources in Qt 3d


In my company there is a shift from an old 3D engine to Qt3d. One goal of this undertaking is to compare the rendered view of the old 3D engine with the Qt3d rendering.

For this I wrote a small example application, where I can compare old and new rendering. There are still plenty differences. My first idea was to switch of all light sources in both engines and compare the silhouettes of both renderings.

Now, there is some thing, that I really don't understand and this has to do with the Qt3d lighting model.

In my small example app I define a simple sphere mesh and a camera and a check box, which can disable a point light source. The sphere is lighted by the phong reflection model.

No, if I switch out mylight, I'm expecting a simple black sphere in my viewer, as there is really no light. Instead there is still some lighting (from a different source). I think, that there is some other light source, that is activated by default.

How, can I disable all light sources in Qt3d? As a side question I'm also wondering why meshMaterial->setAmbient(QColor(255, 0, 0)); has no visible effect on the material after all. It really doesn't matter what you will enter here.

#include <QApplication>
#include <QWidget>
#include <QCheckBox>
#include <QVBoxLayout>
#include <QFrame>
#include <Qt3DCore/QTransform.h>
#include <Qt3DRender/QCamera.h>
#include <Qt3DRender/QRenderSettings.h>
#include <Qt3DRender/QPointLight.h>
#include <Qt3DExtras/QSphereMesh>
#include <Qt3DExtras/QPhongMaterial>
#include <Qt3DExtras/qforwardrenderer.h>
#include <Qt3DExtras/Qt3DWindow.h>
#include <Qt3DExtras/QFirstPersonCameraController.h>

int main(int argc, char* argv[])
{
    QApplication a(argc, argv);

    auto view = new Qt3DExtras::Qt3DWindow();
    view->defaultFrameGraph()->setClearColor(QColor(255,255,255));

    auto rootEntity = new Qt3DCore::QEntity();
    view->setRootEntity(rootEntity);

    auto cameraEntity = view->camera();
    cameraEntity->lens()->setPerspectiveProjection(45.0f, 1., 0.1f, 10000.0f);
    cameraEntity->setPosition(QVector3D(5, 5, 5));
    cameraEntity->setUpVector(QVector3D(0, 1, 0));
    cameraEntity->setViewCenter(QVector3D(0, 0, 0));

    auto lightEntity = new Qt3DCore::QEntity(rootEntity);

    auto light = new Qt3DRender::QPointLight(lightEntity);
    light->setColor("white");
    light->setIntensity(1);
    lightEntity->addComponent(light);

    auto lightTransform = new Qt3DCore::QTransform(lightEntity);
    lightTransform->setTranslation(cameraEntity->position());
    lightEntity->addComponent(lightTransform);

    lightEntity->setEnabled(false);

    // For camera controls
    auto camController = new Qt3DExtras::QFirstPersonCameraController(rootEntity);
    camController->setCamera(cameraEntity);

    auto mesh = new Qt3DExtras::QSphereMesh();
    mesh->setRadius(1.);

    auto meshMaterial = new Qt3DExtras::QPhongMaterial();
    meshMaterial->setDiffuse(QColor(0, 255, 0));
    meshMaterial->setAmbient(QColor(255, 0, 0));
    meshMaterial->setSpecular(QColor(0,0,255));
    meshMaterial->setShininess(23);

    auto meshEntity = new Qt3DCore::QEntity(rootEntity);
    meshEntity->addComponent(mesh);
    meshEntity->addComponent(meshMaterial);
    meshEntity->setEnabled(true);

    auto disableLight = new QCheckBox();
    auto container = QWidget::createWindowContainer(view);
    QFrame frame;
    frame.setLayout(new QVBoxLayout);
    frame.layout()->addWidget(container);
    frame.layout()->addWidget(disableLight);
    QObject::connect(disableLight, &QCheckBox::stateChanged, [lightEntity](auto state) {
        lightEntity->setEnabled(state == Qt::CheckState::Checked);
    });
    frame.setFixedSize(500, 500);
    frame.show();
    return a.exec();
}

Solution

  • If no light entities are created in your Qt3D scene Qt3D will add one for you. This is to prevent users not seeing anything without light. Once you add a light yourself the default one is omitted

    You can workaround this default behaviour by adding a light with intensity set to zero:

    DirectionalLight {
        worldDirection: Qt.vector3d(-1, 1, -1)
        intensity: 0.0
    }
    

    This will give you the following effect: test with cuboid and sphere mesh with PhongMaterial:

    test with cuboid and sphere mesh with PhongMaterial

    So tinkering with the intensity property of the light might give what you want.