OpenXRVkInput.cpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <OpenXRVk/OpenXRVkInput.h>
  9. #include <OpenXRVk/OpenXRVkInstance.h>
  10. #include <OpenXRVk/OpenXRVkSession.h>
  11. #include <OpenXRVk/OpenXRVkDevice.h>
  12. #include <OpenXRVk/OpenXRVkSpace.h>
  13. #include <OpenXRVk/OpenXRVkUtils.h>
  14. #include <AzCore/Casting/numeric_cast.h>
  15. #include <Atom/RPI.Public/XR/XRSpaceNotificationBus.h>
  16. namespace OpenXRVk
  17. {
  18. XR::Ptr<Input> Input::Create()
  19. {
  20. const auto newInput = aznew Input;
  21. newInput->m_xrController.SetImplementation(&AzFramework::InputDeviceXRController::Implementation::Create);
  22. newInput->m_xrControllerImpl = newInput->m_xrController.GetImplementation();
  23. return newInput;
  24. }
  25. AZ::RHI::ResultCode Input::InitInternal()
  26. {
  27. const auto xrVkInstance = static_cast<Instance*>(GetDescriptor().m_instance.get());
  28. const XrInstance xrInstance = xrVkInstance->GetXRInstance();
  29. // Create an action set.
  30. CreateActionSet(xrInstance);
  31. // Create all the XrActions
  32. CreateAllActions(xrInstance);
  33. // Bindings for the Oculus Touch.
  34. XrPath oculusTouchInteractionProfilePath;
  35. AZStd::string controllerProfilePath{ m_xrControllerImpl->GetInputDeviceProfilePath() };
  36. [[maybe_unused]] XrResult result = xrStringToPath(xrInstance, controllerProfilePath.data(), &oculusTouchInteractionProfilePath);
  37. WARN_IF_UNSUCCESSFUL(result);
  38. XrInteractionProfileSuggestedBinding suggestedBindings{};
  39. suggestedBindings.type = XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING;
  40. suggestedBindings.interactionProfile = oculusTouchInteractionProfilePath;
  41. suggestedBindings.suggestedBindings = m_xrActionPaths.data();
  42. suggestedBindings.countSuggestedBindings = aznumeric_cast<AZ::u32>(m_xrActionPaths.size());
  43. result = xrSuggestInteractionProfileBindings(xrInstance, &suggestedBindings);
  44. WARN_IF_UNSUCCESSFUL(result);
  45. //Init the location data so we dont read bad data when the device is in a bad state at start
  46. for (int i = 0; i < AZ::RPI::XRMaxNumControllers; i++)
  47. {
  48. m_handSpaceLocation[i].pose.orientation.x = 0.0f;
  49. m_handSpaceLocation[i].pose.orientation.y = 0.0f;
  50. m_handSpaceLocation[i].pose.orientation.z = 0.0f;
  51. m_handSpaceLocation[i].pose.orientation.w = 0.0f;
  52. m_handSpaceLocation[i].pose.position.x = 0.0f;
  53. m_handSpaceLocation[i].pose.position.y = 0.0f;
  54. m_handSpaceLocation[i].pose.position.z = 0.0f;
  55. }
  56. for (int i = 0; i < SpaceType::Count; i++)
  57. {
  58. m_xrVisualizedSpaceLocations[i].pose.orientation.x = 0.0f;
  59. m_xrVisualizedSpaceLocations[i].pose.orientation.y = 0.0f;
  60. m_xrVisualizedSpaceLocations[i].pose.orientation.z = 0.0f;
  61. m_xrVisualizedSpaceLocations[i].pose.orientation.w = 0.0f;
  62. m_xrVisualizedSpaceLocations[i].pose.position.x = 0.0f;
  63. m_xrVisualizedSpaceLocations[i].pose.position.y = 0.0f;
  64. m_xrVisualizedSpaceLocations[i].pose.position.z = 0.0f;
  65. }
  66. return ConvertResult(result);
  67. }
  68. void Input::CreateAction(XrAction& action, XrActionType actionType,
  69. const char* actionName, const char* localizedActionName,
  70. uint32_t countSubactionPathCount, const XrPath* subActionPaths) const
  71. {
  72. XrActionCreateInfo actionInfo{};
  73. actionInfo.type = XR_TYPE_ACTION_CREATE_INFO;
  74. actionInfo.actionType = actionType;
  75. azstrcpy(actionInfo.actionName, sizeof(actionInfo.actionName), actionName);
  76. azstrcpy(actionInfo.localizedActionName, sizeof(actionInfo.localizedActionName), localizedActionName);
  77. actionInfo.countSubactionPaths = countSubactionPathCount;
  78. actionInfo.subactionPaths = subActionPaths;
  79. [[maybe_unused]] const XrResult result = xrCreateAction(m_actionSet, &actionInfo, &action);
  80. WARN_IF_UNSUCCESSFUL(result);
  81. }
  82. void Input::CreateActionSet(const XrInstance& xrInstance)
  83. {
  84. // Create an action set.
  85. XrActionSetCreateInfo actionSetInfo{};
  86. actionSetInfo.type = XR_TYPE_ACTION_SET_CREATE_INFO;
  87. azstrcpy(actionSetInfo.actionSetName, sizeof(actionSetInfo.actionSetName), "gameplay");
  88. azstrcpy(actionSetInfo.localizedActionSetName, sizeof(actionSetInfo.localizedActionSetName), "Gameplay");
  89. actionSetInfo.priority = 0;
  90. [[maybe_unused]] const XrResult result = xrCreateActionSet(xrInstance, &actionSetInfo, &m_actionSet);
  91. WARN_IF_UNSUCCESSFUL(result);
  92. }
  93. void Input::CreateAllActions(const XrInstance& xrInstance)
  94. {
  95. // Get the XrPath for the left and right hands - we will use them as subaction paths.
  96. const AZStd::string leftHandPath{ m_xrControllerImpl->GetLeftHandSubPath() };
  97. const AZStd::string rightHandPath{ m_xrControllerImpl->GetRightHandSubPath() };
  98. XrResult result = xrStringToPath(xrInstance, leftHandPath.data(), &m_handSubactionPath[static_cast<uint32_t>(XR::Side::Left)]);
  99. WARN_IF_UNSUCCESSFUL(result);
  100. result = xrStringToPath(xrInstance, rightHandPath.data(), &m_handSubactionPath[static_cast<uint32_t>(XR::Side::Right)]);
  101. WARN_IF_UNSUCCESSFUL(result);
  102. // Lambda to create an action and path, store them in m_xrActionPaths
  103. using namespace AzFramework;
  104. auto createXrAction = [this, &xrInstance](const InputChannelId& channelId, const XrActionType actionType)
  105. {
  106. m_xrActionIndices[channelId] = m_xrActionPaths.size();
  107. m_xrActionPaths.push_back({});
  108. CreateAction(m_xrActionPaths.back().action, actionType, channelId.GetName(), channelId.GetName(),
  109. aznumeric_cast<AZ::u32>(AZStd::size(m_handSubactionPath)), m_handSubactionPath.data());
  110. const AZStd::string xrPathStr{ m_xrControllerImpl->GetInputChannelPath(channelId) };
  111. [[maybe_unused]] const XrResult pathResult = xrStringToPath(xrInstance, xrPathStr.data(), &m_xrActionPaths.back().binding);
  112. WARN_IF_UNSUCCESSFUL(pathResult);
  113. };
  114. for (const InputChannelId& channelId : InputDeviceXRController::Button::All)
  115. {
  116. createXrAction(channelId, XR_ACTION_TYPE_BOOLEAN_INPUT);
  117. }
  118. for (const InputChannelId& channelId : InputDeviceXRController::Trigger::All)
  119. {
  120. createXrAction(channelId, XR_ACTION_TYPE_FLOAT_INPUT);
  121. }
  122. for (const InputChannelId& channelId : InputDeviceXRController::ThumbStickAxis1D::All)
  123. {
  124. createXrAction(channelId, XR_ACTION_TYPE_FLOAT_INPUT);
  125. }
  126. for (const InputChannelId& channelId : InputDeviceXRController::ControllerPosePosition::All)
  127. {
  128. createXrAction(channelId, XR_ACTION_TYPE_POSE_INPUT);
  129. }
  130. for (const InputChannelId& channelId : InputDeviceXRController::ControllerPoseOrientation::All)
  131. {
  132. createXrAction(channelId, XR_ACTION_TYPE_POSE_INPUT); // is this correct?
  133. }
  134. m_xrControllerImpl->RegisterTickCallback([this](){ PollActions(); });
  135. }
  136. AZ::RHI::ResultCode Input::InitializeActionSpace(XrSession xrSession)
  137. {
  138. XrActionSpaceCreateInfo actionSpaceInfo{};
  139. actionSpaceInfo.type = XR_TYPE_ACTION_SPACE_CREATE_INFO;
  140. actionSpaceInfo.action = GetAction(AzFramework::InputDeviceXRController::ControllerPosePosition::LPos);
  141. actionSpaceInfo.poseInActionSpace.orientation.w = 1.f;
  142. actionSpaceInfo.subactionPath = m_handSubactionPath[static_cast<uint32_t>(XR::Side::Left)];
  143. XrResult result = xrCreateActionSpace(xrSession, &actionSpaceInfo, &m_handSpace[static_cast<uint32_t>(XR::Side::Left)]);
  144. WARN_IF_UNSUCCESSFUL(result);
  145. RETURN_RESULTCODE_IF_UNSUCCESSFUL(ConvertResult(result));
  146. actionSpaceInfo.action = GetAction(AzFramework::InputDeviceXRController::ControllerPosePosition::RPos);
  147. actionSpaceInfo.subactionPath = m_handSubactionPath[static_cast<uint32_t>(XR::Side::Right)];
  148. result = xrCreateActionSpace(xrSession, &actionSpaceInfo, &m_handSpace[static_cast<uint32_t>(XR::Side::Right)]);
  149. WARN_IF_UNSUCCESSFUL(result);
  150. return ConvertResult(result);
  151. }
  152. AZ::RHI::ResultCode Input::InitializeActionSets(XrSession xrSession) const
  153. {
  154. XrSessionActionSetsAttachInfo attachInfo{};
  155. attachInfo.type = XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO;
  156. attachInfo.countActionSets = 1;
  157. attachInfo.actionSets = &m_actionSet;
  158. const XrResult result = xrAttachSessionActionSets(xrSession, &attachInfo);
  159. WARN_IF_UNSUCCESSFUL(result);
  160. return ConvertResult(result);
  161. }
  162. void Input::ShutdownInternal()
  163. {
  164. if (m_actionSet != XR_NULL_HANDLE)
  165. {
  166. for (const auto hand : { XR::Side::Left, XR::Side::Right })
  167. {
  168. xrDestroySpace(m_handSpace[static_cast<AZ::u32>(hand)]);
  169. }
  170. xrDestroyActionSet(m_actionSet);
  171. }
  172. // Turn off the tick callback and reset the (non-owning) impl pointer back to null
  173. m_xrControllerImpl->RegisterTickCallback(nullptr);
  174. m_xrControllerImpl = nullptr;
  175. }
  176. XrAction Input::GetAction(const AzFramework::InputChannelId& channelId) const
  177. {
  178. // this is a private function and only input channel ids that were used to
  179. // initialize structures in this class should be passed.
  180. // "at" will assert if the channelId is something unexpected for xr controller
  181. const auto index = m_xrActionIndices.at(channelId);
  182. return m_xrActionPaths[index].action;
  183. }
  184. void Input::PollActions()
  185. {
  186. const auto session = static_cast<Session*>(GetDescriptor().m_session.get());
  187. XrSession xrSession = session->GetXrSession();
  188. m_handActive = { XR_FALSE, XR_FALSE };
  189. auto& rawControllerData = m_xrControllerImpl->GetRawState();
  190. // Might not need to reset if we're constantly refreshing all raw values.
  191. // In the future we may want to store off a couple ticks of data in a history
  192. // so that derivatives and edge detection can be computed.
  193. rawControllerData.Reset();
  194. // Sync actions
  195. const XrActiveActionSet activeActionSet{ m_actionSet, XR_NULL_PATH };
  196. XrActionsSyncInfo syncInfo{};
  197. syncInfo.type = XR_TYPE_ACTIONS_SYNC_INFO;
  198. syncInfo.countActiveActionSets = 1;
  199. syncInfo.activeActionSets = &activeActionSet;
  200. XrResult result = xrSyncActions(xrSession, &syncInfo);
  201. if (result != XR_SUCCESS)
  202. {
  203. // This will hit when the device gets put down / goes idle.
  204. // So to avoid spam, just return here.
  205. return;
  206. }
  207. using namespace AzFramework;
  208. using xrc = InputDeviceXRController;
  209. // Updating digital buttons is somewhat unique, because it compacts and combines them all to a u32 with bit masks...
  210. for (const auto& [channelId, bitMask] : rawControllerData.m_buttonIdsToBitMasks)
  211. {
  212. XrActionStateGetInfo getButtonInfo{};
  213. getButtonInfo.type = XR_TYPE_ACTION_STATE_GET_INFO;
  214. getButtonInfo.next = nullptr;
  215. getButtonInfo.action = GetAction(channelId);
  216. getButtonInfo.subactionPath = XR_NULL_PATH;
  217. XrActionStateBoolean buttonValue{};
  218. buttonValue.type = XR_TYPE_ACTION_STATE_BOOLEAN;
  219. result = xrGetActionStateBoolean(xrSession, &getButtonInfo, &buttonValue);
  220. WARN_IF_UNSUCCESSFUL(result);
  221. rawControllerData.m_digitalButtonStates |= (
  222. (buttonValue.isActive == XR_TRUE && buttonValue.currentState == XR_TRUE)
  223. ? bitMask
  224. : 0
  225. );
  226. }
  227. // lambda that obtains a float state from an action...
  228. auto getActionStateFloat = [&xrSession, this](const InputChannelId& channelId) -> float
  229. {
  230. XrActionStateGetInfo getAnalogInfo{};
  231. getAnalogInfo.type = XR_TYPE_ACTION_STATE_GET_INFO;
  232. getAnalogInfo.next = nullptr;
  233. getAnalogInfo.action = GetAction(channelId);
  234. getAnalogInfo.subactionPath = XR_NULL_PATH;
  235. XrActionStateFloat analogValue{};
  236. analogValue.type = XR_TYPE_ACTION_STATE_FLOAT;
  237. const XrResult result = xrGetActionStateFloat(xrSession, &getAnalogInfo, &analogValue);
  238. WARN_IF_UNSUCCESSFUL(result);
  239. if (analogValue.isActive == XR_TRUE)
  240. {
  241. return analogValue.currentState;
  242. }
  243. return 0.f;
  244. };
  245. // Update Analog values...
  246. rawControllerData.m_leftTriggerState = getActionStateFloat(xrc::Trigger::LTrigger);
  247. rawControllerData.m_rightTriggerState = getActionStateFloat(xrc::Trigger::RTrigger);
  248. rawControllerData.m_leftGripState = getActionStateFloat(xrc::Trigger::LGrip);
  249. rawControllerData.m_rightGripState = getActionStateFloat(xrc::Trigger::RGrip);
  250. rawControllerData.m_leftThumbStickXState = getActionStateFloat(xrc::ThumbStickAxis1D::LX);
  251. rawControllerData.m_leftThumbStickYState = getActionStateFloat(xrc::ThumbStickAxis1D::LY);
  252. rawControllerData.m_rightThumbStickXState = getActionStateFloat(xrc::ThumbStickAxis1D::RX);
  253. rawControllerData.m_rightThumbStickYState = getActionStateFloat(xrc::ThumbStickAxis1D::RY);
  254. // Scale the rendered hand by 1.0f (open) to 0.5f (fully squeezed).
  255. m_handScale[static_cast<AZ::u32>(XR::Side::Left)] = 1.f - 0.5f * rawControllerData.m_leftGripState;
  256. m_handScale[static_cast<AZ::u32>(XR::Side::Right)] = 1.f - 0.5f * rawControllerData.m_rightGripState;
  257. // lambda that outputs vibration amount to a particular side
  258. auto setHapticVibration = [this, &xrSession](AZ::u32 side, float amount)
  259. {
  260. if (amount > 0.f)
  261. {
  262. XrHapticVibration hapticVibration{};
  263. hapticVibration.type = XR_TYPE_HAPTIC_VIBRATION;
  264. hapticVibration.amplitude = amount;
  265. hapticVibration.duration = XR_MIN_HAPTIC_DURATION;
  266. hapticVibration.frequency = XR_FREQUENCY_UNSPECIFIED;
  267. XrHapticActionInfo hapticActionInfo{};
  268. hapticActionInfo.type = XR_TYPE_HAPTIC_ACTION_INFO;
  269. hapticActionInfo.action = m_hapticAction;
  270. hapticActionInfo.subactionPath = m_handSubactionPath[side];
  271. [[maybe_unused]] const XrResult result = xrApplyHapticFeedback(
  272. xrSession, &hapticActionInfo, reinterpret_cast<XrHapticBaseHeader*>(&hapticVibration));
  273. WARN_IF_UNSUCCESSFUL(result);
  274. }
  275. };
  276. setHapticVibration(static_cast<AZ::u32>(XR::Side::Left), rawControllerData.m_leftMotorVibrationValue);
  277. setHapticVibration(static_cast<AZ::u32>(XR::Side::Right), rawControllerData.m_rightMotorVibrationValue);
  278. // after the vibration values have been used, reset them
  279. rawControllerData.m_leftMotorVibrationValue = 0.f;
  280. rawControllerData.m_rightMotorVibrationValue = 0.f;
  281. // Check if the Quit (Home) button was pressed this sync...
  282. const bool quitPressed = GetButtonState(InputDeviceXRController::Button::Home);
  283. if (quitPressed && !m_wasQuitPressedLastSync)
  284. {
  285. result = xrRequestExitSession(xrSession);
  286. WARN_IF_UNSUCCESSFUL(result);
  287. }
  288. m_wasQuitPressedLastSync = quitPressed;
  289. }
  290. bool Input::UpdateXrSpaceLocations(const OpenXRVk::Device& device, XrTime predictedDisplayTime, AZStd::vector<XrView>& xrViews)
  291. {
  292. const auto thisDevice = static_cast<Device*>(GetDescriptor().m_device.get());
  293. if (thisDevice != &device)
  294. {
  295. return false;
  296. }
  297. auto& rawControllerData = m_xrControllerImpl->GetRawState();
  298. const auto session = static_cast<Session*>(GetDescriptor().m_session.get());
  299. XrSession xrSession = session->GetXrSession();
  300. XrSpace xrBaseSpaceForVisualization = session->GetXrSpace(session->GetBaseSpaceTypeForVisualization());
  301. XrSpace xrBaseSpaceForJoysticks = session->GetXrSpace(session->GetBaseSpaceTypeForControllers());
  302. // Update poses
  303. for (const auto hand : { XR::Side::Left, XR::Side::Right })
  304. {
  305. XrActionStateGetInfo getInfo{};
  306. getInfo.type = XR_TYPE_ACTION_STATE_GET_INFO;
  307. getInfo.action = GetPoseAction(static_cast<AZ::u32>(hand));
  308. XrActionStatePose poseState{};
  309. poseState.type = XR_TYPE_ACTION_STATE_POSE;
  310. XrResult result = xrGetActionStatePose(xrSession, &getInfo, &poseState);
  311. WARN_IF_UNSUCCESSFUL(result);
  312. m_handActive[static_cast<AZ::u32>(hand)] = poseState.isActive;
  313. LocateControllerSpace(predictedDisplayTime, xrBaseSpaceForJoysticks, static_cast<AZ::u32>(hand));
  314. }
  315. // Cache 3d location information
  316. for (AZ::u32 i = 0; i < static_cast<AZ::u32>(SpaceType::Count); i++)
  317. {
  318. const auto spaceType = static_cast<SpaceType>(i);
  319. LocateVisualizedSpace(predictedDisplayTime, session->GetXrSpace(spaceType),
  320. xrBaseSpaceForVisualization, spaceType);
  321. }
  322. rawControllerData.m_leftPositionState = AzPositionFromXrPose(m_handSpaceLocation[static_cast<AZ::u32>(XR::Side::Left)].pose);
  323. rawControllerData.m_rightPositionState = AzPositionFromXrPose(m_handSpaceLocation[static_cast<AZ::u32>(XR::Side::Right)].pose);
  324. rawControllerData.m_leftOrientationState = AzQuaternionFromXrPose(m_handSpaceLocation[static_cast<AZ::u32>(XR::Side::Left)].pose);
  325. rawControllerData.m_rightOrientationState = AzQuaternionFromXrPose(m_handSpaceLocation[static_cast<AZ::u32>(XR::Side::Right)].pose);
  326. if (LocateEyeViews(predictedDisplayTime, xrViews))
  327. {
  328. //! Time to notify the engine that we have new poses.
  329. const auto& xrSpaceLocationHeadToBase = m_xrVisualizedSpaceLocations[OpenXRVk::SpaceType::View];
  330. const auto baseToHeadTm = AzTransformFromXrPose(xrSpaceLocationHeadToBase.pose);
  331. const auto headToLeftEyeTm = AzTransformFromXrPose(xrViews[0].pose);
  332. const auto headToRightEyeTm = AzTransformFromXrPose(xrViews[1].pose);
  333. AZ::RPI::XRSpaceNotificationBus::Broadcast(&AZ::RPI::XRSpaceNotifications::OnXRSpaceLocationsChanged,
  334. baseToHeadTm, headToLeftEyeTm, headToRightEyeTm);
  335. return true;
  336. }
  337. return false;
  338. }
  339. bool Input::LocateEyeViews(XrTime predictedDisplayTime, AZStd::vector<XrView>& xrViews)
  340. {
  341. const auto session = static_cast<Session*>(GetDescriptor().m_session.get());
  342. XrSession xrSession = session->GetXrSession();
  343. const auto xrVkInstance = static_cast<Instance*>(GetDescriptor().m_instance.get());
  344. // Let's get the FOV data, which for most practical purposes it is always the same
  345. // across all frames. But most importantly we need to get the location of each Eye relative to the View Space pose.
  346. Space* xrSpace = static_cast<Space*>(session->GetSpace());
  347. XrViewState viewState{ XR_TYPE_VIEW_STATE };
  348. uint32_t viewCapacityInput = aznumeric_cast<uint32_t>(xrViews.size());
  349. uint32_t viewCountOutput = 0;
  350. XrViewLocateInfo viewLocateInfo{ XR_TYPE_VIEW_LOCATE_INFO };
  351. viewLocateInfo.viewConfigurationType = xrVkInstance->GetViewConfigType();
  352. viewLocateInfo.displayTime = predictedDisplayTime;
  353. viewLocateInfo.space = xrSpace->GetXrSpace(OpenXRVk::SpaceType::View);
  354. XrResult result = xrLocateViews(xrSession, &viewLocateInfo, &viewState, viewCapacityInput, &viewCountOutput, xrViews.data());
  355. ASSERT_IF_UNSUCCESSFUL(result);
  356. if ((viewState.viewStateFlags & XR_VIEW_STATE_POSITION_VALID_BIT) == 0 ||
  357. (viewState.viewStateFlags & XR_VIEW_STATE_ORIENTATION_VALID_BIT) == 0)
  358. {
  359. //There is no valid tracking poses for the views
  360. return false;
  361. }
  362. AZ_Error(LogName, viewCountOutput == viewCapacityInput, "Size mismatch between xrLocateViews %i and xrEnumerateViewConfigurationViews %i", viewCountOutput, viewCapacityInput);
  363. return (viewCountOutput == viewCapacityInput);
  364. }
  365. void Input::LocateControllerSpace(XrTime predictedDisplayTime, XrSpace baseSpace, AZ::u32 handIndex)
  366. {
  367. XrSpaceLocation spaceLocation{};
  368. spaceLocation.type = XR_TYPE_SPACE_LOCATION;
  369. if (const XrResult result = xrLocateSpace(m_handSpace[handIndex], baseSpace, predictedDisplayTime, &spaceLocation);
  370. result == XR_SUCCESS)
  371. {
  372. if ((spaceLocation.locationFlags & XR_SPACE_LOCATION_POSITION_VALID_BIT) != 0 &&
  373. (spaceLocation.locationFlags & XR_SPACE_LOCATION_ORIENTATION_VALID_BIT) != 0)
  374. {
  375. m_handSpaceLocation[handIndex] = spaceLocation;
  376. }
  377. }
  378. }
  379. void Input::LocateVisualizedSpace(XrTime predictedDisplayTime, XrSpace space, XrSpace baseSpace, OpenXRVk::SpaceType visualizedSpaceType)
  380. {
  381. XrSpaceLocation spaceLocation{};
  382. spaceLocation.type = XR_TYPE_SPACE_LOCATION;
  383. if (const XrResult result = xrLocateSpace(space, baseSpace, predictedDisplayTime, &spaceLocation);
  384. result == XR_SUCCESS)
  385. {
  386. if ((spaceLocation.locationFlags & XR_SPACE_LOCATION_POSITION_VALID_BIT) != 0 &&
  387. (spaceLocation.locationFlags & XR_SPACE_LOCATION_ORIENTATION_VALID_BIT) != 0)
  388. {
  389. m_xrVisualizedSpaceLocations[static_cast<uint32_t>(visualizedSpaceType)] = spaceLocation;
  390. }
  391. }
  392. }
  393. AZ::RHI::ResultCode Input::GetControllerPose(AZ::u32 handIndex, AZ::RPI::PoseData& outPoseData, bool convertToO3de) const
  394. {
  395. if (handIndex < AZStd::size(m_handSpaceLocation))
  396. {
  397. outPoseData.m_orientation = AzQuaternionFromXrPose(m_handSpaceLocation[handIndex].pose, convertToO3de);
  398. outPoseData.m_position = AzPositionFromXrPose(m_handSpaceLocation[handIndex].pose, convertToO3de);
  399. return AZ::RHI::ResultCode::Success;
  400. }
  401. return AZ::RHI::ResultCode::Fail;
  402. }
  403. AZ::RHI::ResultCode Input::GetControllerTransform(AZ::u32 handIndex, AZ::Transform& outTransform, bool convertToO3de) const
  404. {
  405. if (handIndex < AZStd::size(m_handSpaceLocation))
  406. {
  407. outTransform = AzTransformFromXrPose(m_handSpaceLocation[handIndex].pose, convertToO3de);
  408. outTransform.SetUniformScale(m_handScale[handIndex]);
  409. return AZ::RHI::ResultCode::Success;
  410. }
  411. return AZ::RHI::ResultCode::Fail;
  412. }
  413. AZ::RHI::ResultCode Input::GetVisualizedSpacePose(OpenXRVk::SpaceType visualizedSpaceType, AZ::RPI::PoseData& outPoseData, bool convertToO3de) const
  414. {
  415. const auto spaceIndex = static_cast<AZ::u32>(visualizedSpaceType);
  416. if (spaceIndex < AZStd::size(m_xrVisualizedSpaceLocations))
  417. {
  418. outPoseData.m_orientation = AzQuaternionFromXrPose(m_xrVisualizedSpaceLocations[spaceIndex].pose, convertToO3de);
  419. outPoseData.m_position = AzPositionFromXrPose(m_xrVisualizedSpaceLocations[spaceIndex].pose, convertToO3de);
  420. return AZ::RHI::ResultCode::Success;
  421. }
  422. return AZ::RHI::ResultCode::Fail;
  423. }
  424. AZ::RHI::ResultCode Input::GetVisualizedSpaceTransform(OpenXRVk::SpaceType visualizedSpaceType, AZ::Transform& outTransform, bool convertToO3de) const
  425. {
  426. const auto spaceIndex = static_cast<AZ::u32>(visualizedSpaceType);
  427. if (spaceIndex < AZStd::size(m_xrVisualizedSpaceLocations))
  428. {
  429. outTransform = AzTransformFromXrPose(m_xrVisualizedSpaceLocations[spaceIndex].pose, convertToO3de);
  430. return AZ::RHI::ResultCode::Success;
  431. }
  432. return AZ::RHI::ResultCode::Fail;
  433. }
  434. float Input::GetControllerScale(AZ::u32 handIndex) const
  435. {
  436. return m_handScale[handIndex];
  437. }
  438. XrAction Input::GetSqueezeAction(AZ::u32 handIndex) const
  439. {
  440. return (handIndex == static_cast<AZ::u32>(XR::Side::Left))
  441. ? GetAction(AzFramework::InputDeviceXRController::Trigger::LGrip)
  442. : GetAction(AzFramework::InputDeviceXRController::Trigger::RGrip);
  443. }
  444. XrAction Input::GetPoseAction(AZ::u32 handIndex) const
  445. {
  446. return (handIndex == static_cast<AZ::u32>(XR::Side::Left))
  447. ? GetAction(AzFramework::InputDeviceXRController::ControllerPosePosition::LPos)
  448. : GetAction(AzFramework::InputDeviceXRController::ControllerPosePosition::RPos);
  449. }
  450. XrAction Input::GetVibrationAction() const
  451. {
  452. return m_hapticAction;
  453. }
  454. XrAction Input::GetQuitAction() const
  455. {
  456. return GetAction(AzFramework::InputDeviceXRController::Button::Home);
  457. }
  458. bool Input::GetButtonState(const AzFramework::InputChannelId& channelId) const
  459. {
  460. const auto& state = m_xrControllerImpl->GetRawState();
  461. return state.GetDigitalButtonState(channelId);
  462. }
  463. bool Input::GetXButtonState() const
  464. {
  465. return GetButtonState(AzFramework::InputDeviceXRController::Button::X);
  466. }
  467. bool Input::GetYButtonState() const
  468. {
  469. return GetButtonState(AzFramework::InputDeviceXRController::Button::Y);
  470. }
  471. bool Input::GetAButtonState() const
  472. {
  473. return GetButtonState(AzFramework::InputDeviceXRController::Button::A);
  474. }
  475. bool Input::GetBButtonState() const
  476. {
  477. return GetButtonState(AzFramework::InputDeviceXRController::Button::B);
  478. }
  479. float Input::GetXJoyStickState(AZ::u32 handIndex) const
  480. {
  481. const auto& state = m_xrControllerImpl->GetRawState();
  482. return (handIndex == static_cast<AZ::u32>(XR::Side::Left))
  483. ? state.m_leftThumbStickXState
  484. : state.m_rightThumbStickXState;
  485. }
  486. float Input::GetYJoyStickState(AZ::u32 handIndex) const
  487. {
  488. const auto& state = m_xrControllerImpl->GetRawState();
  489. return (handIndex == static_cast<AZ::u32>(XR::Side::Left))
  490. ? state.m_leftThumbStickYState
  491. : state.m_rightThumbStickYState;
  492. }
  493. float Input::GetSqueezeState(AZ::u32 handIndex) const
  494. {
  495. const auto& state = m_xrControllerImpl->GetRawState();
  496. return (handIndex == static_cast<AZ::u32>(XR::Side::Left))
  497. ? state.m_leftGripState
  498. : state.m_rightGripState;
  499. }
  500. float Input::GetTriggerState(AZ::u32 handIndex) const
  501. {
  502. const auto& state = m_xrControllerImpl->GetRawState();
  503. return (handIndex == static_cast<AZ::u32>(XR::Side::Left))
  504. ? state.m_leftTriggerState
  505. : state.m_rightTriggerState;
  506. }
  507. } // namespace OpenXRVk