このページでは

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 の2つの関数があります。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 が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: 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.