Sur cette page

Qt Quick 3D - Exemple d'interaction 3D XR

Illustre comment manipuler des objets 3D à l'aide de l'Qt Quick e 3D XR.

Scène en 3D avec des lettres et des formes colorées flottant dans l'espace

Cet exemple montre comment créer des composants permettant de déplacer et de redimensionner des objets 3D dans une scène. Il utilise la même stratégie de sélection par rayons que l'exemple xr_input.

Entrée du contrôleur

Dans cet exemple, nous créons un composant réutilisable nommé AimController. Celui-ci effectue une sélection par rayons pour choisir un modèle et permet, en option, à l’utilisateur de saisir le modèle sélectionné et de le déplacer.

AimController Il définit des signaux qui nous permettent de mettre en œuvre des interactions personnalisées :

property Model hoveredObject: null
signal objectPressed(obj: Model, pos: vector3d, direction: vector3d)
signal moved(pos: vector3d, direction: vector3d)
signal released()
signal objectGrabbed(obj: Model)

Gadgets

Nous définissons un composant abstrait, XrGadget, qui dispose de deux fonctions : handleControllerPress et handleControllerMove. En C++, ces fonctions auraient été virtuelles. Comme cet exemple est entièrement implémenté en QML, nous émettons à la place des signaux pouvant être gérés dans des sous-composants.

Par exemple, TranslateGadget déplace l’objet contrôlé le long de l’axe du gadget en fonction du signal onMoved:

onMoved: (pos, dir) => {
    let moveDirection = delta.normalized()
    let mapped_axis = controlledObject.mapDirectionToScene(axisDirection).normalized()
    let dot = mapped_axis.dotProduct(moveDirection)
    let offset = mapped_axis.times(delta.length() * dot)
    controlledObject.position = originalPos.plus(offset)
}

Rassembler le tout

Nous définissons un composant GadgetBox qui garde en mémoire l’objet sélectionné et affiche un cadre translucide autour de celui-ci, en plus d’afficher des gadgets autour de l’objet. Lorsqu’on appuie sur un objet sélectionné, le signal GadgetBox bascule entre les trois types de gadgets (translation, rotation et redimensionnement).

Dans ` main.qml `, nous réagissons aux signaux provenant de ` AimController ` et appelons les fonctions de ` GadgetBox` :

AimController {
    id: rightAim
    controller: XrController.RightController
    view: xrView
    enableVirtualMouse: true
    enableThumbstickMove: thumbCheckBox.checked

    onObjectPressed: (obj, pos, dir) => {
        gadgetBox.handlePress(obj, pos, dir)
    }
    onHoveredObjectChanged: {
        gadgetBox.handleHover(hoveredObject)
        hapticFeedback.handleHover(hoveredObject)
    }
    onMoved: (pos, dir) => {
        gadgetBox.handleMove(pos, dir)
    }
    onReleased: {
        gadgetBox.handleRelease()
    }
    onObjectGrabbed: (obj) => {
        if (!grabCheckBox.checked)
            return
        const gadget = obj as XrGadget
        if (!gadget)
            startGrab(obj)
        else if (gadget.grabbable)
            startGrab(gadget.controlledObject)
    }
    Model {
        source: "#Cylinder"
        scale: "0.05, 0.1, 0.05"
        z: 5
        eulerRotation.x: 90
        materials: PrincipledMaterial {
            baseColor: "black"
        }
    }
    xrCursor: cursor
}

Nous fournissons également un retour haptique lorsque l’objet ou le gadget survolé change :

XrHapticFeedback {
    id: hapticFeedback
    controller: XrHapticFeedback.RightController
    hapticEffect: XrSimpleHapticEffect {
        amplitude: 0.5
        duration: 10
        frequency: 200
    }
    property Model prevObj: null
    function handleHover(obj: Model) {
        if (obj && obj !== prevObj)
            start()
        prevObj = obj
    }
}

Exemple de projet sur code.qt.io

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.