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

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

该示例展示了如何创建可移动和调整场景中 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 ,它有两个函数:handleControllerPresshandleControllerMove 。在 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)
}

可重复使用的组件

我们将AimController 和小工具放在单独的子项目xr_shared 中,以便在未来的示例中重复使用。(xr_shared 还包括自由形式传送示例中的FreeformTeleporter 组件)。

将所有组件连接在一起

我们定义了一个组件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: 30
        frequency: 3000
    }
    property Model prevObj: null
    function handleHover(obj: Model) {
        if (obj && obj !== prevObj)
            start()
        prevObj = obj
    }
}

示例项目 @ code.qt.io

© 2025 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.