From 2b5c9c40d7ba3ba0befbe67a9a29b9ef4f892318 Mon Sep 17 00:00:00 2001 From: OneUp Date: Thu, 27 Jun 2024 23:07:01 -0500 Subject: [PATCH] Add Yaw HMD emulation --- README.md | 9 +-- vrto3d/src/hmd_device_driver.cpp | 75 ++++++++++++++++--- vrto3d/src/hmd_device_driver.h | 8 +- .../resources/settings/default.vrsettings | 4 +- 4 files changed, 76 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 65f1e0b..c1532e4 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,7 @@ Windows-only solution, but there are other solutions on Linux like MonadoVR. |---------------------|---------|---------------------------------------------------------------------------------------------|----------------| | `window_width` | `int` | The width of the application window. | `1920` | | `window_height` | `int` | The height of the application window. | `1080` | +| `hmd_height` | `float` | The height of the simulated HMD. | `1.0` | | `aspect_ratio` | `float` | The aspect ratio used to calculate vertical FoV | `1.77778` | | `fov` | `float` | The field of view (FoV) for the VR rendering. | `90.0` | | `depth` | `float` | The max depth. Overrides VR's IPD field. | `0.5` | @@ -24,7 +25,8 @@ Windows-only solution, but there are other solutions on Linux like MonadoVR. | `depth_gauge` | `bool` | Enable or disable SteamVR IPD depth gauge display. | `false` | | `display_latency` | `float` | The display latency in seconds. | `0.011` | | `display_frequency` | `float` | The display refresh rate, in Hz. | `60.0` | -| `ctrl_enable` | `bool` | Enables or disables Controller right stick y-axis mapped to HMD Pitch | `false` | +| `pitch_enable` | `bool` | Enables or disables Controller right stick y-axis mapped to HMD Pitch | `false` | +| `yaw_enable` | `bool` | Enables or disables Controller right stick x-axis mapped to HMD Yaw | `false` | | `ctrl_deadzone` | `float` | Controller Deadzone | `0.05` | | `ctrl_sensitivity` | `float` | Controller Sensitivity | `1.0` | | `num_user_settings` | `int` | The number of user settings defined below. | `3` | @@ -70,10 +72,7 @@ Windows-only solution, but there are other solutions on Linux like MonadoVR. - Overlays generally won't work on this virtual HMD - Recommend using a XInput controller - OpenXR games/mods seem to be more likely to work and be stable than OpenVR ones - - Select the OpenXR toggle in UEVR GUI - - Delete openvr_api.dll for REFramework -- Optional HMD pitch emulation can be turned on to help with games or mods that prevent you from adjusting the game camera's pitch with a controller/mouse (maps to XInput right stick Y-axis) - - REFramework lua files can be modified to remove the pitch lock. Search for `Stop the player from rotating the camera vertically` and remove the block of code from the `if` to its `end` +- Optional HMD pitch and yaw emulation can be turned on to help with games or mods that need it (maps to XInput right stick) - HDR doesn't seem to work currently - Several mods/games may override your settings - DLSS, TAA, and other temporal based settings often create a halo around objects. UEVR has a halo fix that lets you use TAA, but others may not diff --git a/vrto3d/src/hmd_device_driver.cpp b/vrto3d/src/hmd_device_driver.cpp index 7312770..4482620 100644 --- a/vrto3d/src/hmd_device_driver.cpp +++ b/vrto3d/src/hmd_device_driver.cpp @@ -58,6 +58,8 @@ MockControllerDeviceDriver::MockControllerDeviceDriver() display_configuration.window_width = vrs->GetInt32( stereo_display_settings_section, "window_width" ); display_configuration.window_height = vrs->GetInt32( stereo_display_settings_section, "window_height" ); + display_configuration.hmd_height = vrs->GetFloat(stereo_display_settings_section, "hmd_height"); + display_configuration.aspect_ratio = vrs->GetFloat(stereo_display_settings_section, "aspect_ratio"); display_configuration.fov = vrs->GetFloat(stereo_display_settings_section, "fov"); display_configuration.depth = vrs->GetFloat(stereo_display_settings_section, "depth"); @@ -85,7 +87,8 @@ MockControllerDeviceDriver::MockControllerDeviceDriver() } // Controller settings - display_configuration.ctrl_enable = vrs->GetBool(stereo_display_settings_section, "ctrl_enable"); + display_configuration.pitch_enable = vrs->GetBool(stereo_display_settings_section, "pitch_enable"); + display_configuration.yaw_enable = vrs->GetBool(stereo_display_settings_section, "yaw_enable"); display_configuration.ctrl_deadzone = vrs->GetFloat(stereo_display_settings_section, "ctrl_deadzone"); display_configuration.ctrl_sensitivity = vrs->GetFloat(stereo_display_settings_section, "ctrl_sensitivity"); @@ -215,7 +218,7 @@ vr::EVRInitError MockControllerDeviceDriver::Activate( uint32_t unObjectId ) ], "play_area" : [ 2.0, 2.0 ], "seated" : { - "translation" : [ 0.0, 0.0, 0.0 ], + "translation" : [ 0.0, 0.5, 0.0 ], "yaw" : 0.0 }, "standing" : { @@ -301,16 +304,17 @@ void MockControllerDeviceDriver::DebugRequest( const char *pchRequest, char *pch vr::DriverPose_t MockControllerDeviceDriver::GetPose() { static float currentPitch = 0.0f; // Keep track of the current pitch + static float currentYaw = 0.0f; // Keep track of the current yaw vr::DriverPose_t pose = { 0 }; - pose.qWorldFromDriverRotation.w = 1.f; - pose.qDriverFromHeadRotation.w = 1.f; + pose.qWorldFromDriverRotation = HmdQuaternion_Identity; + pose.qDriverFromHeadRotation = HmdQuaternion_Identity; - pose.qRotation.w = 1.f; + pose.qRotation = HmdQuaternion_Identity; pose.vecPosition[ 0 ] = 0.0f; - pose.vecPosition[ 1 ] = 1.0f; + pose.vecPosition[ 1 ] = stereo_display_component_->GetConfig().hmd_height; pose.vecPosition[ 2 ] = 0.0f; pose.poseIsValid = true; @@ -321,11 +325,24 @@ vr::DriverPose_t MockControllerDeviceDriver::GetPose() pose.shouldApplyHeadModel = false; // Adjust pitch based on controller input - if (stereo_display_component_->GetConfig().ctrl_enable) + if (stereo_display_component_->GetConfig().pitch_enable) + { + stereo_display_component_->AdjustPitch(currentPitch); + } + + // Adjust yaw based on controller input + if (stereo_display_component_->GetConfig().yaw_enable) { - stereo_display_component_->AdjustPitch(pose.qRotation, currentPitch); + stereo_display_component_->AdjustYaw(currentYaw); } + // Recompose the rotation quaternion from pitch and yaw + vr::HmdQuaternion_t pitchQuaternion = HmdQuaternion_FromEulerAngles(0, DEG_TO_RAD(currentPitch), 0); + vr::HmdQuaternion_t yawQuaternion = HmdQuaternion_FromEulerAngles(0, 0, DEG_TO_RAD(currentYaw)); + + // Combine pitch and yaw quaternions + pose.qRotation = HmdQuaternion_Normalize(yawQuaternion * pitchQuaternion); + return pose; } @@ -697,7 +714,7 @@ void StereoDisplayComponent::CheckUserSettings(uint32_t device_index) //----------------------------------------------------------------------------- // Purpose: Adjust HMD Pitch using XInput Right Stick YAxis //----------------------------------------------------------------------------- -void StereoDisplayComponent::AdjustPitch(vr::HmdQuaternion_t& qRotation, float& currentPitch) +void StereoDisplayComponent::AdjustPitch(float& currentPitch) { XINPUT_STATE state; ZeroMemory(&state, sizeof(XINPUT_STATE)); @@ -725,9 +742,43 @@ void StereoDisplayComponent::AdjustPitch(vr::HmdQuaternion_t& qRotation, float& currentPitch += (normalizedY * config_.ctrl_sensitivity); if (currentPitch > 90.0f) currentPitch = 90.0f; if (currentPitch < -90.0f) currentPitch = -90.0f; + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Adjust HMD Yaw using XInput Right Stick XAxis +//----------------------------------------------------------------------------- +void StereoDisplayComponent::AdjustYaw(float& currentYaw) +{ + XINPUT_STATE state; + ZeroMemory(&state, sizeof(XINPUT_STATE)); + DWORD dwResult = XInputGetState(0, &state); + + if (dwResult == ERROR_SUCCESS) + { + SHORT sThumbRX = state.Gamepad.sThumbRX; + float normalizedX = sThumbRX / 32767.0f; + + // Apply deadzone + if (std::abs(normalizedX) < config_.ctrl_deadzone) + { + normalizedX = 0.0f; + } + else + { + if (normalizedX > 0) + normalizedX = (normalizedX - config_.ctrl_deadzone) / (1.0f - config_.ctrl_deadzone); + else + normalizedX = (normalizedX + config_.ctrl_deadzone) / (1.0f - config_.ctrl_deadzone); + } + + // Scale Yaw + float yawAdjustment = -normalizedX * config_.ctrl_sensitivity; - // Adjust quaternion - vr::HmdQuaternion_t pitchQuaternion = HmdQuaternion_FromEulerAngles(0, DEG_TO_RAD(currentPitch), 0); - qRotation = HmdQuaternion_Normalize(qRotation * pitchQuaternion); + // Apply the incremental yaw adjustment to the current yaw + currentYaw += yawAdjustment; + if (currentYaw > 180.0f) currentYaw -= 360.0f; + if (currentYaw < -180.0f) currentYaw += 360.0f; } } diff --git a/vrto3d/src/hmd_device_driver.h b/vrto3d/src/hmd_device_driver.h index 0f3c8a4..7dbd114 100644 --- a/vrto3d/src/hmd_device_driver.h +++ b/vrto3d/src/hmd_device_driver.h @@ -43,6 +43,8 @@ struct StereoDisplayDriverConfiguration int32_t render_width; int32_t render_height; + float hmd_height; + float aspect_ratio; float fov; float depth; @@ -57,7 +59,8 @@ struct StereoDisplayDriverConfiguration float display_latency; float display_frequency; - bool ctrl_enable; + bool pitch_enable; + bool yaw_enable; float ctrl_deadzone; float ctrl_sensitivity; @@ -95,7 +98,8 @@ class StereoDisplayComponent : public vr::IVRDisplayComponent float GetDepth(); float GetConvergence(); void CheckUserSettings(uint32_t device_index); - void AdjustPitch(vr::HmdQuaternion_t& qRotation, float& currentPitch); + void AdjustPitch(float& currentPitch); + void AdjustYaw(float& currentYaw); private: StereoDisplayDriverConfiguration config_; diff --git a/vrto3d/vrto3d/resources/settings/default.vrsettings b/vrto3d/vrto3d/resources/settings/default.vrsettings index fcfa865..2e9c605 100644 --- a/vrto3d/vrto3d/resources/settings/default.vrsettings +++ b/vrto3d/vrto3d/resources/settings/default.vrsettings @@ -7,6 +7,7 @@ "vrto3d_display": { "window_width": 1920, "window_height": 1080, + "hmd_height": 1.0, "aspect_ratio": 1.77778, "fov": 90.0, "depth": 0.5, @@ -18,7 +19,8 @@ "depth_gauge": false, "display_latency": 0.011, "display_frequency": 60.0, - "ctrl_enable": false, + "pitch_enable": false, + "yaw_enable": false, "ctrl_deadzone": 0.05, "ctrl_sensitivity": 1.0, "num_user_settings": 3,