Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qquick3dxrinputmanager_visionos.mm
Go to the documentation of this file.
1// Copyright (C) 2024 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
6
8
9#include <QtQuick3DUtils/private/qssgassert_p.h>
10#include <QtQuick3DUtils/private/qssgutils_p.h>
11
12#include <QtQuick3D/private/qquick3dprincipledmaterial_p.h>
13
15
16
18 : q_ptr(&manager)
19{
20 m_handInputState[Hand::LeftHand] = new QQuick3DXrHandInput(&manager);
21 m_handInputState[Hand::RightHand] = new QQuick3DXrHandInput(&manager);
22}
23
25{
26
27}
28
30{
31 QSSG_ASSERT_X(!m_initialized, "Handtracking is already initialized!", return);
32
33 m_isHandTrackingSupported = ar_hand_tracking_provider_is_supported();
34 if (m_isHandTrackingSupported) {
35 ar_hand_tracking_configuration_t handTrackingConfiguration = ar_hand_tracking_configuration_create();
36 m_handTrackingProvider = ar_hand_tracking_provider_create(handTrackingConfiguration);
37 ar_data_providers_add_data_provider(dataProviders, m_handTrackingProvider);
38 } else {
39 qWarning("Hand tracking is not supported on this device.");
40 }
41
42 qDebug() << Q_FUNC_INFO << ", Handtracking supported: " << m_isHandTrackingSupported;
43}
44
46{
47 if (m_isHandTrackingSupported) {
48 m_handAnchors[Hand::LeftHand] = ar_hand_anchor_create();
49 m_handAnchors[Hand::RightHand] = ar_hand_anchor_create();
50 m_initialized = true;
51 }
52
53 qDebug() << Q_FUNC_INFO << ", Initialized: " << m_initialized;
54}
55
57{
59}
60
62{
63 m_handInputState[hand]->setPosePosition(position);
64}
65
67{
68 m_handInputState[hand]->setPoseRotation(rotation);
69}
70
72{
73 return m_handInputState[Hand::LeftHand];
74}
75
77{
78 return m_handInputState[Hand::RightHand];
79}
80
82{
83 return inputManager->d_func();
84}
85
87{
90}
91
92static bool setupJoint(ar_hand_skeleton_joint_name_t jointName, const ar_hand_skeleton_t handSkeleton, const simd_float4x4 handTransform, QVector3D &jointPosition, QQuaternion &jointRotation)
93{
94 bool isTracked = false;
95 ar_skeleton_joint_t joint = ar_hand_skeleton_get_joint_named(handSkeleton, jointName);
96 if (joint != nullptr) {
97 if (ar_skeleton_joint_is_tracked(joint)) {
98 simd_float4x4 jointTransform = ar_skeleton_joint_get_anchor_from_joint_transform(joint);
99 jointTransform = simd_mul(handTransform, jointTransform);
100
101 QMatrix4x4 transform{jointTransform.columns[0].x, jointTransform.columns[1].x, jointTransform.columns[2].x, jointTransform.columns[3].x,
102 jointTransform.columns[0].y, jointTransform.columns[1].y, jointTransform.columns[2].y, jointTransform.columns[3].y,
103 jointTransform.columns[0].z, jointTransform.columns[1].z, jointTransform.columns[2].z, jointTransform.columns[3].z,
104 0.0f, 0.0f, 0.0f, 1.0f};
105
106
107 QVector3D jp;
109 QQuaternion jr;
111
112 // NOTE: We need to scale the joint position by 100 to get it into the right scale (m -> cm).
113 jointPosition = jp * 100.0f;
114 jointRotation = jr;
115
116 isTracked = true;
117 }
118 }
119
120 return isTracked;
121}
122
123using HandJointList = QVarLengthArray<ar_hand_skeleton_joint_name_t, 28>;
124
126{
127 // NOTE: "Joints" are placed in the order from the forarm to the fingers (This might differ from Apple's documentation),
128 // moving from the wrist to the finger tips going from the left to the right.
129 // That means the forarm is at position 0, and the wrist is at position 1 (this is the origin).
130
131 static const HandJointList jointNames {
132 ar_hand_skeleton_joint_name_forearm_arm, // This is the forearm.
133
134 // These are technically the same joint, but depends on the orientation of the hand.
135 ar_hand_skeleton_joint_name_wrist, // This is the actual wrist.
136 ar_hand_skeleton_joint_name_forearm_wrist,
137
138 // The thumb.
139 ar_hand_skeleton_joint_name_thumb_knuckle,
140 ar_hand_skeleton_joint_name_thumb_intermediate_base,
141 ar_hand_skeleton_joint_name_thumb_intermediate_tip,
142 ar_hand_skeleton_joint_name_thumb_tip,
143
144 // The index finger.
145 ar_hand_skeleton_joint_name_index_finger_metacarpal,
146 ar_hand_skeleton_joint_name_index_finger_knuckle,
147 ar_hand_skeleton_joint_name_index_finger_intermediate_base,
148 ar_hand_skeleton_joint_name_index_finger_intermediate_tip,
149 ar_hand_skeleton_joint_name_index_finger_tip,
150
151 // The middle finger.
152 ar_hand_skeleton_joint_name_middle_finger_metacarpal,
153 ar_hand_skeleton_joint_name_middle_finger_knuckle,
154 ar_hand_skeleton_joint_name_middle_finger_intermediate_base,
155 ar_hand_skeleton_joint_name_middle_finger_intermediate_tip,
156 ar_hand_skeleton_joint_name_middle_finger_tip,
157
158 // The ring finger.
159 ar_hand_skeleton_joint_name_ring_finger_metacarpal,
160 ar_hand_skeleton_joint_name_ring_finger_knuckle,
161 ar_hand_skeleton_joint_name_ring_finger_intermediate_base,
162 ar_hand_skeleton_joint_name_ring_finger_intermediate_tip,
163 ar_hand_skeleton_joint_name_ring_finger_tip,
164
165 // The little finger.
166 ar_hand_skeleton_joint_name_little_finger_metacarpal,
167 ar_hand_skeleton_joint_name_little_finger_knuckle,
168 ar_hand_skeleton_joint_name_little_finger_intermediate_base,
169 ar_hand_skeleton_joint_name_little_finger_intermediate_tip,
170 ar_hand_skeleton_joint_name_little_finger_tip,
171 };
172
173 return jointNames;
174}
175
176static qsizetype getJointIndex(ar_hand_skeleton_joint_name_t jointName)
177{
178 qsizetype index = -1;
179 const auto &jointNames = getJointNameTable();
180 for (size_t i = 0, e = jointNames.size(); i != e && index == -1; ++i) {
181 if (jointNames[i] == jointName)
182 index = i;
183 }
184
185 return index;
186}
187
189{
190 // NOTE: Static for now...
191 static const qsizetype idx = getJointIndex(ar_hand_skeleton_joint_name_index_finger_tip);
192 return idx;
193}
194
196{
197 if (!m_isHandTrackingSupported)
198 return;
199
200 QSSG_ASSERT(m_handTrackingProvider != nullptr, return);
201 QSSG_ASSERT(m_handAnchors[Hand::LeftHand] != nullptr && m_handAnchors[Hand::RightHand] != nullptr, return);
202
203 ar_hand_tracking_provider_get_latest_anchors(m_handTrackingProvider, m_handAnchors[Hand::LeftHand], m_handAnchors[Hand::RightHand]);
204
205 // FIXME: We can and probably should cache the hand skeleton.
206 ar_hand_skeleton_t handSkeletons[2] {};
207 uint64_t handJointCount = 0;
208 for (const auto hand : { Hand::LeftHand, Hand::RightHand }) {
209 handSkeletons[hand] = ar_hand_anchor_get_hand_skeleton(m_handAnchors[hand]);
210 handJointCount = qMax(handJointCount, ar_hand_skeleton_get_joint_count(handSkeletons[hand]));
211 }
212
213 const auto &jointNames = getJointNameTable();
214 // Sanity check the joint count.
215 QSSG_CHECK(handJointCount <= size_t(jointNames.size()));
216
217 for (const auto hand : { Hand::LeftHand, Hand::RightHand }) {
218 const auto handSkeleton = handSkeletons[hand];
219 if (handSkeleton == nullptr) {
220 m_handInputState[hand]->setIsHandTracking(false);
221 continue;
222 }
223
224 // Clear cached joint data.
225 auto &jpositions = jcache[hand].positions;
226 auto &jrotations = jcache[hand].rotations;
227 jpositions.clear();
228 jrotations.clear();
229
230 // NOTE: Separate as we're just sanity checking that the wrist is tracked.
231 ar_skeleton_joint_t wristJoinOrigin = ar_hand_skeleton_get_joint_named(handSkeleton, ar_hand_skeleton_joint_name_wrist);
232 const bool isWristTracked = ar_skeleton_joint_is_tracked(wristJoinOrigin);
233
234 // The hand transform is relative to the head anchor. The wrist is at the origin of the hand anchor.
235 const simd_float4x4 handTransform = ar_anchor_get_origin_from_anchor_transform(m_handAnchors[hand]);
236
237 // Get the joint data.
238 for (auto jointName : jointNames) {
239 QVector3D jointPosition;
240 QQuaternion jointRotation;
241 if (setupJoint(jointName, handSkeleton, handTransform, jointPosition, jointRotation)) {
242 jpositions.append(jointPosition);
243 jrotations.append(jointRotation);
244 }
245 }
246
247 m_handInputState[hand]->setJointPositionsAndRotations(jpositions, jrotations);
248
249 m_handInputState[hand]->setIsActive(isWristTracked);
250 }
251}
252
The QMatrix4x4 class represents a 4x4 transformation matrix in 3D space.
Definition qmatrix4x4.h:25
The QQuaternion class represents a quaternion consisting of a vector and scalar.
void setIsActive(bool isActive)
void setPoseRotation(const QQuaternion &rotation)
void setJointPositionsAndRotations(const QList< QVector3D > &newJointPositions, const QList< QQuaternion > &newJointRotations)
void setPosePosition(const QVector3D &position)
QQuick3DXrInputManagerPrivate(QQuick3DXrInputManager &manager)
void prepareHandtracking(ar_data_providers_t dataProviders)
QQuick3DXrHandInput * rightHandInput() const
static QQuick3DXrInputManagerPrivate * get(QQuick3DXrInputManager *inputManager)
void setPosePosition(Hand hand, const QVector3D &position)
void setPoseRotation(Hand hand, const QQuaternion &rotation)
void setupHandModel(QQuick3DXrHandModel *model)
QQuick3DXrHandInput * leftHandInput() const
The QVector3D class represents a vector or vertex in 3D space.
Definition qvectornd.h:171
bool Q_QUICK3DUTILS_EXPORT decompose(const QMatrix4x4 &m, QVector3D &position, QVector3D &scale, QQuaternion &rotation)
Combined button and popup list for selecting options.
#define Q_FUNC_INFO
#define qDebug
[1]
Definition qlogging.h:165
#define qWarning
Definition qlogging.h:167
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:21
GLuint index
[2]
GLuint GLenum GLenum transform
GLenum GLenum GLenum GLenum GLenum scale
static bool setupJoint(ar_hand_skeleton_joint_name_t jointName, const ar_hand_skeleton_t handSkeleton, const simd_float4x4 handTransform, QVector3D &jointPosition, QQuaternion &jointRotation)
static qsizetype getJointIndex(ar_hand_skeleton_joint_name_t jointName)
const HandJointList & getJointNameTable()
QVarLengthArray< ar_hand_skeleton_joint_name_t, 28 > HandJointList
struct ar_data_providers_s * ar_data_providers_t
static qreal position(const QQuickItem *item, QQuickAnchors::Anchor anchorLine)
#define QSSG_ASSERT_X(cond, msg, action)
#define QSSG_CHECK(cond)
#define QSSG_ASSERT(cond, action)
#define Q_UNIMPLEMENTED()
#define Q_UNUSED(x)
ptrdiff_t qsizetype
Definition qtypes.h:165
QSqlQueryModel * model
[16]
QNetworkAccessManager manager