本页内容

Qt Quick 3D - XR 3D交互示例

演示如何使用Qt Quick 3D XR操作3D对象。

一个3D场景,其中色彩斑斓的字母和形状在太空中漂浮

本示例展示了如何创建组件,以移动和调整场景中3D对象的大小。它采用了与xr_input示例相同的光线拾取策略。

控制器输入

在此示例中,我们将创建一个名为 `AimController` 的可复用组件。该组件通过光线拾取来选择模型,并可选地允许用户抓取所选模型并对其进行移动。

AimController 定义了信号,使我们能够实现自定义交互:

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

控件

我们定义了一个抽象组件XrGadget ,它具有两个函数:handleControllerPress 和handleControllerMove 。在 C++ 中,这些函数本应是虚拟函数。由于本示例完全使用 QML 实现,因此我们改为发出信号,以便在子组件中进行处理。

例如,TranslateGadget 会根据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)
}

整合所有内容

我们定义了一个名为 `GadgetBox ` 的组件,它不仅会在对象周围显示控件,还会跟踪哪个对象被选中,并在选中对象周围显示一个半透明的框。当选中的对象被按下时,GadgetBox 信号将循环切换三种不同类型的控件(平移、旋转和调整大小)。

在 `main.qml ` 中,我们响应来自 `AimController ` 的信号,并调用 `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
}

当悬停对象或控件发生变化时,我们还会提供触觉反馈:

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
    }
}

示例项目 @ 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.