Преглед на файлове

XR/OpenXrVk changes related to the new RPI sample added to AtomSampleViewer (#22)

* Added a new XR level that tests a proper VR multi-view pipeline. It creates a render pipeline for each eye and runs than consecutively with a pipeline for PC. The two XR pipelines themselves are a variant of low end render pipeline as a start but in future they will be modified for performance and memory improvements. For example currently we are doing the ShadowMap passes for both the pipelines. This sample adds a ground plane and a few meshes on top of the plane. It also added support for rendering and updating Quest 2 controller related meshes. There is support to switch through different lighting presets for testing purposes as well as support for iterating through differnt ground materials in order to test shadows, reflections, etc.

The sample  supports Quest 2 controllers to fly around the world. It has support to use button presses for specific functionality in the scene. The schema for each controller is below
    - Left controller
             Joystick - Camera movement, Button X - Camera Up (View space y-axis), Button Y - Camera Down (View space Y axis), Squeeze - Scales Controller model
    - Right controller
             Joystick - View Orientation if Trigger button is pressed, otherwise it will use device for view tracking,
             Button A - Iterate through lighting preset, Button B - Iterate through ground plane material, Squeeze - Scales Controller model

Signed-off-by: moudgils <[email protected]>

* Address feedback

Signed-off-by: moudgils <[email protected]>

* Address feedback

Signed-off-by: moudgils <[email protected]>

* Removing const before uint32_t types

Signed-off-by: moudgils <[email protected]>

* Addressed feedback

Signed-off-by: moudgils <[email protected]>

Signed-off-by: moudgils <[email protected]>
moudgils преди 3 години
родител
ревизия
359e8c7810

+ 2 - 2
Gems/OpenXRVk/Code/Include/OpenXRVk/OpenXRVkDevice.h

@@ -30,9 +30,9 @@ namespace OpenXRVk
         // Create the xr specific native device object and populate the XRDeviceDescriptor with it.
         AZ::RHI::ResultCode InitDeviceInternal(AZ::RHI::XRDeviceDescriptor* instanceDescriptor) override;
         //! Get the Fov data  of the view specified by view index
-        AZ::RPI::FovData GetViewFov(AZ::u32 viewIndex) const override;
+        AZ::RHI::ResultCode GetViewFov(AZ::u32 viewIndex, AZ::RPI::FovData& outFovData) const override;
         //! Get the Pose data  of the view specified by view index
-        AZ::RPI::PoseData GetViewPose(AZ::u32 viewIndex) const override;
+        AZ::RHI::ResultCode GetViewPose(AZ::u32 viewIndex, AZ::RPI::PoseData& outPoseData) const override;
         //////////////////////////////////////////////////////////////////////////
 
         //! Returns true if rendering data is valid for the current frame.

+ 67 - 10
Gems/OpenXRVk/Code/Include/OpenXRVk/OpenXRVkInput.h

@@ -43,16 +43,16 @@ namespace OpenXRVk
         void LocateVisualizedSpace(XrTime predictedDisplayTime, XrSpace space, XrSpace baseSpace, OpenXRVk::SpaceType visualizedSpaceType);
 
         //! Return Pose data for a controller attached to a view index
-        AZ::RPI::PoseData GetControllerPose(AZ::u32 viewIndex) const;
+        AZ::RHI::ResultCode GetControllerPose(AZ::u32 handIndex, AZ::RPI::PoseData& outPoseData) const;
 
         //! Return scale for a controller attached to a view index
         float GetControllerScale(AZ::u32 viewIndex) const;
 
         //! Return Pose data for a tracked space type (i.e visualizedSpaceType)
-        AZ::RPI::PoseData GetVisualizedSpacePose(OpenXRVk::SpaceType visualizedSpaceType) const;
+        AZ::RHI::ResultCode GetVisualizedSpacePose(OpenXRVk::SpaceType visualizedSpaceType, AZ::RPI::PoseData& outPoseData) const;
 
-        //! Get the Grab action
-        XrAction GetGrabAction() const;
+        //! Get the Pose action
+        XrAction GetSqueezeAction() const;
 
         //! Get the Pose action
         XrAction GetPoseAction() const;
@@ -62,8 +62,51 @@ namespace OpenXRVk
 
         //! Get the Quit action
         XrAction GetQuitAction() const;
+
+        //! Get the X button state
+        float GetXButtonState() const;
+
+        //! Get the Y button state
+        float GetYButtonState() const;
+
+        //! Get the A button state
+        float GetAButtonState() const;
+
+        //! Get the B button state
+        float GetBButtonState() const;
+
+        //! Get the joystick state for x-axis
+        float GetXJoyStickState(AZ::u32 handIndex) const;
+
+        //! Get the joystick state for y-axis
+        float GetYJoyStickState(AZ::u32 handIndex) const;
+
+        //! Get the Squeeze action
+        float GetSqueezeState(AZ::u32 handIndex) const;
+
+        //! Get the Squeeze action
+        float GetTriggerState(AZ::u32 handIndex) const;
+
     private:
 
+        struct SingleActionData
+        {
+            XrAction m_actionHandle{ XR_NULL_HANDLE };
+            float m_actionState = 0.0f;
+        };
+
+        struct DualActionData
+        {
+            XrAction m_actionHandle{ XR_NULL_HANDLE };
+            AZStd::array<float, AZ::RPI::XRMaxNumControllers> m_actionState = { { 0.0f, 0.0f } };
+        };
+
+        struct ControllerActionData
+        {
+            SingleActionData m_actionData;
+            uint16_t m_handIndex = 0;
+        };
+
         //! Create a XrAction
         void CreateAction(XrAction& action, XrActionType actionType,
                           const char* actionName, const char* localizedActionName,
@@ -72,17 +115,31 @@ namespace OpenXRVk
         //! Destroy native objects
         void ShutdownInternal() override;
 
+        bool GetActionState(XrSession xrSession, XrAction xrAction, uint16_t handIndex, float& outputSate);
+        bool UpdateActionState(XrSession xrSession, SingleActionData& actionData, uint16_t handIndex);
+        bool UpdateActionState(XrSession xrSession, DualActionData& actionData, uint16_t handIndex);
+
         XrActionSet m_actionSet{ XR_NULL_HANDLE };
-        XrAction m_grabAction{ XR_NULL_HANDLE };
         XrAction m_poseAction{ XR_NULL_HANDLE };
         XrAction m_vibrateAction{ XR_NULL_HANDLE };
         XrAction m_quitAction{ XR_NULL_HANDLE };
-        AZStd::array<XrPath, 2> m_handSubactionPath;
-        AZStd::array<XrSpace, 2> m_handSpace;
-        AZStd::array<float, 2> m_handScale = { { 1.0f, 1.0f } };
-        AZStd::array<XrBool32, 2> m_handActive;
+        DualActionData m_squeezeAction{ XR_NULL_HANDLE, 0.0f };
+        DualActionData m_triggerAction{ XR_NULL_HANDLE, 0.0f };
 
-        AZStd::array<XrSpaceLocation, 2> m_handSpaceLocation;
+        AZStd::array<XrPath, AZ::RPI::XRMaxNumControllers> m_handSubactionPath;
+        AZStd::array<XrSpace, AZ::RPI::XRMaxNumControllers> m_handSpace;
+        AZStd::array<float, AZ::RPI::XRMaxNumControllers> m_handScale = { { 1.0f, 1.0f } };
+        AZStd::array<XrBool32, AZ::RPI::XRMaxNumControllers> m_handActive;
+
+        AZStd::array<XrSpaceLocation, AZ::RPI::XRMaxNumControllers> m_handSpaceLocation;
         AZStd::array<XrSpaceLocation, SpaceType::Count> m_xrVisualizedSpaceLocations;
+
+        //Todo: This is assuming Quest 2 controller. Needs better abstraction to cover other types of controllers
+        SingleActionData m_xButtonAction{XR_NULL_HANDLE, 0.0f};
+        SingleActionData m_yButtonAction{XR_NULL_HANDLE, 0.0f};
+        SingleActionData m_aButtonAction{XR_NULL_HANDLE, 0.0f};
+        SingleActionData m_bButtonAction{XR_NULL_HANDLE, 0.0f};
+        DualActionData m_joyStickXAction{ XR_NULL_HANDLE, 0.0f };
+        DualActionData m_joyStickYAction{ XR_NULL_HANDLE, 0.0f };
     };
 }

+ 15 - 3
Gems/OpenXRVk/Code/Include/OpenXRVk/OpenXRVkSession.h

@@ -11,6 +11,7 @@
 #include <AzCore/std/smart_ptr/intrusive_ptr.h>
 #include <OpenXRVk_Platform.h>
 #include <OpenXRVk/OpenXRVkSpace.h>
+#include <OpenXRVk/OpenXRVkInput.h>
 #include <XR/XRSession.h>
 
 namespace OpenXRVk
@@ -49,16 +50,27 @@ namespace OpenXRVk
         bool IsExitRenderLoopRequested() const override;
         void PollEvents() override;
         void LocateControllerSpace(AZ::u32 handIndex) override;
-        AZ::RPI::PoseData GetControllerPose(AZ::u32 handIndex) const override;
-        AZ::RPI::PoseData GetViewFrontPose() const override;
+        AZ::RHI::ResultCode GetControllerPose(AZ::u32 handIndex, AZ::RPI::PoseData& outPoseData) const override;
+        AZ::RHI::ResultCode GetControllerStagePose(AZ::u32 handIndex, AZ::RPI::PoseData& outPoseData) const override;
+        AZ::RHI::ResultCode GetViewFrontPose(AZ::RPI::PoseData& outPoseData) const override;
+        AZ::RHI::ResultCode GetViewLocalPose(AZ::RPI::PoseData& outPoseData) const override;
         float GetControllerScale(AZ::u32 handIndex) const override;
+        float GetXButtonState() const override;
+        float GetYButtonState() const override;
+        float GetAButtonState() const override;
+        float GetBButtonState() const override;
+        float GetXJoyStickState(AZ::u32 handIndex) const override;
+        float GetYJoyStickState(AZ::u32 handIndex) const override;
+        float GetSqueezeState(AZ::u32 handIndex) const override;
+        float GetTriggerState(AZ::u32 handIndex) const override;
         //////////////////////////////////////////////////////////////////////////
 
     private:
 
         void ShutdownInternal() override;
         void LogActionSourceName(XrAction action, const AZStd::string_view actionName) const;
-        
+        Input* GetNativeInput() const;
+
         XrSession m_session = XR_NULL_HANDLE;
         XrSessionState m_sessionState = XR_SESSION_STATE_UNKNOWN;
         XrEventDataBuffer m_eventDataBuffer;

+ 19 - 19
Gems/OpenXRVk/Code/Source/OpenXRVkDevice.cpp

@@ -243,35 +243,35 @@ namespace OpenXRVk
         return m_context;
     }
 
-    AZ::RPI::FovData Device::GetViewFov(AZ::u32 viewIndex) const
+    AZ::RHI::ResultCode Device::GetViewFov(AZ::u32 viewIndex, AZ::RPI::FovData& outFovData) const
     {
-        AZ::RPI::FovData viewFov;
         if(viewIndex < m_projectionLayerViews.size())
         { 
-            viewFov.m_angleLeft = m_projectionLayerViews[viewIndex].fov.angleLeft;
-            viewFov.m_angleRight = m_projectionLayerViews[viewIndex].fov.angleRight;
-            viewFov.m_angleUp = m_projectionLayerViews[viewIndex].fov.angleUp;
-            viewFov.m_angleDown = m_projectionLayerViews[viewIndex].fov.angleDown;     
+            outFovData.m_angleLeft = m_projectionLayerViews[viewIndex].fov.angleLeft;
+            outFovData.m_angleRight = m_projectionLayerViews[viewIndex].fov.angleRight;
+            outFovData.m_angleUp = m_projectionLayerViews[viewIndex].fov.angleUp;
+            outFovData.m_angleDown = m_projectionLayerViews[viewIndex].fov.angleDown;
+            return AZ::RHI::ResultCode::Success;
         }
-        return viewFov;
+        return AZ::RHI::ResultCode::Fail;
     }
 
-    AZ::RPI::PoseData Device::GetViewPose(AZ::u32 viewIndex) const
-    {
-        AZ::RPI::PoseData viewPose;
+    AZ::RHI::ResultCode Device::GetViewPose(AZ::u32 viewIndex, AZ::RPI::PoseData& outPoseData) const
+    { 
         if (viewIndex < m_projectionLayerViews.size())
         {
             const XrQuaternionf& orientation = m_projectionLayerViews[viewIndex].pose.orientation;
             const XrVector3f& position = m_projectionLayerViews[viewIndex].pose.position;
-            viewPose.orientation = AZ::Quaternion(orientation.x,
-                                                  orientation.y, 
-                                                  orientation.z, 
-                                                  orientation.w);
-            viewPose.position = AZ::Vector3(position.x, 
-                                            position.y, 
-                                            position.z);
-        }        
-        return viewPose;
+            outPoseData.m_orientation.Set(orientation.x,
+                                          orientation.y, 
+                                          orientation.z, 
+                                          orientation.w);
+            outPoseData.m_position.Set(position.x,
+                                       position.y, 
+                                       position.z);
+            return AZ::RHI::ResultCode::Success;
+        }
+        return AZ::RHI::ResultCode::Fail;
     }
 
     XrTime Device::GetPredictedDisplayTime() const

+ 162 - 34
Gems/OpenXRVk/Code/Source/OpenXRVkInput.cpp

@@ -42,9 +42,12 @@ namespace OpenXRVk
 
         // Create actions.   
         // Create an input action for grabbing objects with the left and right hands.
-        CreateAction(m_grabAction, XR_ACTION_TYPE_FLOAT_INPUT, "grab_object", "Grab Object",
+        CreateAction(m_squeezeAction.m_actionHandle, XR_ACTION_TYPE_FLOAT_INPUT, "squeeze_object", "Squeeze Object",
                      aznumeric_cast<uint32_t>(m_handSubactionPath.size()), m_handSubactionPath.data());
 
+        CreateAction(m_triggerAction.m_actionHandle, XR_ACTION_TYPE_FLOAT_INPUT, "trigger_object", "Trigger Object",
+            aznumeric_cast<uint32_t>(m_handSubactionPath.size()), m_handSubactionPath.data());
+
         CreateAction(m_poseAction, XR_ACTION_TYPE_POSE_INPUT, "hand_pose", "Hand Pose",
             aznumeric_cast<uint32_t>(m_handSubactionPath.size()), m_handSubactionPath.data());
 
@@ -53,30 +56,70 @@ namespace OpenXRVk
 
         CreateAction(m_quitAction, XR_ACTION_TYPE_BOOLEAN_INPUT, "quit_session", "Quit Session", 0, nullptr);
 
-        AZStd::array<XrPath, static_cast<uint32_t>(XR::Side::Count)> squeezeValuePath;
-        AZStd::array<XrPath, static_cast<uint32_t>(XR::Side::Count)> posePath;
-        AZStd::array<XrPath, static_cast<uint32_t>(XR::Side::Count)> hapticPath;
-        AZStd::array<XrPath, static_cast<uint32_t>(XR::Side::Count)> menuClickPath;
+        CreateAction(m_xButtonAction.m_actionHandle, XR_ACTION_TYPE_FLOAT_INPUT, "x_button", "X Button Object",
+            aznumeric_cast<uint32_t>(m_handSubactionPath.size()), m_handSubactionPath.data());
+        CreateAction(m_yButtonAction.m_actionHandle, XR_ACTION_TYPE_FLOAT_INPUT, "y_button", "Y Button Object",
+            aznumeric_cast<uint32_t>(m_handSubactionPath.size()), m_handSubactionPath.data());
+        CreateAction(m_aButtonAction.m_actionHandle, XR_ACTION_TYPE_FLOAT_INPUT, "a_button", "A Button Object",
+            aznumeric_cast<uint32_t>(m_handSubactionPath.size()), m_handSubactionPath.data());
+        CreateAction(m_bButtonAction.m_actionHandle, XR_ACTION_TYPE_FLOAT_INPUT, "b_button", "B Button Object",
+            aznumeric_cast<uint32_t>(m_handSubactionPath.size()), m_handSubactionPath.data());
+        CreateAction(m_joyStickXAction.m_actionHandle, XR_ACTION_TYPE_FLOAT_INPUT, "joystick_x", "JoyStick X Object",
+            aznumeric_cast<uint32_t>(m_handSubactionPath.size()), m_handSubactionPath.data());
+        CreateAction(m_joyStickYAction.m_actionHandle, XR_ACTION_TYPE_FLOAT_INPUT, "joystick_y", "JoyStick Y Object",
+            aznumeric_cast<uint32_t>(m_handSubactionPath.size()), m_handSubactionPath.data());
+
+        AZStd::array<XrPath, AZ::RPI::XRMaxNumControllers> squeezeValuePath;
+        AZStd::array<XrPath, AZ::RPI::XRMaxNumControllers> triggerValuePath;
+        AZStd::array<XrPath, AZ::RPI::XRMaxNumControllers> posePath;
+        AZStd::array<XrPath, AZ::RPI::XRMaxNumControllers> hapticPath;
+        AZStd::array<XrPath, AZ::RPI::XRMaxNumControllers> menuClickPath;
+        AZStd::array<XrPath, AZ::RPI::XRMaxNumControllers> joyStickXPath;
+        AZStd::array<XrPath, AZ::RPI::XRMaxNumControllers> joyStickYPath;
+        XrPath xButtonValuePath;
+        XrPath yButtonValuePath;
+        XrPath aButtonValuePath;
+        XrPath bButtonValuePath;
 
         result = xrStringToPath(xrInstance, "/user/hand/left/input/squeeze/value", &squeezeValuePath[static_cast<uint32_t>(XR::Side::Left)]);
         result = xrStringToPath(xrInstance, "/user/hand/right/input/squeeze/value", &squeezeValuePath[static_cast<uint32_t>(XR::Side::Right)]);
+        result = xrStringToPath(xrInstance, "/user/hand/left/input/trigger/value", &triggerValuePath[static_cast<uint32_t>(XR::Side::Left)]);
+        result = xrStringToPath(xrInstance, "/user/hand/right/input/trigger/value", &triggerValuePath[static_cast<uint32_t>(XR::Side::Right)]);
         result = xrStringToPath(xrInstance, "/user/hand/left/input/grip/pose", &posePath[static_cast<uint32_t>(XR::Side::Left)]);
         result = xrStringToPath(xrInstance, "/user/hand/right/input/grip/pose", &posePath[static_cast<uint32_t>(XR::Side::Right)]);
         result = xrStringToPath(xrInstance, "/user/hand/left/output/haptic", &hapticPath[static_cast<uint32_t>(XR::Side::Left)]);
         result = xrStringToPath(xrInstance, "/user/hand/right/output/haptic", &hapticPath[static_cast<uint32_t>(XR::Side::Right)]);
         result = xrStringToPath(xrInstance, "/user/hand/left/input/menu/click", &menuClickPath[static_cast<uint32_t>(XR::Side::Left)]);
         result = xrStringToPath(xrInstance, "/user/hand/right/input/menu/click", &menuClickPath[static_cast<uint32_t>(XR::Side::Right)]);
+        result = xrStringToPath(xrInstance, "/user/hand/left/input/thumbstick/x", &joyStickXPath[static_cast<uint32_t>(XR::Side::Left)]);
+        result = xrStringToPath(xrInstance, "/user/hand/right/input/thumbstick/x", &joyStickXPath[static_cast<uint32_t>(XR::Side::Right)]);
+        result = xrStringToPath(xrInstance, "/user/hand/left/input/thumbstick/y", &joyStickYPath[static_cast<uint32_t>(XR::Side::Left)]);
+        result = xrStringToPath(xrInstance, "/user/hand/right/input/thumbstick/y", &joyStickYPath[static_cast<uint32_t>(XR::Side::Right)]);
+        result = xrStringToPath(xrInstance, "/user/hand/left/input/x/click", &xButtonValuePath);
+        result = xrStringToPath(xrInstance, "/user/hand/left/input/y/click", &yButtonValuePath);
+        result = xrStringToPath(xrInstance, "/user/hand/right/input/a/click", &aButtonValuePath);
+        result = xrStringToPath(xrInstance, "/user/hand/right/input/b/click", &bButtonValuePath);
         
-        // Bindings for the Occulus Touch.
+        // Bindings for the Oculus Touch.
         XrPath oculusTouchInteractionProfilePath;
         result = xrStringToPath(xrInstance, "/interaction_profiles/oculus/touch_controller", &oculusTouchInteractionProfilePath);
-        AZStd::vector<XrActionSuggestedBinding> bindings{ { { m_grabAction, squeezeValuePath[static_cast<uint32_t>(XR::Side::Left)] },
-                                                            { m_grabAction, squeezeValuePath[static_cast<uint32_t>(XR::Side::Right)] },
+        AZStd::vector<XrActionSuggestedBinding> bindings{   { m_squeezeAction.m_actionHandle, squeezeValuePath[static_cast<uint32_t>(XR::Side::Left)] },
+                                                            { m_squeezeAction.m_actionHandle, squeezeValuePath[static_cast<uint32_t>(XR::Side::Right)] },
+                                                            { m_triggerAction.m_actionHandle, triggerValuePath[static_cast<uint32_t>(XR::Side::Left)] },
+                                                            { m_triggerAction.m_actionHandle, triggerValuePath[static_cast<uint32_t>(XR::Side::Right)] },
                                                             { m_poseAction, posePath[static_cast<uint32_t>(XR::Side::Left)] },
                                                             { m_poseAction, posePath[static_cast<uint32_t>(XR::Side::Right)] },
                                                             { m_quitAction, menuClickPath[static_cast<uint32_t>(XR::Side::Left)] },
                                                             { m_vibrateAction, hapticPath[static_cast<uint32_t>(XR::Side::Left)] },
-                                                            { m_vibrateAction, hapticPath[static_cast<uint32_t>(XR::Side::Right)] } } };
+                                                            { m_vibrateAction, hapticPath[static_cast<uint32_t>(XR::Side::Right)] },
+                                                            { m_joyStickXAction.m_actionHandle, joyStickXPath[static_cast<uint32_t>(XR::Side::Left)] },
+                                                            { m_joyStickXAction.m_actionHandle, joyStickXPath[static_cast<uint32_t>(XR::Side::Right)] },
+                                                            { m_joyStickYAction.m_actionHandle, joyStickYPath[static_cast<uint32_t>(XR::Side::Left)] },
+                                                            { m_joyStickYAction.m_actionHandle, joyStickYPath[static_cast<uint32_t>(XR::Side::Right)] },
+                                                            { m_xButtonAction.m_actionHandle, xButtonValuePath },
+                                                            { m_yButtonAction.m_actionHandle, yButtonValuePath },
+                                                            { m_aButtonAction.m_actionHandle, aButtonValuePath },
+                                                            { m_bButtonAction.m_actionHandle, bButtonValuePath } };
         XrInteractionProfileSuggestedBinding suggestedBindings{ XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING };
         suggestedBindings.interactionProfile = oculusTouchInteractionProfilePath;
         suggestedBindings.suggestedBindings = bindings.data();
@@ -84,6 +127,17 @@ namespace OpenXRVk
         result = xrSuggestInteractionProfileBindings(xrInstance, &suggestedBindings);
         WARN_IF_UNSUCCESSFUL(result);
         
+        for (int i = 0; i < AZ::RPI::XRMaxNumControllers; i++)
+        {
+            m_handSpaceLocation[i].pose.orientation.x = 0.0f;
+            m_handSpaceLocation[i].pose.orientation.y = 0.0f;
+            m_handSpaceLocation[i].pose.orientation.z = 0.0f;
+            m_handSpaceLocation[i].pose.orientation.w = 0.0f;
+            m_handSpaceLocation[i].pose.position.x = 0.0f;
+            m_handSpaceLocation[i].pose.position.y = 0.0f;
+            m_handSpaceLocation[i].pose.position.z = 0.0f;
+        }
+
         return ConvertResult(result);
     }
 
@@ -157,19 +211,15 @@ namespace OpenXRVk
         // Get pose and grab action state and start haptic vibrate when hand is 90% squeezed for testing purposes
         for (auto hand : { XR::Side::Left, XR::Side::Right })
         {
-            XrActionStateGetInfo getInfo{ XR_TYPE_ACTION_STATE_GET_INFO };
-            getInfo.action = m_grabAction;
-            getInfo.subactionPath = m_handSubactionPath[static_cast<uint32_t>(hand)];
-
-            XrActionStateFloat grabValue{ XR_TYPE_ACTION_STATE_FLOAT };
-            result = xrGetActionStateFloat(xrSession, &getInfo, &grabValue);
-            WARN_IF_UNSUCCESSFUL(result);
-            if (grabValue.isActive == XR_TRUE)
+            bool isActive = UpdateActionState(xrSession, m_squeezeAction, static_cast<uint16_t>(hand));
+            if (isActive)
             {
                 // Scale the rendered hand by 1.0f (open) to 0.5f (fully squeezed).
-                m_handScale[static_cast<uint32_t>(hand)] = 1.0f - 0.5f * grabValue.currentState;
-                if (grabValue.currentState > 0.9f)
+                m_handScale[static_cast<uint32_t>(hand)] = 1.0f - 0.5f * m_squeezeAction.m_actionState[static_cast<uint32_t>(hand)];
+                if (m_squeezeAction.m_actionState[static_cast<uint32_t>(hand)] > 0.9f)
                 {
+                    //This vibration event is currently added here for testing purposes.
+                    //Remove this when this is moved to an event that is triggered externally 
                     XrHapticVibration vibration{ XR_TYPE_HAPTIC_VIBRATION };
                     vibration.amplitude = 0.5;
                     vibration.duration = XR_MIN_HAPTIC_DURATION;
@@ -183,6 +233,7 @@ namespace OpenXRVk
                 }
             }
 
+            XrActionStateGetInfo getInfo{ XR_TYPE_ACTION_STATE_GET_INFO };
             getInfo.action = m_poseAction;
             XrActionStatePose poseState{ XR_TYPE_ACTION_STATE_POSE };
             result = xrGetActionStatePose(xrSession, &getInfo, &poseState);
@@ -190,8 +241,17 @@ namespace OpenXRVk
             m_handActive[static_cast<uint32_t>(hand)] = poseState.isActive;
 
             LocateControllerSpace(device->GetPredictedDisplayTime(), session->GetXrSpace(OpenXRVk::SpaceType::View), static_cast<uint32_t>(hand));
+
+            UpdateActionState(xrSession, m_triggerAction, static_cast<uint16_t>(hand));
+            UpdateActionState(xrSession, m_joyStickXAction, static_cast<uint16_t>(hand));
+            UpdateActionState(xrSession, m_joyStickYAction, static_cast<uint16_t>(hand));
         }  
 
+        UpdateActionState(xrSession, m_xButtonAction, static_cast<uint32_t>(XR::Side::Left));
+        UpdateActionState(xrSession, m_yButtonAction, static_cast<uint32_t>(XR::Side::Left));
+        UpdateActionState(xrSession, m_aButtonAction, static_cast<uint32_t>(XR::Side::Right));
+        UpdateActionState(xrSession, m_bButtonAction, static_cast<uint32_t>(XR::Side::Right));
+
         //Cache 3d location information
         for (uint32_t i = 0; i < static_cast<uint32_t>(SpaceType::Count); i++)
         {
@@ -212,6 +272,34 @@ namespace OpenXRVk
         }
     }
 
+    bool Input::GetActionState(XrSession xrSession, XrAction xrAction, uint16_t handIndex, float& outputSate)
+    {
+        XrActionStateGetInfo buttonGetInfo{ XR_TYPE_ACTION_STATE_GET_INFO };
+        buttonGetInfo.action = xrAction;
+        buttonGetInfo.subactionPath = m_handSubactionPath[handIndex];
+
+        XrActionStateFloat buttonValue{ XR_TYPE_ACTION_STATE_FLOAT };
+        XrResult result = xrGetActionStateFloat(xrSession, &buttonGetInfo, &buttonValue);
+        WARN_IF_UNSUCCESSFUL(result);
+        if (buttonValue.isActive == XR_TRUE)
+        {
+            outputSate = buttonValue.currentState;
+            return true;
+        }
+        return false;
+    }
+
+    bool Input::UpdateActionState(XrSession xrSession, SingleActionData& actionData, uint16_t handIndex)
+    {
+        return GetActionState(xrSession, actionData.m_actionHandle, handIndex, actionData.m_actionState);
+    }
+
+    bool Input::UpdateActionState(XrSession xrSession, DualActionData& actionData, uint16_t handIndex)
+    {
+        return GetActionState(xrSession, actionData.m_actionHandle, handIndex, actionData.m_actionState[handIndex]);
+    }
+
+
     void Input::LocateControllerSpace(XrTime predictedDisplayTime, XrSpace baseSpace, uint32_t handIndex)
     {
         XrSpaceLocation spaceLocation{ XR_TYPE_SPACE_LOCATION };
@@ -240,31 +328,31 @@ namespace OpenXRVk
         }
     }
 
-    AZ::RPI::PoseData Input::GetControllerPose(AZ::u32 viewIndex) const
+    AZ::RHI::ResultCode Input::GetControllerPose(AZ::u32 handIndex, AZ::RPI::PoseData& outPoseData) const
     {
-        AZ::RPI::PoseData viewPose;
-        if (viewIndex < m_handSpaceLocation.size())
+        if (handIndex < m_handSpaceLocation.size())
         {
-            const XrQuaternionf& orientation = m_handSpaceLocation[viewIndex].pose.orientation;
-            const XrVector3f& position = m_handSpaceLocation[viewIndex].pose.position;
-            viewPose.orientation = AZ::Quaternion(orientation.x, orientation.y, orientation.z, orientation.w);
-            viewPose.position = AZ::Vector3(position.x, position.y, position.z);
+            const XrQuaternionf& orientation = m_handSpaceLocation[handIndex].pose.orientation;
+            const XrVector3f& position = m_handSpaceLocation[handIndex].pose.position;
+            outPoseData.m_orientation.Set(orientation.x, orientation.y, orientation.z, orientation.w);
+            outPoseData.m_position.Set(position.x, position.y, position.z);
+            return AZ::RHI::ResultCode::Success;
         }
-        return viewPose;
+        return AZ::RHI::ResultCode::Fail;
     }
 
-    AZ::RPI::PoseData Input::GetVisualizedSpacePose(OpenXRVk::SpaceType visualizedSpaceType) const
+    AZ::RHI::ResultCode Input::GetVisualizedSpacePose(OpenXRVk::SpaceType visualizedSpaceType, AZ::RPI::PoseData& outPoseData) const
     {
-        AZ::RPI::PoseData viewPose;
         uint32_t spaceIndex = static_cast<uint32_t>(visualizedSpaceType);
         if (spaceIndex < m_xrVisualizedSpaceLocations.size())
         {
             const XrQuaternionf& orientation = m_xrVisualizedSpaceLocations[spaceIndex].pose.orientation;
             const XrVector3f& position = m_xrVisualizedSpaceLocations[spaceIndex].pose.position;
-            viewPose.orientation = AZ::Quaternion(orientation.x, orientation.y, orientation.z, orientation.w);
-            viewPose.position = AZ::Vector3(position.x, position.y, position.z);
+            outPoseData.m_orientation.Set(orientation.x, orientation.y, orientation.z, orientation.w);
+            outPoseData.m_position.Set(position.x, position.y, position.z);
+            return AZ::RHI::ResultCode::Success;
         }
-        return viewPose;
+        return AZ::RHI::ResultCode::Fail;
     }
 
     float Input::GetControllerScale(AZ::u32 viewIndex) const
@@ -272,9 +360,9 @@ namespace OpenXRVk
         return m_handScale[viewIndex];
     }
 
-    XrAction Input::GetGrabAction() const
+    XrAction Input::GetSqueezeAction() const
     {
-        return m_grabAction;
+        return m_squeezeAction.m_actionHandle;
     }
 
     XrAction Input::GetPoseAction() const
@@ -291,4 +379,44 @@ namespace OpenXRVk
     {
         return m_quitAction;
     }
+
+    float Input::GetXButtonState() const
+    {
+        return m_xButtonAction.m_actionState;
+    }
+
+    float Input::GetYButtonState() const
+    {
+        return m_yButtonAction.m_actionState;
+    }
+
+    float Input::GetAButtonState() const
+    {
+        return m_aButtonAction.m_actionState;
+    }
+
+    float Input::GetBButtonState() const
+    {
+        return m_bButtonAction.m_actionState;
+    }
+
+    float Input::GetXJoyStickState(AZ::u32 handIndex) const
+    {
+        return m_joyStickXAction.m_actionState[handIndex];
+    }
+
+    float Input::GetYJoyStickState(AZ::u32 handIndex) const
+    {
+        return m_joyStickYAction.m_actionState[handIndex];
+    }
+
+    float Input::GetSqueezeState(AZ::u32 handIndex) const
+    {
+        return m_squeezeAction.m_actionState[handIndex];
+    }
+
+    float Input::GetTriggerState(AZ::u32 handIndex) const
+    {
+        return m_triggerAction.m_actionState[handIndex];
+    }
 }

+ 66 - 12
Gems/OpenXRVk/Code/Source/OpenXRVkSession.cpp

@@ -47,7 +47,7 @@ namespace OpenXRVk
         ASSERT_IF_UNSUCCESSFUL(result);
         
         LogReferenceSpaces();
-        Input* xrVkInput = static_cast<Input*>(GetInput());
+        Input* xrVkInput = GetNativeInput();
         xrVkInput->InitializeActionSpace(m_session);
         xrVkInput->InitializeActionSets(m_session);
 
@@ -197,8 +197,8 @@ namespace OpenXRVk
                 {
                     if (GetDescriptor().m_validationMode == AZ::RHI::ValidationMode::Enabled)
                     {
-                        Input* xrVkInput = static_cast<Input*>(GetInput());
-                        LogActionSourceName(xrVkInput->GetGrabAction(), "Grab");
+                        Input* xrVkInput = GetNativeInput();
+                        LogActionSourceName(xrVkInput->GetSqueezeAction(), "Squeeze");
                         LogActionSourceName(xrVkInput->GetQuitAction(), "Quit");
                         LogActionSourceName(xrVkInput->GetPoseAction(), "Pose");
                         LogActionSourceName(xrVkInput->GetVibrationAction(), "Vibrate");
@@ -265,28 +265,77 @@ namespace OpenXRVk
 
     void Session::LocateControllerSpace(AZ::u32 handIndex)
     {
-        Input* xrInput = static_cast<Input*>(GetInput());
+        Input* xrInput = GetNativeInput();
         Device* device = static_cast<Device*>(GetDescriptor().m_device.get());
         Space* space = static_cast<Space*>(GetSpace());
         xrInput->LocateControllerSpace(device->GetPredictedDisplayTime(), space->GetXrSpace(OpenXRVk::SpaceType::View), handIndex);
     }
 
-    AZ::RPI::PoseData Session::GetControllerPose(AZ::u32 handIndex) const
+    AZ::RHI::ResultCode Session::GetControllerPose(AZ::u32 handIndex, AZ::RPI::PoseData& outPoseData) const
     {
-        Input* xrInput = static_cast<Input*>(GetInput());
-        return xrInput->GetControllerPose(handIndex);
+        return GetNativeInput()->GetControllerPose(handIndex, outPoseData);
     }
     
+    AZ::RHI::ResultCode Session::GetControllerStagePose(AZ::u32 handIndex, AZ::RPI::PoseData& outPoseData) const
+    {
+        Input* xrInput = GetNativeInput();
+        return handIndex == 0 ? xrInput->GetVisualizedSpacePose(OpenXRVk::SpaceType::StageLeft, outPoseData) :
+            xrInput->GetVisualizedSpacePose(OpenXRVk::SpaceType::StageRight, outPoseData);
+    }
+
+    AZ::RHI::ResultCode Session::GetViewFrontPose(AZ::RPI::PoseData& outPoseData) const
+    {
+        return GetNativeInput()->GetVisualizedSpacePose(OpenXRVk::SpaceType::ViewFront, outPoseData);
+    }
+
+    AZ::RHI::ResultCode Session::GetViewLocalPose(AZ::RPI::PoseData& outPoseData) const
+    {
+        return GetNativeInput()->GetVisualizedSpacePose(OpenXRVk::SpaceType::Local, outPoseData);
+    }
+
     float Session::GetControllerScale(AZ::u32 handIndex) const
     {
-        Input* xrInput = static_cast<Input*>(GetInput());
-        return xrInput->GetControllerScale(handIndex);
+        return GetNativeInput()->GetControllerScale(handIndex);
     }
 
-    AZ::RPI::PoseData Session::GetViewFrontPose() const
+    float Session::GetSqueezeState(AZ::u32 handIndex) const
     {
-        Input* xrInput = static_cast<Input*>(GetInput());
-        return xrInput->GetVisualizedSpacePose(OpenXRVk::SpaceType::ViewFront);
+        return GetNativeInput()->GetSqueezeState(handIndex);
+    }
+
+    float Session::GetTriggerState(AZ::u32 handIndex) const
+    {
+        return GetNativeInput()->GetTriggerState(handIndex);
+    }
+
+    float Session::GetXButtonState() const
+    {
+        return GetNativeInput()->GetXButtonState();
+    }
+
+    float Session::GetYButtonState() const
+    {
+        return GetNativeInput()->GetYButtonState();
+    }
+
+    float Session::GetAButtonState() const
+    {
+        return GetNativeInput()->GetAButtonState();
+    }
+
+    float Session::GetBButtonState() const
+    {
+        return GetNativeInput()->GetBButtonState();
+    }
+
+    float Session::GetXJoyStickState(AZ::u32 handIndex) const
+    {
+        return GetNativeInput()->GetXJoyStickState(handIndex);
+    }
+    
+    float Session::GetYJoyStickState(AZ::u32 handIndex) const
+    {
+        return GetNativeInput()->GetYJoyStickState(handIndex);
     }
 
     XrSession Session::GetXrSession() const
@@ -327,4 +376,9 @@ namespace OpenXRVk
             xrDestroySession(m_session);
         }
     }
+
+    Input* Session::GetNativeInput() const
+    {
+        return static_cast<Input*>(GetInput());
+    }
 }

+ 2 - 2
Gems/XR/Code/Include/XR/XRDevice.h

@@ -43,10 +43,10 @@ namespace XR
         virtual bool ShouldRender() const = 0;
         
         //! Returns fov data for a give view index.
-        virtual AZ::RPI::FovData GetViewFov(AZ::u32 viewIndex) const = 0;
+        virtual AZ::RHI::ResultCode GetViewFov(AZ::u32 viewIndex, AZ::RPI::FovData& outFovData) const = 0;
 
         //! Returns pose data for a give view index.
-        virtual AZ::RPI::PoseData GetViewPose(AZ::u32 viewIndex) const = 0;
+        virtual AZ::RHI::ResultCode GetViewPose(AZ::u32 viewIndex, AZ::RPI::PoseData& outPoseData) const = 0;
 
         //! Init the XR device.
         AZ::RHI::ResultCode Init(Descriptor descriptor);

+ 32 - 2
Gems/XR/Code/Include/XR/XRSession.h

@@ -73,13 +73,43 @@ namespace XR
         virtual void LocateControllerSpace(AZ::u32 handIndex) = 0;
 
         //! Api to retrieve the controller space data
-        virtual AZ::RPI::PoseData GetControllerPose(AZ::u32 handIndex) const = 0;
+        virtual AZ::RHI::ResultCode GetControllerPose(AZ::u32 handIndex, AZ::RPI::PoseData& outPoseData) const = 0;
+
+        //! Api to retrieve the controller space data associated with local view translated and rotated by 60 deg left or right based on handIndex
+        virtual AZ::RHI::ResultCode GetControllerStagePose(AZ::u32 handIndex, AZ::RPI::PoseData& outPoseData) const = 0;
 
         //! Api to retrieve the controller scale data
         virtual float GetControllerScale(AZ::u32 handIndex) const = 0;
 
         //! Api to retrieve the front view space data
-        virtual AZ::RPI::PoseData GetViewFrontPose() const = 0;
+        virtual AZ::RHI::ResultCode GetViewFrontPose(AZ::RPI::PoseData& outPoseData) const = 0;
+
+        //! Api to retrieve the local view space data
+        virtual AZ::RHI::ResultCode GetViewLocalPose(AZ::RPI::PoseData& outPoseData) const = 0;
+
+        //! Api to retrieve the controller X button state
+        virtual float GetXButtonState() const = 0;
+
+        //! Api to retrieve the controller Y button state
+        virtual float GetYButtonState() const = 0;
+
+        //! Api to retrieve the controller A button state
+        virtual float GetAButtonState() const = 0;
+
+        //! Api to retrieve the controller B button state
+        virtual float GetBButtonState() const = 0;
+
+        //! Api to retrieve the joystick controller state related to x-axis
+        virtual float GetXJoyStickState(AZ::u32 handIndex) const = 0;
+
+        //! Api to retrieve the joystick controller state related to y-axis
+        virtual float GetYJoyStickState(AZ::u32 handIndex) const = 0;
+
+        //! Api to retrieve the controller Y button state
+        virtual float GetSqueezeState(AZ::u32 handIndex) const = 0;
+
+        //! Api to retrieve the controller Y button state
+        virtual float GetTriggerState(AZ::u32 handIndex) const = 0;
 
     private:
 

+ 1 - 1
Gems/XR/Code/Include/XR/XRSwapChain.h

@@ -80,7 +80,7 @@ namespace XR
         };
 
         //! Returns the view swap chain related to the index.
-        SwapChain::View* GetView(const AZ::u32 swapChainIndex) const;
+        SwapChain::View* GetView(AZ::u32 swapChainIndex) const;
 
         //! Returns the image associated with the provided image
         //! index and view swap chain index.

+ 15 - 5
Gems/XR/Code/Include/XR/XRSystem.h

@@ -62,16 +62,26 @@ namespace XR
         AZ::u32 GetSwapChainWidth(AZ::u32 viewIndex) const override;
         AZ::u32 GetSwapChainHeight(AZ::u32 viewIndex) const override;
         AZ::RHI::Format GetSwapChainFormat(AZ::u32 viewIndex) const override;
-        AZ::RPI::FovData GetViewFov(AZ::u32 viewIndex) const override;
-        AZ::RPI::PoseData GetViewPose(AZ::u32 viewIndex) const override;
-        AZ::RPI::PoseData GetViewFrontPose() const override;
-        AZ::RPI::PoseData GetControllerPose(AZ::u32 handIndex) const override;
+        AZ::RHI::ResultCode GetViewFov(AZ::u32 viewIndex, AZ::RPI::FovData& outFovData) const override;
+        AZ::RHI::ResultCode GetViewPose(AZ::u32 viewIndex, AZ::RPI::PoseData& outPoseData) const override;
+        AZ::RHI::ResultCode GetViewFrontPose(AZ::RPI::PoseData& outPoseData) const override;
+        AZ::RHI::ResultCode GetViewLocalPose(AZ::RPI::PoseData& outPoseData) const override;
+        AZ::RHI::ResultCode GetControllerStagePose(AZ::u32 handIndex, AZ::RPI::PoseData& outPoseData) const override;
+        AZ::RHI::ResultCode GetControllerPose(AZ::u32 handIndex, AZ::RPI::PoseData& outPoseData) const override;
         float GetControllerScale(AZ::u32 handIndex) const override;
         bool ShouldRender() const override;
         AZ::Matrix4x4 CreateProjectionOffset(float angleLeft, float angleRight, 
                                              float angleBottom, float angleTop, 
-                                             float nearDist, float farDist) override;
+                                             float nearDist, float farDist, bool reverseDepth) override;
         AZ::RHI::XRRenderingInterface* GetRHIXRRenderingInterface() override;
+        float GetXButtonState() const override;
+        float GetYButtonState() const override;
+        float GetAButtonState() const override;
+        float GetBButtonState() const override;
+        float GetXJoyStickState(AZ::u32 handIndex) const override;
+        float GetYJoyStickState(AZ::u32 handIndex) const override;
+        float GetSqueezeState(AZ::u32 handIndex) const override;
+        float GetTriggerState(AZ::u32 handIndex) const override;
         ///////////////////////////////////////////////////////////////////
 
         ///////////////////////////////////////////////////////////////////

+ 7 - 2
Gems/XR/Code/Include/XR/XRUtils.h

@@ -12,6 +12,11 @@
 
 namespace XR
 {
-    //! Creates an off-center projection matrix suitable for VR
-    AZ::Matrix4x4 CreateProjectionOffset(float angleLeft, float angleRight, float angleBottom, float angleTop, float nearDist, float farDist);
+    //! Creates an off-center projection matrix suitable for VR. It does the following in order to provide a stereoscopic projection
+    //! Stretch more horizontally and vertically
+    //! Generate asymmetric or off-center projection matrix
+    //! Right handed coord system as Openxr provides data in that system
+    //! Provides support for reverse depth in case we want better depth precision
+    //! Handles the case where farDist is less than nearDist whereby it will place far plane at infinity. 
+    AZ::Matrix4x4 CreateProjectionOffset(float angleLeft, float angleRight, float angleBottom, float angleTop, float nearDist, float farDist, bool reverseDepth);
 }

+ 1 - 1
Gems/XR/Code/Source/XRSwapChain.cpp

@@ -10,7 +10,7 @@
 
 namespace XR
 { 
-    SwapChain::View* SwapChain::GetView(const AZ::u32 swapchainIndex) const
+    SwapChain::View* SwapChain::GetView(AZ::u32 swapchainIndex) const
     {
         return m_viewSwapchains[swapchainIndex].get();
     }

+ 102 - 12
Gems/XR/Code/Source/XRSystem.cpp

@@ -186,23 +186,50 @@ namespace XR
         return false;
     }
 
-    AZ::RPI::FovData System::GetViewFov(AZ::u32 viewIndex) const
+    AZ::RHI::ResultCode System::GetViewFov(AZ::u32 viewIndex, AZ::RPI::FovData& outFovData) const
     {
-        return m_device->GetViewFov(viewIndex);
+        return m_device->GetViewFov(viewIndex, outFovData);
     }
 
-    AZ::RPI::PoseData System::GetViewPose(AZ::u32 viewIndex) const
+    AZ::RHI::ResultCode System::GetViewPose(AZ::u32 viewIndex, AZ::RPI::PoseData& outPoseData) const
     {
-        return m_device->GetViewPose(viewIndex);
+        return m_device->GetViewPose(viewIndex, outPoseData);
     }
 
-    AZ::RPI::PoseData System::GetControllerPose(AZ::u32 handIndex) const
+    AZ::RHI::ResultCode System::GetControllerPose(AZ::u32 handIndex, AZ::RPI::PoseData& outPoseData) const
     {
         if (m_session->IsSessionRunning())
         {
-            return m_session->GetControllerPose(handIndex);
+            return m_session->GetControllerPose(handIndex, outPoseData);
         }
-        return AZ::RPI::PoseData();
+        return AZ::RHI::ResultCode::NotReady;
+    }
+
+    AZ::RHI::ResultCode System::GetControllerStagePose(AZ::u32 handIndex, AZ::RPI::PoseData& outPoseData) const
+    {
+        if (m_session->IsSessionRunning())
+        {
+            return m_session->GetControllerStagePose(handIndex, outPoseData);
+        }
+        return AZ::RHI::ResultCode::NotReady;
+    }
+
+    AZ::RHI::ResultCode System::GetViewFrontPose(AZ::RPI::PoseData& outPoseData) const
+    {
+        if (m_session->IsSessionRunning())
+        {
+            return m_session->GetViewFrontPose(outPoseData);
+        }
+        return AZ::RHI::ResultCode::NotReady;
+    }
+
+    AZ::RHI::ResultCode System::GetViewLocalPose(AZ::RPI::PoseData& outPoseData) const
+    {
+        if (m_session->IsSessionRunning())
+        {
+            return m_session->GetViewLocalPose(outPoseData);
+        }
+        return AZ::RHI::ResultCode::NotReady;
     }
 
     float System::GetControllerScale(AZ::u32 handIndex) const
@@ -214,20 +241,83 @@ namespace XR
         return 1.0f;
     }
 
-    AZ::RPI::PoseData System::GetViewFrontPose() const
+    float System::GetSqueezeState(AZ::u32 handIndex) const
+    {
+        if (m_session->IsSessionRunning())
+        {
+            return m_session->GetSqueezeState(handIndex);
+        }
+        return 0.0f;
+    }
+
+    float System::GetTriggerState(AZ::u32 handIndex) const
+    {
+        if (m_session->IsSessionRunning())
+        {
+            return m_session->GetTriggerState(handIndex);
+        }
+        return 0.0f;
+    }
+
+    float System::GetXButtonState() const
+    {
+        if (m_session->IsSessionRunning())
+        {
+            return m_session->GetXButtonState();
+        }
+        return 0.0f;
+    }
+
+    float System::GetYButtonState() const
+    {
+        if (m_session->IsSessionRunning())
+        {
+            return m_session->GetYButtonState();
+        }
+        return 0.0f;
+    }
+
+    float System::GetAButtonState() const
+    {
+        if (m_session->IsSessionRunning())
+        {
+            return m_session->GetAButtonState();
+        }
+        return 0.0f;
+    }
+
+    float System::GetBButtonState() const
+    {
+        if (m_session->IsSessionRunning())
+        {
+            return m_session->GetBButtonState();
+        }
+        return 0.0f;
+    }
+
+    float System::GetXJoyStickState(AZ::u32 handIndex) const
+    {
+        if (m_session->IsSessionRunning())
+        {
+            return m_session->GetXJoyStickState(handIndex);
+        }
+        return 0.0f;
+    }
+
+    float System::GetYJoyStickState(AZ::u32 handIndex) const
     {
         if (m_session->IsSessionRunning())
         {
-            return m_session->GetViewFrontPose();
+            return m_session->GetYJoyStickState(handIndex);
         }
-        return AZ::RPI::PoseData();
+        return 0.0f;
     }
 
     AZ::Matrix4x4 System::CreateProjectionOffset(float angleLeft, float angleRight, 
                                                  float angleBottom, float angleTop, 
-                                                 float nearDist, float farDist)
+                                                 float nearDist, float farDist, bool reverseDepth)
     {
-        return XR::CreateProjectionOffset(angleLeft, angleRight, angleBottom, angleTop, nearDist, farDist);
+        return XR::CreateProjectionOffset(angleLeft, angleRight, angleBottom, angleTop, nearDist, farDist, reverseDepth);
     }
 
     AZ::RHI::XRRenderingInterface* System::GetRHIXRRenderingInterface()

+ 19 - 3
Gems/XR/Code/Source/XRUtils.cpp

@@ -10,7 +10,7 @@
 
 namespace XR
 {
-    AZ::Matrix4x4 CreateProjectionOffset(float angleLeft, float angleRight, float angleBottom, float angleTop, float nearDist, float farDist)
+    AZ::Matrix4x4 CreateProjectionOffset(float angleLeft, float angleRight, float angleBottom, float angleTop, float nearDist, float farDist, bool reverseDepth)
     {
         AZ::Matrix4x4 result;
         AZ_MATH_ASSERT(nearDist > 0.0f, "Near plane distance must be greater than 0");
@@ -32,16 +32,32 @@ namespace XR
         { 
             result.SetRow(0, 2.0f / tanAngleWidth, 0.0f, (left + right) / tanAngleWidth, 0.0f);
             result.SetRow(1, 0.0f, 2.0f / tanAngleHeight, (top + bottom) / tanAngleHeight, 0.0f);
-            result.SetRow(2, 0.0f, 0.0f, -1 * (farDist + nearDist) * invfn, -2.0f * farDist * nearDist * invfn);
+            if(reverseDepth)
+            { 
+                result.SetRow(2, 0.0f, 0.0f, 2.0f * nearDist * invfn, 2.0f * farDist * nearDist * invfn);
+            }
+            else
+            {
+                result.SetRow(2, 0.0f, 0.0f, -1.0f * (farDist + nearDist) * invfn, -2.0f * farDist * nearDist * invfn);
+            }
             result.SetRow(3, 0.0f, 0.0f, -1.0f, 0.0f);
         }
         else
         {
+            // place the far plane at infinity
             result.SetRow(0, 2.0f / tanAngleWidth, 0.0f, (left + right) / tanAngleWidth, 0.0f);
             result.SetRow(1, 0.0f, 2.0f / tanAngleHeight, (top + bottom) / tanAngleHeight, 0.0f);
-            result.SetRow(2, 0.0f, 0.0f, -1.0f, -2.0f * nearDist);
+            if (reverseDepth)
+            {
+                result.SetRow(2, 0.0f, 0.0f, 0.0f, 2.0f * nearDist);
+            }
+            else
+            {
+                result.SetRow(2, 0.0f, 0.0f, -1.0f, -2.0f * nearDist);
+            }
             result.SetRow(3, 0.0f, 0.0f, -1.0f, 0.0f);
         }
+
         return result;
     }
 }