Skip to content

Commit

Permalink
Add Yaw HMD emulation
Browse files Browse the repository at this point in the history
  • Loading branch information
oneup03 committed Jun 28, 2024
1 parent 341bfb5 commit 2b5c9c4
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 20 deletions.
9 changes: 4 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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` |
Expand All @@ -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` |
Expand Down Expand Up @@ -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
Expand Down
75 changes: 63 additions & 12 deletions vrto3d/src/hmd_device_driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down Expand Up @@ -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");

Expand Down Expand Up @@ -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" : {
Expand Down Expand Up @@ -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;
Expand All @@ -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;
}

Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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;
}
}
8 changes: 6 additions & 2 deletions vrto3d/src/hmd_device_driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ struct StereoDisplayDriverConfiguration
int32_t render_width;
int32_t render_height;

float hmd_height;

float aspect_ratio;
float fov;
float depth;
Expand All @@ -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;

Expand Down Expand Up @@ -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_;
Expand Down
4 changes: 3 additions & 1 deletion vrto3d/vrto3d/resources/settings/default.vrsettings
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
Expand Down

0 comments on commit 2b5c9c4

Please sign in to comment.