Sur cette page

Qt Quick Exemple simple d'entrée 3D - XR

Illustre l'utilisation des manettes dans Qt Quick 3D XR.

Théière avec un contrôleur XR dont le faisceau est dirigé vers un panneau d'interface utilisateur doté de boutons colorés

Cet exemple montre comment utiliser les API de saisie de bas niveau d'Qt Quick 3D XR pour interagir avec des objets 2D et 3D dans la scène. Il suit la structure de base de l'exemple xr_simple.

Entrées du contrôleur

Dans cet exemple, nous effectuons l’ ray picking depuis la position de l’ XrController:

XrController {
    id: rightController
    controller: XrController.RightController
    poseSpace: XrController.AimPose

    property QtObject hitObject

    onRotationChanged: {
        const pickResult = xrView.rayPick(scenePosition, forward)
        if (pickResult.hitType !== PickResult.Null) {
            pickRay.hit = true
            pickRay.length = pickResult.distance
            hitObject = pickResult.objectHit
            cursorSphere.position = pickResult.scenePosition
            cursorSphere.visible = true
        } else {
            pickRay.hit = false
            pickRay.length = 50
            hitObject = null
            cursorSphere.visible = false
        }
    }

    Node {
        id: pickRay
        property real length: 50
        property bool hit: false

        Model {
            eulerRotation.x: -90
            scale: Qt.vector3d(0.005, pickRay.length/100, 0.005)
            source: "#Cone"
            materials: PrincipledMaterial {
                baseColor: rightTrigger.pressed ? "#99aaff" : "#cccccc"
                lighting: PrincipledMaterial.NoLighting
            }
            opacity: 0.8
        }
    }

    Node {
        z: 5
        Model {
            eulerRotation.x: 90
            scale: Qt.vector3d(0.05, 0.10, 0.05)
            source: "#Cylinder"
            materials: PrincipledMaterial {
                baseColor: "black"
                roughness: 0.2
            }
        }
    }
}

Cela permet d’effectuer les opérations suivantes :

  • Si nous touchons un objet, nous modifions la longueur de l’« pickRay » afin qu’il touche l’objet en question. L’« pickRay » est un cône semi-transparent (un cylindre effilé) qui indique où l’utilisateur vise. Nous déplaçons également l’« cursorSphere » vers le point où le rayon touche l’objet. (L’«cursorSphere » est une sphère semi-transparente qui est un enfant de l’« XrView »).
  • Nous attribuons la propriété hitObject à l’objet que nous touchons.

Nous utilisons également un cylindre noir pour représenter de manière générique la manette.

Pour cet exemple, nous avons créé un simple bouton-poussoir 3D dans le fichier ExampleButton.qml. (Le fonctionnement détaillé du bouton n’est pas expliqué ici.) Nous créons une action XrInputAction pour réagir aux pressions sur le bouton :

XrInputAction {
    id: rightTrigger
    controller: XrInputAction.RightController
    actionId: [XrInputAction.TriggerPressed, XrInputAction.TriggerValue, XrInputAction.IndexFingerPinch]
    onTriggered: {
        const button = rightController.hitObject as ExampleButton
        if (button && button !== panel.activeButton) {
            panel.activeButton = button
        }
    }
}

L’action rightTrigger réagit à plusieurs identifiants différents afin de prendre en charge à la fois le suivi des mains et différents types de manettes. Lorsque l’action est déclenchée, elle vérifie si l’ hitObject que nous avons définie ci-dessus est de type ExampleButton. Dans ce cas, le bouton est activé.

Pour permettre à une manette 3D d’interagir avec du contenu 2D, nous devons ajouter une action « XrVirtualMouse » afin d’établir une correspondance entre les deux :

XrInputAction {
    id: rightThumbstickX
    controller: XrInputAction.RightController
    actionId: [XrInputAction.ThumbstickX]
}
XrInputAction {
    id: rightThumbstickY
    controller: XrInputAction.RightController
    actionId: [XrInputAction.ThumbstickY]
}

XrVirtualMouse {
    view: xrView
    source: rightController
    leftMouseButton: rightTrigger.pressed
    scrollWheelX: rightThumbstickX.value
    scrollWheelY: rightThumbstickY.value
}

Nous ajoutons d’abord deux actions supplémentaires pour détecter la position horizontale et verticale du joystick. Ensuite, nous créons une « XrVirtualMouse » en utilisant l’« XrController » comme source de position. Nous utilisons l’action « rightTrigger » créée précédemment pour générer des clics et des relâchements de souris, et nous utilisons les actions du joystick pour générer des événements de molette de souris.

Enfin, nous ajoutons un retour haptique lorsque l’ pickRay entre en collision avec un objet :

XrHapticFeedback {
    controller: XrHapticFeedback.RightController
    condition: XrHapticFeedback.RisingEdge
    trigger: pickRay.hit
    hapticEffect: XrSimpleHapticEffect {
        amplitude: 0.5
        duration: 10
        frequency: 200
    }
}

L’effet haptique se déclenchera chaque fois que la propriété « pickRay.hit » passera de « false » à « true ».

XrItem

La méthode habituelle d’intégration d’interfaces utilisateur 2D dans des scènes 3D fonctionne également en XR, mais comme l’unité de mesure est le centimètre, ces interfaces devront être mises à l’échelle pour être utilisables. Le type ` XrItem ` offre un moyen pratique de réaliser automatiquement cette mise à l’échelle en définissant la taille physique de l’élément 3D et la taille logique de la surface 2D.

XrItem {
    width: 75
    height: 100
    x: -100
    y: height + table.height + 5
    z: 40
    eulerRotation.y: 45
    color: "transparent"
    contentItem: Rectangle {
        color: Qt.rgba(1, 1, 1, 0.5)
        border.width: 5
        border.color: "lightblue"
        height: 400
        width: 300
        radius: 25
    ...
        }
    }

Nous positionnons l’ XrItem en trois dimensions et lui attribuons une largeur de 75 cm et une hauteur de 100 cm. Nous ajoutons ensuite un rectangle en tant qu’élément de contenu, et lui attribuons les dimensions 300 x 400 unités. Les autres éléments de l’interface utilisateur d’ Qt Quick sont ajoutés en tant qu’enfants du rectangle de la manière habituelle et ne sont pas représentés ici. Le contenu 2D est automatiquement redimensionné pour remplir l’ XrItem.

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.