Qt Quick 3D - XR 3D インタラクションの例

Qt Quick 3D XR で 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)

ガジェット

handleControllerPresshandleControllerMove の2つの関数を持つ抽象コンポーネントXrGadget を定義します。この例は完全に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 、3種類のガジェット(平行移動、回転、サイズ変更)が切り替わります。

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.