Skip to content

What a mesh! Part 1

With all the advances being made in Qt 3D, we wanted to create some new examples showing some of what it can do. To get us started, we decided to use an existing learning framework, so we followed the open source Tower Defence course, which you can find at CGCookie. Being a game, it allows an interactive view of everything at work, which is very useful. We found it to be so diverse, that we are now implementing Parts 2 and 3 of the game into Qt 3D. However you don’t have to wait for that, you can start now by following the steps we took.

The setup

These instructions will help you setup for Qt 5.11.0 . To start, turn to your QtCreator and create a new Qt Console Application, set to run on your Qt 5.11.0 kit. A Qt Console Application doesn’t come with too much ‘plumbing’. A lot of the other options will attempt to give you starting files that aren’t required or in some cases, the wrong type entirely. Let’s edit it to fit our needs by opening up the .pro file and adding the following: First remove the QT += core and QT -= gui lines if they are present.

QT += 3dcore 3drender 3dinput 3dquick 3dquickextras qml quick

Then, if the lines CONFIG += c++11 console and CONFIG -= app_bundle are present, remove them too. Now back on the main.cpp file we need to edit our “includes” from the Qt 3D library. Replace the #include QCoreApplication with #include QGuiApplication and add these lines:

#include <Qt3DQuick/QQmlAspectEngine>;
#include <Qt3DQuickExtras/Qt3DQuickWindow>
#include <QtQml>

Within the main block we now have to edit QCoreApplication a(argc, argv); to mirror our include change. So change it to:

QGuiApplication a(argc, argv);

Before the first build / run we should add something to look at. Adding the following block of code before the return statement will provide us with a window:

Qt3DExtras::Quick::Qt3DQuickWindow view;
view.setSource(QUrl("qrc:/main.qml"));
view.show();

Commenting out the line referring to main.qml will allow you to build and run what you have already. If everything has gone to plan, you will get a white window appear. Now you can uncomment the line and continue onwards!

QRC creation

Okay, let’s get rid of the boring white scene and get something in there. Right-click the ‘Sources’ folder and select ‘Add New…’. From here select the Qt > QML File (Qt Quick 2) option. We’ve gone and named it main so that after clicking next till the end you should now have a main.qml and a main.cpp. This QML file is now going to hold our scene, but to do that we need some resources. We will achieve this by adding a Qt Resource File, just as we did for main.qml – assuming you have an obj with accompanying textures placed in an assets folder within the project. So this time right-click on the project folder and select ‘Add New…’. From the Qt menu, select ‘Qt Resource File’ and name it something fitting. When this opens it will look noticeably different to the qml and cpp files. At the bottom you will see the self-descriptive; Add, Remove and Remove Missing Files buttons. Click the ‘Add’ button and select ‘Add Prefix’. Now remove everything from the Prefix: text input just leaving the ‘/‘. Click the ‘Add’ button again, this time selecting the ‘Add Files’ option. Navigate to your obj and texture files and add them all to the qrc, save and close it. If everything went to plan, a ‘Resources’ folder will now be visible in the Projects window on the left. Follow this again and add main.qml to the qrc in the same way. One last thing we need before playing with the scene is a skymap. With the files placed in your assets folder, go ahead and add the skymap to the qrc file.

Gotcha

We use three dds files for our skymaps, irradiance, radiance and specular. If you are trying this on a Mac, you will have to uncompress them or they will not work. Keep the names similar to their compressed version. For example we simply added ‘-16f’ to the filename. So our files would be ‘wobbly_bridge_4k_cube_irradiance’ vs ‘wobbly_bridge_4k-16f_cube_irradiance’ respectively.

The necessities

Back to the QML file now, rename the Item { } to be an Entity { } and give it the id: scene. Entity is not recognised because we are missing some imports. Hitting F1 with Entity selected shows us that we need to import Qt3D.Core 2.0, so add this to the imports at the top of the file. There are certain components that a 3D scene must have, a camera and Render settings being two of those. For this example, we’ll throw in a camera controller too so we can move around the scene.

components: [
    RenderSettings {
        activeFrameGraph: ForwardRenderer {
            camera: mainCamera
            clearColor: Qt.rgba(0.1, 0.1, 0.1, 1.0)
        }
    },
    // Event Source will be set by the Qt3DQuickWindow
    InputSettings { }
]
Camera {
    id: mainCamera
    position: Qt.vector3d(30, 30, 30)
    viewCenter: Qt.vector3d(0, 0, 0)
}
FirstPersonCameraController {
    camera: mainCamera
    linearSpeed: 10
    lookSpeed: 50
}

Here we see that Camera is not recognised, so let’s get the missing import.

Gotcha

If you select Camera and hit F1 to find the import, you will in fact be shown the import for the non-Qt3D Camera. The one you will want is: import Qt3D.Render 2.9

The sky is the limit

Let’s put that skymap to use now. Back in the main.cpp file, we need to add code to check if we’re on MAC or not. If you remember, this was due to MAC not supporting compressed files and needing its own versions. After the QGuiApplication line, put in the following:

#if defined(Q_OS_MAC)
    const QString envmapFormat = QLatin1String("-16f");
#else
    const QString envmapFormat = QLatin1String("");
#endif

Then after the Qt3DExtras line, add the following:

auto context = view.engine()->qmlEngine()->rootContext();
context->setContextProperty(QLatin1String("_envmapFormat"), envmapFormat);

If you try to build at this point, you will notice various imports missing. One for FirstPersonCameraController, one for InputSettings and TexturedMetalRoughtMaterial. Hitting F1 on FirstPersonCameraController will give you import Qt3D.Extras 2.0 and F1 on InputSettings will give you import Qt3D.Input 2.0 but then later you’ll hit a snag. TexturedMetalRoughtMaterial may not turn up any documentation but we’ll be kind enough to give you the answer… edit the Qt3D.Extras 2.0 to be 2.9 instead. If this now works you will get a dark grey window.

Barrel of laughs

The final part will be our mesh, we chose a barrel, and the skymap for it to reflect (although this might not be visible). In main.qml after the InputSettings{}, throw in the following:

EnvironmentLight {
    id: envLight
    irradiance: TextureLoader {
        source: "qrc:/path/to/your/file" + _envmapFormat + "_cube_irradiance.dds";
        minificationFilter: Texture.LinearMipMapLinear
        magnificationFilter: Texture.Linear
        wrapMode {
            x: WrapMode.ClampToEdge
            y: WrapMode.ClampToEdge
        }
        generateMipMaps: false
    }
    specular: TextureLoader {
        source: "qrc:/path/to/your/file" + _envmapFormat + "_cube_specular.dds"
        minificationFilter: Texture.LinearMipMapLinear
        magnificationFilter: Texture.Linear
        wrapMode {
            x: WrapMode.ClampToEdge
            y: WrapMode.ClampToEdge
        }
        generateMipMaps: false
    }
}

You can hit build now to check it’s working, but the scene will still be pretty boring. Throw in your obj to get some eye candy. Here is the code we used after EnvironmentLight:

Mesh {
    source: "qrc:/your/model.obj"
},
Transform {
    translation: Qt.vector3d(4, 0, 2)
},
TexturedMetalRoughMaterial {
    baseColor: TextureLoader {
        format: Texture.SRGB8_Alpha8
        source: "qrc:/path/to/your/Base_Color.png"
    }
    metalness: TextureLoader { source: "qrc:/path/to/your/Metallic.png" }
    roughness: TextureLoader { source: "qrc:/path/to/your/Roughness.png" }
    normal: TextureLoader { source: "qrc:/path/to/your/Normal_OpenGL.png" }
    ambientOcclusion: TextureLoader { source: "qrc:/path/to/your/Mixed_AO.png" }
}

Finally, hit build and then run.

Rendered Barrel

The barrel viewed at the end of What A Mesh pt1

Categories: KDAB Blogs / KDAB on Qt / Qt3D

Tags: / / / /

3 thoughts on “What a mesh!”

  1. hello,
    I tried to use QMetalRoughMaterial for my cube to see how it’s work. i saw the example in QML and i tried to translate it in C++ code That’s it :

    Qt3DExtras::QMorphPhongMaterial *mat {new Qt3DExtras::QMorphPhongMaterial(this)};
    mat->baseColor().setValue(QUrl(QStringLiteral(“qrc:/texture/metal/Metal03_col.jpg”)));
    mat->metalness().setValue(QUrl(QStringLiteral(“qrc:/texture/metal/Metal03_met.jpg”)));
    mat->roughness().setValue(QUrl(QStringLiteral(“qrc:/texture/metal/Metal03_rgh.jpg”)));
    mat->normal().setValue(QUrl(QStringLiteral(“qrc:/texture/metal/Metal03_nrm.jpg”)));
    mat->ambientOcclusion().setValue(QUrl(QStringLiteral(“qrc:/texture/metal/Metal03_disp.jpg”)));
    Not Working, so I say to go the documentation to see how the methods work, the properties are Qvariant type. I looked how to do, QVariant :: FromValue() it does not work either.

    My question is how to get textures through qvariant or QAbsractTexture ?

    Oh yes, the QTextureLoader does not work anymore? is it deleted in this version?

Leave a Reply

Your email address will not be published. Required fields are marked *