当前位置:网站首页>QT quick 3D learning: mouse picking up objects

QT quick 3D learning: mouse picking up objects

2022-06-12 22:15:00 Gongjianbo

( Be careful , Open source Qt Quick 3D It is not used by dogs GPL agreement )

Qt Creator There is one of them. picking An example of , For demonstration View3D Picking up objects in :

Based on the examples , I added a simple drag effect , As shown in the figure :

 

In the use of OpenGL When picking is realized , We can use the ray method .Qt Quick 3D The pick operation is encapsulated in , adopt View3D Of pick function , You can get it. View3D The object closest to the screen at a certain point in the viewport  Model.

PickResult pick(float x, float y)

This function returns a PickResult object , Through its  objectHit Property to determine whether an object has been picked up .

View3D {
    MouseArea {
        id: mouse_area
        anchors.fill: parent
        onPressed: {
            // Get point at View Screen coordinates on 
            pick_screen.text = "(" + mouse.x + ", " + mouse.y + ")"
            //pick Take the nearest intersection with the ray path at this point Model Information about , return PickResult object 
            var result = control.pick(mouse.x, mouse.y)
            // Judge objectHit Whether it works , You can only know if you have picked up an object 
            if (result.objectHit) {

            } else {

            }
        }
    }
}

stay Qt5.15 in , Back to PickResult Types have only a few simple properties :

// Pick the distance between the origin and the object , Pick with viewport coordinates, and the origin is the observation point Camera The location of 
distance : float

// Pick the selected Model object 
objectHit : Model

//pick The position of the point in the scene ,( It may be equivalent to the focal coordinates of the ray and the object surface )
//This property holds the scene position of the hit.
scenePosition : vector3d

//pick Dot UV Location 
//This property holds the UV position of the hit.
uvPosition : vector2d

stay Qt6.3 in ,View3D Added pickAll Function to pick up all objects at that point , meanwhile PickResult Type also adds some attributes :

// The normal of the selected face in local space 
//This property holds the normal of the face that was hit in local coordinate space.
normal : vector3d

//This property holds the scene position of the hit in local coordinate space.
position : vector3d

//This property holds the normal of the face that was hit in scene coordinate space.
sceneNormal : vector3d

After picking up the object , You can do this Model The node has been operated . this paper Demo I implemented a simple drag operation in , The main process is :

1.pick Save when selected Model Location and pick Viewport screen coordinate difference of position ( Can pass View3D Of  mapFrom3DScene Function to convert scene coordinates to viewport coordinates , To use this function, you need to give View3D Set up camera )

2. While the mouse is moving , Restore objects by difference Model Relative position of , Use View3D Of mapTo3DScene Function conversion to get Model New scene coordinates .

( But this logic does not consider perspective projection , Move the scene coordinates xy, Viewport coordinates xy It doesn't change proportionally )

Main code

Github(PickModel.qml): https://github.com/gongjianbo/HelloQtQuick3D

import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick3D 1.15
import QtQuick3D.Helpers 1.15

View3D {
    id: control

    // background 
    environment: SceneEnvironment {
        clearColor: "darkGreen"
        backgroundMode: SceneEnvironment.Color
    }

    // Observation camera 
    //View3D Of mapTo/mapFrom Coordinate conversion function needs to be set first camera attribute 
    camera: perspective_camera
    PerspectiveCamera {
        id: perspective_camera
        z: 300
    }

    // light 
    DirectionalLight {
        eulerRotation.y: 45
    }

    // Cube 
    Model {
        id: cube_node
        objectName: "Cube"
        source: "#Cube"
        // Can make pick
        pickable: true
        materials: DefaultMaterial {
            diffuseColor: mouse_area.pickNode == cube_node ? "cyan" : "yellow"
        }
        // The cube turns 
        SequentialAnimation on eulerRotation {
            running: true
            loops: Animation.Infinite
            PropertyAnimation {
                duration: 10000
                from: Qt.vector3d(0, 0, 0)
                to: Qt.vector3d(360, 360, 360)
            }
        }
    }

    // cone 
    Model {
        id: cone_node
        objectName: "Cone"
        source: "#Cone"
        pickable: true
        x: 100
        z: 50
        materials: DefaultMaterial {
            diffuseColor: mouse_area.pickNode == cone_node ? "cyan" : "orange"
        }
    }

    // sphere 
    Model {
        id: sphere_node
        objectName: "Sphere"
        source: "#Sphere"
        pickable: true
        x: -100
        z: -50
        materials: DefaultMaterial {
            diffuseColor: mouse_area.pickNode == sphere_node ? "cyan" : "purple"
        }
    }

    // Show information about picked objects 
    Row {
        x: 20
        y: 20
        spacing: 10
        Column {
            Label {
                color: "white"
                text: "Pick Node:"
            }
            Label {
                color: "white"
                text: "Screen Position:"
            }
            Label {
                color: "white"
                text: "Distance:"
            }
            Label {
                color: "white"
                text: "World Position:"
            }
        }
        Column {
            Label {
                id: pick_name
                color: "white"
            }
            Label {
                id: pick_screen
                color: "white"
            }
            Label {
                id: pick_distance
                color: "white"
            }
            Label {
                id: pick_word
                color: "white"
            }
        }
    }

    MouseArea {
        id: mouse_area
        anchors.fill: parent
        hoverEnabled: false
        property var pickNode: null
        // Mouse and objects xy The migration 
        property real xOffset: 0
        property real yOffset: 0
        property real zOffset: 0

        onPressed: {
            // Get point at View Screen coordinates on 
            pick_screen.text = "(" + mouse.x + ", " + mouse.y + ")"
            //pick Take the nearest intersection with the ray path at this point Model Information about , return PickResult object 
            // Because the module has been iterating , The new version can be downloaded from PickResult Object to get more information 
            //Qt6 It is also provided pickAll Get all that intersect the ray Model Information 
            var result = control.pick(mouse.x, mouse.y)
            // Currently only updated when clicked pick Information about objects 
            if (result.objectHit) {
                pickNode = result.objectHit
                pick_name.text = pickNode.objectName
                pick_distance.text = result.distance.toFixed(2)
                pick_word.text = "("
                        + result.scenePosition.x.toFixed(2) + ", "
                        + result.scenePosition.y.toFixed(2) + ", "
                        + result.scenePosition.z.toFixed(2) + ")"
                //console.log('in',pick_screen.text)
                //console.log(result.scenePosition)
                var map_from = control.mapFrom3DScene(pickNode.scenePosition)
                //var map_to = control.mapTo3DScene(Qt.vector3d(mouse.x,mouse.y,map_from.z))
                //console.log(map_from)
                //console.log(map_to)
                xOffset = map_from.x - mouse.x
                yOffset = map_from.y - mouse.y
                zOffset = map_from.z
            } else {
                pickNode = null
                pick_name.text = "None"
                pick_distance.text = " "
                pick_word.text = " "
            }
        }
        onPositionChanged: {
            if(!mouse_area.containsMouse || !pickNode){
                return
            }
            var pos_temp = Qt.vector3d(mouse.x + xOffset, mouse.y + yOffset, zOffset);
            var map_to = control.mapTo3DScene(pos_temp)
            pickNode.x = map_to.x
            pickNode.y = map_to.y
        }
    }
}

Reference resources

Qt file :https://doc.qt.io/qt-5/qml-qtquick3d-view3d.html

原网站

版权声明
本文为[Gongjianbo]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/163/202206122201192164.html