1 | // Copyright (C) 2024 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only |
3 | |
4 | #include "qquick3dxrhandinput_p.h" |
5 | #include "qquick3dxrinputmanager_p.h" |
6 | #include "qquick3dxrhandmodel_p.h" |
7 | |
8 | #if defined(Q_OS_VISIONOS) |
9 | # include "visionos/qquick3dxrinputmanager_visionos_p.h" |
10 | #else |
11 | # include "openxr/qopenxrinputmanager_p.h" |
12 | #endif |
13 | |
14 | QT_BEGIN_NAMESPACE |
15 | |
16 | /*! |
17 | \qmltype XrHandModel |
18 | \inherits Model |
19 | \inqmlmodule QtQuick3D.Xr |
20 | \brief Represents a 3D model for a hand. |
21 | |
22 | Contains an animated 3D model that tracks the user's hands |
23 | |
24 | XrHandModel is only visible when hand tracking is active. |
25 | |
26 | \note XrHandModel depends on hand-tracking data from the underlying |
27 | system and is, therefore, not available on all platforms. |
28 | |
29 | \section1 Platform Notes |
30 | |
31 | \section2 Apple Vision Pro |
32 | |
33 | The Apple Vision Pro will overlay video of the user's hands directly, |
34 | and the XrHandModel will not have any content. |
35 | |
36 | \section2 Meta devices |
37 | |
38 | This required the following feature and permission lines to be added |
39 | in the AndroidManifest.qml file of your project. |
40 | |
41 | \badcode |
42 | <uses-permission android:name="com.oculus.permission.HAND_TRACKING" /> |
43 | <uses-feature android:name="oculus.software.handtracking" android:required="false" /> |
44 | \endcode |
45 | |
46 | Use \c true instead of \c false in the \c uses-feature tag if your app's interaction |
47 | is implemented only for hands. |
48 | */ |
49 | |
50 | QQuick3DXrHandModel::QQuick3DXrHandModel(QQuick3DNode *parent) |
51 | : QQuick3DModel(parent) |
52 | { |
53 | } |
54 | |
55 | void QQuick3DXrHandModel::updatePose() |
56 | { |
57 | if (auto *skin = QQuick3DModel::skin()) { |
58 | auto jointListProp = skin->joints(); |
59 | int count = jointListProp.count(&jointListProp); |
60 | const auto positions = m_handTracker->jointPositions(); |
61 | const auto rotations = m_handTracker->jointRotations(); |
62 | for (int i = 0; i < count; ++i) { |
63 | auto *joint = jointListProp.at(&jointListProp, i); |
64 | joint->setPosition(positions.at(i)); |
65 | joint->setRotation(rotations.at(i)); |
66 | } |
67 | } else { |
68 | static bool warned = false; |
69 | if (!warned) { |
70 | qWarning() << "No skin available for hand model" ; |
71 | warned = true; |
72 | } |
73 | } |
74 | } |
75 | |
76 | void QQuick3DXrHandModel::setupModel() |
77 | { |
78 | if (m_initialized) { |
79 | qWarning() << "XrHandModel does not support changing hand" ; |
80 | return; |
81 | } |
82 | QQuick3DXrInputManager *inputMan = QQuick3DXrInputManager::instance(); |
83 | if (m_hand == RightHand) |
84 | m_handTracker = inputMan->rightHandInput(); |
85 | else if (m_hand == LeftHand) |
86 | m_handTracker = inputMan->leftHandInput(); |
87 | if (!m_handTracker) |
88 | return; |
89 | |
90 | QQuick3DXrInputManagerPrivate::get(inputManager: inputMan)->setupHandModel(this); |
91 | |
92 | connect(sender: m_handTracker, signal: &QQuick3DXrHandInput::jointDataUpdated, context: this, slot: &QQuick3DXrHandModel::updatePose); |
93 | connect(sender: m_handTracker, signal: &QQuick3DXrHandInput::isHandTrackingChanged, context: this, slot: [this](){ |
94 | setVisible(m_handTracker->isHandTrackingActive()); |
95 | }); |
96 | setVisible(m_handTracker->isActive()); |
97 | m_initialized = true; |
98 | } |
99 | |
100 | void QQuick3DXrHandModel::componentComplete() |
101 | { |
102 | setupModel(); |
103 | QQuick3DModel::componentComplete(); |
104 | } |
105 | |
106 | /*! |
107 | \qmlproperty enumeration XrHandModel::hand |
108 | \brief Specifies which hand the model is showing |
109 | |
110 | \value XrHandModel.LeftHand The left hand. |
111 | \value XrHandModel.RightHand The right hand. |
112 | \value XrHandModel.Unknown No hand is shown. |
113 | |
114 | \default XrHandModel.Unknown |
115 | |
116 | The value of this property is compatible with \l{XrController::controller}{XrController.controller}. |
117 | |
118 | \warning This property must be set when the XrHandModel is constructed. |
119 | Changing hands later is not currently supported. |
120 | */ |
121 | |
122 | QQuick3DXrHandModel::Hand QQuick3DXrHandModel::hand() const |
123 | { |
124 | return m_hand; |
125 | } |
126 | |
127 | void QQuick3DXrHandModel::setHand(Hand newHand) |
128 | { |
129 | if (m_hand == newHand) |
130 | return; |
131 | m_hand = newHand; |
132 | emit handChanged(); |
133 | } |
134 | QT_END_NAMESPACE |
135 | |