Vulkan Schnee 0.0.1
High-performance rendering engine
Loading...
Searching...
No Matches
XrInputHandler.cpp
Go to the documentation of this file.
2
6#include <cstring>
7
8namespace Input {
9
10#define LEFT_HAND_IMPLEMENTATION(className, varName, pathValue) \
11 const std::string className::l_##varName = ActionProfileBase::handLeft + pathValue;
12
13#define RIGHT_HAND_IMPLEMENTATION(className, varName, pathValue) \
14 const std::string className::r_##varName = ActionProfileBase::handRight + pathValue;
15
16#define BOTH_HAND_IMPLEMENTATION(className, varName, pathValue) \
17 LEFT_HAND_IMPLEMENTATION(className, varName, pathValue) \
18 RIGHT_HAND_IMPLEMENTATION(className, varName, pathValue)
19
20 // hand paths
21 const std::string ActionProfileBase::handLeft = "/user/hand/left";
22 const std::string ActionProfileBase::handRight = "/user/hand/right";
23
24 // base profile paths
25 const std::string ActionProfileBase::ActionProfiles::simpleControllerInteractionProfile = "/interaction_profiles/khr/simple_controller";
26 const std::string ActionProfileBase::ActionProfiles::oculusTouchInteractionProfile = "/interaction_profiles/oculus/touch_controller";
27
28
30
35
36 BOTH_HAND_IMPLEMENTATION(ActionProfileSimpleController, select_click, "/input/select/click");
37 BOTH_HAND_IMPLEMENTATION(ActionProfileSimpleController, menu_click, "/input/menu/click");
38 BOTH_HAND_IMPLEMENTATION(ActionProfileSimpleController, grip_pose, "/input/grip/pose");
39 BOTH_HAND_IMPLEMENTATION(ActionProfileSimpleController, aim_pose, "/input/aim/pose");
40
42
47
48 // Left hand implementations
53 LEFT_HAND_IMPLEMENTATION(ActionProfileOculusTouchController, menu_click, "/input/menu/click");
54
55 // Right hand implementations
60 RIGHT_HAND_IMPLEMENTATION(ActionProfileOculusTouchController, system_click, "/input/system/click");
61
62 // Both hands implementations
63 BOTH_HAND_IMPLEMENTATION(ActionProfileOculusTouchController, squeeze_value, "/input/squeeze/value");
64 BOTH_HAND_IMPLEMENTATION(ActionProfileOculusTouchController, trigger_value, "/input/trigger/value");
65 BOTH_HAND_IMPLEMENTATION(ActionProfileOculusTouchController, trigger_touch, "/input/trigger/touch");
66 BOTH_HAND_IMPLEMENTATION(ActionProfileOculusTouchController, trigger_proximity, "/input/trigger/proximity");
67 BOTH_HAND_IMPLEMENTATION(ActionProfileOculusTouchController, thumb_resting_surfaces_proximity, "/input/thumb_resting_surfaces/proximity");
68 BOTH_HAND_IMPLEMENTATION(ActionProfileOculusTouchController, thumbstick_click, "/input/thumbstick/click");
69 BOTH_HAND_IMPLEMENTATION(ActionProfileOculusTouchController, thumbstick_touch, "/input/thumbstick/touch");
70 BOTH_HAND_IMPLEMENTATION(ActionProfileOculusTouchController, thumbrest_touch, "/input/thumbrest/touch");
73
74 // Output (haptic) for both hands
76
78 {
79#ifdef ENABLE_TRACY
81#endif
83
84 {
85 handPoseInfos.resize(2);
86
87 XrPath& leftHandPath = handPoseInfos.at(static_cast<uint32_t>(Hand::LEFT)).handPath;
88 XrPath& rightHandPath = handPoseInfos.at(static_cast<uint32_t>(Hand::RIGHT)).handPath;
89
90 xrStringToPath(context->getXrInstance(), "/user/hand/left", &leftHandPath);
91 xrStringToPath(context->getXrInstance(), "/user/hand/right", &rightHandPath);
92 handPaths = { leftHandPath , rightHandPath };
93 }
94 {
95 XrActionSetCreateInfo actionSetCreateInfo{ XR_TYPE_ACTION_SET_CREATE_INFO };
96 strcpy(actionSetCreateInfo.actionSetName, "actionset");
97 strcpy(actionSetCreateInfo.localizedActionSetName, "Actions");
98 actionSetCreateInfo.priority = 0;
99
100 PLOG_THROW_FN_XR(xrCreateActionSet(context->getXrInstance(), &actionSetCreateInfo, &defaultActionSet));
101 }
102 {
103 XrActionCreateInfo poseActionCreateInfo{ XR_TYPE_ACTION_CREATE_INFO };
104 strcpy(poseActionCreateInfo.actionName, "handpose");
105 strcpy(poseActionCreateInfo.localizedActionName, "Hand Pose");
106 poseActionCreateInfo.actionType = XR_ACTION_TYPE_POSE_INPUT;
107 poseActionCreateInfo.countSubactionPaths = static_cast<uint32_t>(handPaths.size());
108 poseActionCreateInfo.subactionPaths = handPaths.data();
109
110 PLOG_THROW_FN_XR(xrCreateAction(defaultActionSet, &poseActionCreateInfo, &aimPoseAction));
111 }
112 // Create thumbstick action (vec2, both hands)
113 {
114 XrActionCreateInfo thumbstickCreateInfo{ XR_TYPE_ACTION_CREATE_INFO };
115 strcpy(thumbstickCreateInfo.actionName, "thumbstick");
116 strcpy(thumbstickCreateInfo.localizedActionName, "Thumbstick");
117 thumbstickCreateInfo.actionType = XR_ACTION_TYPE_VECTOR2F_INPUT;
118 thumbstickCreateInfo.countSubactionPaths = static_cast<uint32_t>(handPaths.size());
119 thumbstickCreateInfo.subactionPaths = handPaths.data();
120
121 PLOG_THROW_FN_XR(xrCreateAction(defaultActionSet, &thumbstickCreateInfo, &thumbstickAction_));
122 }
123 // Create trigger action (float, both hands)
124 {
125 XrActionCreateInfo triggerCreateInfo{ XR_TYPE_ACTION_CREATE_INFO };
126 strcpy(triggerCreateInfo.actionName, "trigger");
127 strcpy(triggerCreateInfo.localizedActionName, "Trigger");
128 triggerCreateInfo.actionType = XR_ACTION_TYPE_FLOAT_INPUT;
129 triggerCreateInfo.countSubactionPaths = static_cast<uint32_t>(handPaths.size());
130 triggerCreateInfo.subactionPaths = handPaths.data();
131
132 PLOG_THROW_FN_XR(xrCreateAction(defaultActionSet, &triggerCreateInfo, &triggerAction_));
133 }
134 // Create grip/squeeze action (float, both hands)
135 {
136 XrActionCreateInfo gripCreateInfo{ XR_TYPE_ACTION_CREATE_INFO };
137 strcpy(gripCreateInfo.actionName, "grip");
138 strcpy(gripCreateInfo.localizedActionName, "Grip");
139 gripCreateInfo.actionType = XR_ACTION_TYPE_FLOAT_INPUT;
140 gripCreateInfo.countSubactionPaths = static_cast<uint32_t>(handPaths.size());
141 gripCreateInfo.subactionPaths = handPaths.data();
142
143 PLOG_THROW_FN_XR(xrCreateAction(defaultActionSet, &gripCreateInfo, &gripAction_));
144 }
145 {
146 constexpr XrVector3f defaultVector3f = { 0.0f, 0.0f, 0.0f };
147 constexpr XrVector2f defaultVector2f = { 0.0f, 0.0f };
148 constexpr XrQuaternionf defaultQuat = { 0.0f, 0.0f, 0.0f, 1.0f };
149
150 for (HandPoseInfo& handPoseInfo : handPoseInfos) {
151 XrActionSpaceCreateInfo handPoseActionSpaceCreateInfo{ XR_TYPE_ACTION_SPACE_CREATE_INFO };
152 handPoseActionSpaceCreateInfo.action = aimPoseAction;
153 handPoseActionSpaceCreateInfo.poseInActionSpace.position = defaultVector3f;
154 handPoseActionSpaceCreateInfo.poseInActionSpace.orientation = defaultQuat;
155 handPoseActionSpaceCreateInfo.subactionPath = handPoseInfo.handPath;
156 PLOG_FN_XR(xrCreateActionSpace(headset->getSession(), &handPoseActionSpaceCreateInfo, &handPoseInfo.space));
157 }
158 }
159 // Suggest bindings for simple controller profile (fallback)
160 {
161 XrPath aimPoseLeftHandPath = {};
162 PLOG_FN_XR(xrStringToPath(context->getXrInstance(), "/user/hand/left/input/aim/pose", &aimPoseLeftHandPath));
163
164 XrPath aimPoseRightHandPath = {};
165 PLOG_FN_XR(xrStringToPath(context->getXrInstance(), "/user/hand/right/input/aim/pose", &aimPoseRightHandPath));
166
167 std::vector<XrActionSuggestedBinding> actionBindings = {
168 { aimPoseAction, aimPoseLeftHandPath },
169 { aimPoseAction, aimPoseRightHandPath }
170 };
171
172 XrPath interactionProfilePath;
173 PLOG_FN_XR(xrStringToPath(context->getXrInstance(), ActionProfileSimpleController::actionProfile.c_str(), &interactionProfilePath));
174
175 XrInteractionProfileSuggestedBinding suggestedBindings{ XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING };
176 suggestedBindings.interactionProfile = interactionProfilePath;
177 suggestedBindings.countSuggestedBindings = static_cast<uint32_t>(actionBindings.size());
178 suggestedBindings.suggestedBindings = actionBindings.data();
179
180 PLOG_FN_XR(xrSuggestInteractionProfileBindings(context->getXrInstance(), &suggestedBindings));
181 }
182 // Suggest bindings for Oculus Touch controllers
183 {
184 XrPath aimPoseLeftPath, aimPoseRightPath;
185 XrPath thumbstickLeftPath, thumbstickRightPath;
186 XrPath triggerLeftPath, triggerRightPath;
187 XrPath gripLeftPath, gripRightPath;
188
189 PLOG_FN_XR(xrStringToPath(context->getXrInstance(), "/user/hand/left/input/aim/pose", &aimPoseLeftPath));
190 PLOG_FN_XR(xrStringToPath(context->getXrInstance(), "/user/hand/right/input/aim/pose", &aimPoseRightPath));
191 PLOG_FN_XR(xrStringToPath(context->getXrInstance(), "/user/hand/left/input/thumbstick", &thumbstickLeftPath));
192 PLOG_FN_XR(xrStringToPath(context->getXrInstance(), "/user/hand/right/input/thumbstick", &thumbstickRightPath));
193 PLOG_FN_XR(xrStringToPath(context->getXrInstance(), "/user/hand/left/input/trigger/value", &triggerLeftPath));
194 PLOG_FN_XR(xrStringToPath(context->getXrInstance(), "/user/hand/right/input/trigger/value", &triggerRightPath));
195 PLOG_FN_XR(xrStringToPath(context->getXrInstance(), "/user/hand/left/input/squeeze/value", &gripLeftPath));
196 PLOG_FN_XR(xrStringToPath(context->getXrInstance(), "/user/hand/right/input/squeeze/value", &gripRightPath));
197
198 std::vector<XrActionSuggestedBinding> oculusBindings = {
199 { aimPoseAction, aimPoseLeftPath },
200 { aimPoseAction, aimPoseRightPath },
201 { thumbstickAction_, thumbstickLeftPath },
202 { thumbstickAction_, thumbstickRightPath },
203 { triggerAction_, triggerLeftPath },
204 { triggerAction_, triggerRightPath },
205 { gripAction_, gripLeftPath },
206 { gripAction_, gripRightPath }
207 };
208
209 XrPath oculusProfilePath;
210 PLOG_FN_XR(xrStringToPath(context->getXrInstance(), ActionProfileOculusTouchController::actionProfile.c_str(), &oculusProfilePath));
211
212 XrInteractionProfileSuggestedBinding oculusSuggestedBindings{ XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING };
213 oculusSuggestedBindings.interactionProfile = oculusProfilePath;
214 oculusSuggestedBindings.countSuggestedBindings = static_cast<uint32_t>(oculusBindings.size());
215 oculusSuggestedBindings.suggestedBindings = oculusBindings.data();
216
217 PLOG_FN_XR(xrSuggestInteractionProfileBindings(context->getXrInstance(), &oculusSuggestedBindings));
218 }
219 {
220 XrSessionActionSetsAttachInfo attachInfo{ XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO };
221 attachInfo.countActionSets = 1;
222 attachInfo.actionSets = &defaultActionSet;
223 PLOG_FN_XR(xrAttachSessionActionSets(headset->getSession(), &attachInfo));
224 }
225
226 PLOGI << "Finished xr input handler setup";
227 }
228
229 void XrInputHandler::syncInputs(XrSpace playerSpace, XrTime predictedDisplayTime)
230 {
231 XrSession xrSession = headset->getSession();
232
233 const XrActiveActionSet activeActionSet{ defaultActionSet, XR_NULL_PATH };
234 XrActionsSyncInfo syncInfo{ XR_TYPE_ACTIONS_SYNC_INFO };
235 syncInfo.countActiveActionSets = 1;
236 syncInfo.activeActionSets = &activeActionSet;
237 xrSyncActions(xrSession, &syncInfo);
238
239 // Sync hand poses
240 for (size_t i = 0; i < handPoseInfos.size(); ++i) {
241 HandPoseInfo& handPoseInfo = handPoseInfos[i];
242
243 XrActionStateGetInfo actionStateGetInfo{ XR_TYPE_ACTION_STATE_GET_INFO };
244 actionStateGetInfo.action = aimPoseAction;
245 actionStateGetInfo.subactionPath = handPoseInfo.handPath;
246
247 XrActionStatePose aimPoseState{ XR_TYPE_ACTION_STATE_POSE };
248 PLOG_THROW_FN_XR(xrGetActionStatePose(xrSession, &actionStateGetInfo, &aimPoseState));
249
250 if (aimPoseState.isActive) {
251 XrSpaceLocation spaceLocation{ XR_TYPE_SPACE_LOCATION };
252 PLOG_THROW_FN_XR(xrLocateSpace(handPoseInfo.space, playerSpace, predictedDisplayTime, &spaceLocation));
253
254 constexpr XrSpaceLocationFlags checkFlags =
255 XR_SPACE_LOCATION_POSITION_VALID_BIT | XR_SPACE_LOCATION_POSITION_TRACKED_BIT |
256 XR_SPACE_LOCATION_ORIENTATION_VALID_BIT | XR_SPACE_LOCATION_ORIENTATION_TRACKED_BIT;
257
258 if ((spaceLocation.locationFlags & checkFlags) == checkFlags) {
259 handPoseInfo.matrix = EngineCore::OpenXrHelper::poseToMatrix(spaceLocation.pose);
260 handPoseInfo.handPose = EngineCore::OpenXrHelper::xrPosefToGlmPosef(spaceLocation.pose);
261 }
262 }
263
264 // Sync thumbstick for this hand
265 {
266 XrActionStateGetInfo thumbstickGetInfo{ XR_TYPE_ACTION_STATE_GET_INFO };
267 thumbstickGetInfo.action = thumbstickAction_;
268 thumbstickGetInfo.subactionPath = handPoseInfo.handPath;
269
270 XrActionStateVector2f thumbstickState{ XR_TYPE_ACTION_STATE_VECTOR2F };
271 if (xrGetActionStateVector2f(xrSession, &thumbstickGetInfo, &thumbstickState) == XR_SUCCESS) {
272 if (thumbstickState.isActive) {
273 glm::vec2 value(thumbstickState.currentState.x, thumbstickState.currentState.y);
274 if (i == static_cast<size_t>(Hand::LEFT)) {
275 leftThumbstick_ = value;
276 } else {
277 rightThumbstick_ = value;
278 }
279 }
280 }
281 }
282
283 // Sync trigger for this hand
284 {
285 XrActionStateGetInfo triggerGetInfo{ XR_TYPE_ACTION_STATE_GET_INFO };
286 triggerGetInfo.action = triggerAction_;
287 triggerGetInfo.subactionPath = handPoseInfo.handPath;
288
289 XrActionStateFloat triggerState{ XR_TYPE_ACTION_STATE_FLOAT };
290 if (xrGetActionStateFloat(xrSession, &triggerGetInfo, &triggerState) == XR_SUCCESS) {
291 if (triggerState.isActive) {
292 triggerValues_[i] = triggerState.currentState;
293 }
294 }
295 }
296
297 // Sync grip for this hand
298 {
299 XrActionStateGetInfo gripGetInfo{ XR_TYPE_ACTION_STATE_GET_INFO };
300 gripGetInfo.action = gripAction_;
301 gripGetInfo.subactionPath = handPoseInfo.handPath;
302
303 XrActionStateFloat gripState{ XR_TYPE_ACTION_STATE_FLOAT };
304 if (xrGetActionStateFloat(xrSession, &gripGetInfo, &gripState) == XR_SUCCESS) {
305 if (gripState.isActive) {
306 gripValues_[i] = gripState.currentState;
307 }
308 }
309 }
310 }
311 }
312
317
322
324 {
325 return handPoseInfos.at(static_cast<uint32_t>(hand));
326 }
327
329 {
330 return triggerValues_[static_cast<size_t>(hand)];
331 }
332
334 {
335 return gripValues_[static_cast<size_t>(hand)];
336 }
337
338}
#define TRACY_ZONE_SCOPED_FUNCTION
#define RIGHT_HAND_IMPLEMENTATION(className, varName, pathValue)
#define BOTH_HAND_IMPLEMENTATION(className, varName, pathValue)
#define LEFT_HAND_IMPLEMENTATION(className, varName, pathValue)
The application context is the core class which stores the basic openxr and vulkan objects.
EngineCore::Engine * getEngineModule()
gets the pointer to the engine object
Definition Engine.cpp:1140
static EngineManager & getInstance()
gets a reference to the engine manager
Definition Engine.cpp:1135
static posef xrPosefToGlmPosef(const XrPosef &xrPosef)
static glm::mat4 poseToMatrix(const XrPosef &pose)
Converts an XrPosef to a glm::mat4.
static const std::string handRight
static const std::string handLeft
Input mapping implementation for oculus touch devices.
The minimal input mapping implementation provided by open xr which should be supported on any openxr ...
static const std::string actionProfile
const EngineCore::Headset * headset
HandPoseInfo getHandPoseInfo(Hand hand) const
float getTriggerValue(Hand hand) const
Gets the trigger value for the specified hand (0.0 to 1.0)
float getGripValue(Hand hand) const
Gets the grip/squeeze value for the specified hand (0.0 to 1.0)
EngineCore::Engine * engine
std::vector< XrPath > handPaths
const EngineCore::ApplicationContext * context
XrInputHandler(const EngineCore::Headset *headset, const EngineCore::ApplicationContext *context)
void syncInputs(XrSpace playerSpace, XrTime predictedDisplayTime)
std::vector< HandPoseInfo > handPoseInfos
static const std::string simpleControllerInteractionProfile
static const std::string oculusTouchInteractionProfile
EngineCore::OpenXrHelper::posef handPose