Introduction to Qt Quick3D

  • Tutorial
This post participates in the competition “Smart Phones for Smart Posts”.
Not so long ago, the Qt Quick framework acquired the Qt Quick3D add-on, which allows you to fully work with 3D objects (import from 3D Max and Blender is supported), perform various transformations, animations on them, apply effects, and, in general, make full use of the capabilities of the underlying OpenGL. All this works under Symbian, MeeGo, Windows \ Linux \ MacOs (well, and generally wherever Qt is). In this topic, we will try the technology "on the tooth." I don’t want to write something complicated and serious, so we’ll make a habrazer, from which a UFO will fly out by clicking.
Immediately the result:


What do we need


Download and install Qt Creator , Qt library , Qt Quick3D and Blender . We also need 3D models that we will use. I took this fridge and this flying saucer (everything is free). Well, the Habr logo shamelessly stole.

Go


So, launch Qt Creator and create a new project: File-> New File or Project-> Qt Quick Project-> User Interface on Qt Quick .



We enter the name of the project, the location of the folder, we leave all other options by default.



The newly created project looks something like this:



Let us leave it alone for now.

Model Preparation


We open Blender and prepare models in it that we will use. I will not describe in detail the work in Blender (after all, this is not a lesson from him, and I am not special in Blender). Here is a brief summary of what we will do:
  1. Let's open the model of the refrigerator and UFO.
  2. Place the UFO in the refrigerator.
  3. We hook on the Habr logo on the refrigerator.
  4. We export from Blender separately a UFO (which is now in the refrigerator), a refrigerator door (we need it separately so that it can be opened) and its body without a door. And we should have 4 files at the output: ufo.3ds , door.3ds , refr.3ds + texture file . Copy all these files to the project folder.


Hello world


We return to Qt Creator to our project. When it was created, such a “Hello world” was written to the HabraHolod.qml file, but it has nothing to do with Qt Quick3D, and therefore we will delete it. Let's start writing our qml code from scratch. In the first iteration, it will be like this:
import Qt3D 1.0
Viewport {
    Mesh { id: refrigirator; source: "refr.3ds" }
    Mesh { id: ufo; source: "ufo.3ds" }
    Mesh { id: bottom_door; source: "door.3ds" }
    Item3D { mesh: refrigirator }
    Item3D { mesh: ufo;}
    Item3D { mesh: bottom_door; }
}

Let's go through the code. In the first line, we import the Qt3D package, which, if everything is installed correctly, must be found and set to work on displaying 3D objects. If you, like me, messed up something at the installation stage (I had a different version of the Qt libraries installed), then here is a very sensible article that describes what and where to put your hands in order for everything to work and another one explaining how to compile Qt Quick3D manually.

Next, we create the Viewport element.- This is a container where you can add 3D objects and set some parameters for their display (lighting, camera position, etc.). Next, we import 3 of our 3ds files (each in a separate cache) and create 3 Item3D elements (pay attention to their association with the meshes by the id property ).

If you press Ctrl + R (start), you can even see the result:



Something strange, right? :) In fact, everything works correctly. The thing is that so far neither the window of our application, nor the parameters of the 3D scene have been configured and therefore we look at our objects in a tiny window from an incomprehensible position. If you manually make the window larger and use scrolling, you will see our scene something like this:



The beginning is not bad - in 10 lines of code we already have an application that somehow displays a group of 3D objects (well, how many lines will be in it if you write it in C ++ \ Java \ .NET \ Your_Language?).

Move on


So, our objects, of course, are displayed, but somehow not so, not there and are not moving yet. We will gradually improve this business. First, add the Rectangle root element to the code (for this we will have to import the QtQuick 1.0 module), which will allow us to set the window size:
import QtQuick 1.0
import Qt3D 1.0
Rectangle {
    color: "black"
    width: 400
    height: 600
    Viewport {
        anchors.fill: parent
        Mesh { id: refrigirator; source: "refr.3ds" }
        Mesh { id: ufo; source: "ufo.3ds" }
        Mesh { id: bottom_door; source: "door.3ds" }
        Item3D { mesh: refrigirator }
        Item3D { mesh: ufo;}
        Item3D { mesh: bottom_door; }
    }
}

For Rectangle, we set the initial sizes and color, and for Viewport, we said that it should be stretched to the entire size of the parent. Result: The



window is the right size, but we are still looking at the object from somewhere below. Correct the position of the camera. To do this, use the camera property of our Viewport:
camera: Camera {
    id: viewCamera
    eye: Qt.vector3d(15,10,40)
    center: Qt.vector3d(-2,10,0)
}

Full code at this stage

The eye property determines where the camera is, and center determines the point it is looking at. Current result:



But it’s already not bad! If we just wanted to look at a 3D object in Qt Quick3D, we could end there. But no! Our goal is movement.

Click handler


So, we have a display model of the refrigerator, which is actually 3 models in one scene. We will try to make the door open by clicking and a UFO will fly out. First of all, a click handler. It's simple, add a MouseArea element to the Viewport, stretched to the entire size of the parent. By click, we will write the output for now (just to check what works):
MouseArea {
	anchors.fill: parent
	onClicked: {
		Qt.quit();
	}
}

Complete code at this stage

Run, click - the program ends. Works.

Transformations and Animations


Let's start with the opening door. In order to open and close it, we need to do the following things:

1 . Create a Rotation3D element that describes how (around which axes) a certain object will rotate.
Rotation3D {
    id: doorOpen
    angle: 0
    axis: Qt.vector3d(0, 1, 0)
    origin: Qt.vector3d(-3, 0,  0)
}

2 . Create a SequentialAnimation element, the essence of which will be in two Rotation3D calls (one to open the door, the second to close) with different directions of rotation.
SequentialAnimation { id: doorOpenAndClose;
    NumberAnimation { target: doorOpen; property: "angle"; from: 0; to : -80.0; duration: 800;  easing.type: Easing.OutBounce}
    NumberAnimation { target: doorOpen; property: "angle"; from: -80; to : 0.0; duration: 1200; easing.type: Easing.OutCubic}
            }

3 . Bind the Rotation3D element to the Item3D corresponding to our door.
 Item3D { mesh: bottom_door; transform: [doorOpen] }

4 . Call an intermediate function from the click handler that starts the animation.
MouseArea {
    anchors.fill: parent
    onClicked: {
        fullScene.openDoor();
    }
}
		...
Item3D {
	id: fullScene
	function openDoor()	{
		doorOpenAndClose.loops = 1;
		doorOpenAndClose.start();
	}
	...
}

Full code at this stage

Run, click. Bingo!



The door opens and shows our UFO inside (so far quite hanging peacefully). The task of animating a one-on-one UFO departure is similar to opening a door. Therefore, without unnecessary comments, the final code:

import QtQuick 1.0
import Qt3D 1.0
Rectangle {
    color: "black"
    width: 400
    height: 600
    Viewport {
        anchors.fill: parent
        MouseArea {
            anchors.fill: parent
            onClicked: {
                fullScene.openDoor();
            }
        }
        camera: Camera {
            id: viewCamera
            eye: Qt.vector3d(15,10,40)
            center: Qt.vector3d(-2,10,0)
        }
        Item3D {
            id: fullScene
            function openDoor(){
                doorOpenAndClose.loops = 1;
                doorOpenAndClose.start();
                ufoFlyOutAndTeleportBack.loops = 1;
                ufoFlyOutAndTeleportBack.start();
            }
            Mesh { id: refrigirator; source: "refr.3ds" }
            Mesh { id: ufo; source: "ufo.3ds" }
            Mesh { id: bottom_door; source: "door.3ds" }
            Item3D { mesh: refrigirator }
            Item3D { mesh: ufo; transform: [ufoFlyOut]}
            Item3D { mesh: bottom_door;  transform: [doorOpen] }
            // ------------------ Transform + Animations ------------------
            Rotation3D {
                id: doorOpen
                angle: 0
                axis: Qt.vector3d(0, 1, 0)
                origin: Qt.vector3d(-3, 0,  0)
            }
            Rotation3D {
                id: ufoFlyOut
                angle: 0
                axis: Qt.vector3d(0, 3, -1)
                origin: Qt.vector3d(10, 0,  0)
            }
            SequentialAnimation { id: doorOpenAndClose;
                NumberAnimation { target: doorOpen; property: "angle"; from: 0; to : -80.0; duration: 800; easing.type: Easing.OutBounce}
                NumberAnimation { target: doorOpen; property: "angle"; from: -80; to : 0.0; duration: 1200; easing.type: Easing.OutCubic}
            }
            SequentialAnimation { id: ufoFlyOutAndTeleportBack;
                NumberAnimation { target: ufoFlyOut; property: "angle"; from: 0; to : 100.0; duration: 1700; easing.type: Easing.OutCurve}
                NumberAnimation { target: ufoFlyOut; property: "angle"; from: 100; to : 0.0; duration: 0; easing.type: Easing.OutCubic}
            }
        }
    }
}

and again the result:


All project sources can be taken here .

Useful materials on the topic

  1. Introducing Qt Quick3D and Download Links for Multiple Platforms
  2. Cool tutorial on creating a model car
  3. Official documentation of the Qt Quick3D

Also popular now: