How to rotate a 3d cube in qml?

Viewed 889

I am developing an application in Qt Creator with QtQuick. The purpose of this application is to rotate a cube in 3 dimensions with the help of a finger.

I managed to develop the creation of actions in relation to the finger movements but I am completely stuck on the rotation of the cube in relation to the fingers.

I have tried to create a direction vector with respect to the current and previous points as well as the normal vector. I have applied the Euler rotation in x and y on the cube but at a certain point, the cube does not rotate as expected.

Here is my qml code for the main page of the application :

main.qml

import QtQuick 2.15
import QtQuick.Window 2.14
import QtQuick3D 1.15
import Qt3D.Input 2.0
import QtQuick.Controls 2.1
import Qt3D.Extras 2.15

Window {
        visible: true
        width: 640
        height: 480
        title: qsTr("MouseArea Demo")

        MouseArea{
            property int previousX: -1
            property int previousY: -1

            anchors.fill : parent

            onPressed: {

                previousX = mouseX;
                previousY = mouseY;
            }

            onPositionChanged: {

                let direction = Qt.vector2d(mouseX - previousX, mouseY - previousY).normalized();
                let normal = Qt.vector2d(direction.y, direction.x).normalized();
                console.log("direction : " + direction);
                console.log("normal : " + normal);
                cube.eulerRotation.x += normal.x * 3;
                cube.eulerRotation.y += normal.y * 3;



                previousX = mouseX;
                previousY = mouseY
            }

            onReleased: {

                previousX = -1;
                previousY = -1;

            }
        }

    View3D {
        id: view
        anchors.fill: parent
        camera: camera
        renderMode: View3D.Overlay


        PerspectiveCamera {
            id: camera
            position: Qt.vector3d(0, 200, 300)
            eulerRotation.x: -30

        }

        DirectionalLight {
            eulerRotation.x: -30
        }

        Model {

            id: cube
            visible: true
            position: Qt.vector3d(0, 0, 0)
            source: "#Cube"
            materials: [ DefaultMaterial {
                    diffuseMap: Texture {
                        id: texture
                        source: "../build-colorpicker2d-Desktop_Qt_5_15_2_GCC_64bit-Debug/res.png"
                    }
                }
            ]                       
        }
    }

}

here is a video about what I talk to you 2 days ago about the y rotation problem.

Kind regards.

enter image description here

1 Answers

First of all, you should add this in your .pro file :

QT += qml quick 3dcore 3dinput 3dquick 3dlogic  3dquickextras  3dextras

I have 3 class in qml :main.qml , RootEntity.qml and SOrbitCameraController.qml

I have one Scene3D and inside this, I can put all my Entities. I Create a separate class and call it RootEntity. The more important point of this way is orbitController that I use in my class. this makes that you can rotate cube by mouse and for doing this you need Entity. because of this, I use Scene3D and Entity instead of view3d and models.

In main.qml:

import QtQuick 2.12
import QtQuick.Scene3D 2.12
import QtQuick.Window 2.12

import "."

Window {
    visible: true
    width: 640
    height: 480

    Scene3D
    {
        id : scene3d
        anchors.fill: parent
        focus: true
        aspects: ["render", "logic", "input"]
        hoverEnabled: true
        cameraAspectRatioMode: Scene3D.AutomaticAspectRatio


        antialiasing: true

        RootEntity
        {
            id:root
        }

    }

}

in RootEntity.qml:

import QtQuick 2.0

import Qt3D.Core 2.12
import Qt3D.Render 2.12
import Qt3D.Extras 2.12
import Qt3D.Input 2.12

import "."


Entity {
    id: root

    //create camera

    Camera {
        id: mainCamera
        projectionType: CameraLens.PerspectiveProjection
        fieldOfView: 45
        aspectRatio: 16/9
        nearPlane : 0.1
        farPlane : 1000.0
        position: Qt.vector3d(0.0, 4.49373, -3.78577)
        upVector: Qt.vector3d( 0.0, 1.0, 0.0 )
        viewCenter: Qt.vector3d(0.0, 0.5, 0.0)
    }

    //use my class instead of OrbitCameraController

    SOrbitCameraController {
        id: mainCameraController
        camera: mainCamera
    }

    components: [
        RenderSettings {

            Viewport {
                normalizedRect: Qt.rect(0.0, 0.0, 1.0, 1.0)
                RenderSurfaceSelector {
                    CameraSelector {
                        id: cameraSelector
                        camera: mainCamera
                        FrustumCulling {
                            ClearBuffers {
                                buffers: ClearBuffers.AllBuffers
                                clearColor: "#444449"
                                NoDraw {}
                            }
                            LayerFilter {
                                filterMode: LayerFilter.DiscardAnyMatchingLayers
                                layers: [topLayer]
                            }
                            LayerFilter {
                                filterMode: LayerFilter.AcceptAnyMatchingLayers
                                layers: [topLayer]
                                ClearBuffers {
                                    buffers: ClearBuffers.DepthBuffer
                                }
                            }
                        }
                    }
                }
            }
        },
        InputSettings {}
        ,
        ScreenRayCaster
        {
            id:screenRayCaster
            onHitsChanged:
            {
                drawLineMesh(hits)

            }

        }
    ]

    Layer {
        id: topLayer
        recursive: true
    }


    Entity {
        id: cubeEntity
        components: [
            CuboidMesh
            {
                xExtent: 1
                yExtent: 1
                zExtent: 1


            }

            ,

            Transform {
                id: t
                translation: Qt.vector3d(0, 0, 0)

            }
            ,
            PhongMaterial
            {
                ambient: "red"
            }


        ]

    }

}

in SOrbitCameraController.qml :

import Qt3D.Core 2.0
import Qt3D.Render 2.0
import Qt3D.Input 2.0

Entity{
    id: root
    property Camera camera;
    property real dt: 0.001
    property real linearSpeed: 1
    property real lookSpeed: 500
    property real zoomLimit: 0.16

    MouseDevice {
        id: mouseDevice
        sensitivity: 0.001 // Make it more smooth
    }

    MouseHandler {
        id: mh
        readonly property vector3d upVect: Qt.vector3d(0, 1, 0)
        property point lastPos;
        property real pan;
        property real tilt;
        sourceDevice: mouseDevice

        onPanChanged: root.camera.panAboutViewCenter(pan, upVect);
        onTiltChanged: root.camera.tiltAboutViewCenter(tilt);

        onPressed: {
            lastPos = Qt.point(mouse.x, mouse.y);
        }
        onPositionChanged: {
            // You can change the button as you like for rotation or translation
            if (mouse.buttons === 1){ // Left button for rotation
                pan = -(mouse.x - lastPos.x) * dt * lookSpeed;
                tilt = (mouse.y - lastPos.y) * dt * lookSpeed;
            } else if (mouse.buttons === 2) { // Right button for translate
                var rx = -(mouse.x - lastPos.x) * dt * linearSpeed;
                var ry = (mouse.y - lastPos.y) * dt * linearSpeed;
                camera.translate(Qt.vector3d(rx, ry, 0))
            } else if (mouse.buttons === 3) { // Left & Right button for zoom
                ry = (mouse.y - lastPos.y) * dt * linearSpeed
                zoom(ry)
            }

            lastPos = Qt.point(mouse.x, mouse.y)
        }
        onWheel: {
            zoom(wheel.angleDelta.y * dt * linearSpeed)
        }

        function zoom(ry) {
            if (ry > 0 && zoomDistance(camera.position, camera.viewCenter) < zoomLimit) {
                return
            }

            camera.translate(Qt.vector3d(0, 0, ry), Camera.DontTranslateViewCenter)
        }

        function zoomDistance(posFirst, posSecond) {
            return posSecond.minus(posFirst).length()
        }
    }
}

and at the end my main.cpp :

#include <QGuiApplication>
#include <QQmlApplicationEngine>

int  main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication        app(argc, argv);
    QQmlApplicationEngine  engine;
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

    if (engine.rootObjects().isEmpty())
    {
        return -1;
    }

    return app.exec();
}

the out put enter image description here

Related