Frame: put the HUD at vr_hud_distance

The client DLL pushes every HUD item sideways by width / 36 per eye
(it works that out from vr_stereo_side). On the Frame's lenses that's
about 4.5 degrees an eye, so the HUD sat around 0.4 m away and was
hard on the eyes. The DLL is a submodule, so while it draws the HUD the
eyes are given as the mono ones (which is zero for it), and the whole
HUD pass is shifted here instead, by the pixels that put it
vr_hud_distance metres ahead given that eye's real position and focal
length. That also puts the centre print and the engine's FPS counter at
the same place. Scope mode and the screen layer are left alone.

vr_hud_distance is archived, in metres, and defaults to 1.0. The shift
for each eye is logged once.

Frame build only. Builds, haven't had it in the headset yet.
This commit is contained in:
Madison committed 2026-10-04 21:06:56 +09:00
1 parent 02e68f7916
commit 1eac3db3ce
5 files changed
+113 -1

No files matched your search

@@ -356,6 +356,32 @@ bool VR_GetEyeTransform(int eye, float worldScale, vec3_t offset, float* cantDeg
}
return true;
}
/*
How far to shift the 2D content (the HUD) in an eye's image, in pixels, positive to the right,
so that it sits vr_hud_distance metres ahead of the head. 0 for the mono eyes and the screen layer.
*/
float VR_GetHudShift(int eye)
{
if (eye < 0 || eye >= ovrMaxNumEyes || !gAppState.SessionActive || gAppState.Projections == NULL ||
VR_UseScreenLayer() || vr_hud_distance == NULL)
return 0.0f;
const XrView* view = &gAppState.Projections[eye];
const int width = gAppState.Renderer.FrameBuffer[eye].Width;
const float shift = VrEye_HudShiftPixels(view->pose.position.x, view->fov.angleLeft, view->fov.angleRight,
width, vr_hud_distance->value);
static bool logged[ovrMaxNumEyes];
if (!logged[eye])
{
logged[eye] = true;
ALOGI("[openxr] hud: eye %d at x %.1f mm, focal length %.0f px, vr_hud_distance %.2f m, shift %.1f px",
eye, view->pose.position.x * 1000.0f, VrEye_FocalPixels(view->fov.angleLeft, view->fov.angleRight, width),
vr_hud_distance->value, shift);
}
return shift;
}
#endif
void R_ChangeDisplaySettings( int width, int height, qboolean fullscreen );
@@ -437,6 +463,9 @@ convar_t *vr_quick_crouchjump;
convar_t *vr_stereo_side;
convar_t *vr_gesture_triggered_use;
convar_t *vr_use_gesture_boundary;
#ifdef L1VR_STEAM_FRAME
convar_t *vr_hud_distance;
#endif
void initialize_gl4es();
@@ -496,6 +525,9 @@ void VR_Init()
vr_quick_crouchjump = Cvar_Get( "vr_quick_crouchjump", "1", CVAR_ARCHIVE, "Set to 0 to disable quick crouch-jump mode (double clicking jump button triggers duck)" );
vr_gesture_triggered_use = Cvar_Get( "vr_gesture_triggered_use", "1", CVAR_ARCHIVE, "Set to 0 to disable use gesture, 1 to enable" );
vr_use_gesture_boundary = Cvar_Get( "vr_use_gesture_boundary", "0.35", CVAR_ARCHIVE, "Use gesture boundary" );
#ifdef L1VR_STEAM_FRAME
vr_hud_distance = Cvar_Get( "vr_hud_distance", "1.0", CVAR_ARCHIVE, "How far ahead the HUD sits, in metres" );
#endif
//Not to be changed by users, as it will be overwritten anyway
vr_stereo_side = Cvar_Get( "vr_stereo_side", "0", CVAR_READ_ONLY, "Eye being drawn" );
+5 -1
View File
@@ -33,4 +33,8 @@ extern convar_t *vr_gesture_triggered_use;
extern convar_t *vr_use_gesture_boundary;
//Used and updated continuously during rendering
extern convar_t *vr_stereo_side;
extern convar_t *vr_stereo_side;
#ifdef L1VR_STEAM_FRAME
extern convar_t *vr_hud_distance;
#endif
@@ -1148,6 +1148,52 @@ static void CL_DrawPause( void )
R_DrawStretchPic( x, y, width, height, 0, 0, 1, 1, cls.pauseIcon );
}
#ifdef L1VR_STEAM_FRAME
extern convar_t *vr_stereo_side;
float VR_GetHudShift( int eye );
void R_SetHudShift( float pixels );
bool isScopeEngaged( void );
/*
===============
CL_RedrawHUD
The client DLL puts its HUD in front of the screen with a fixed sideways shift of width / 36
per eye, which it works out from vr_stereo_side. That's about 0.4 m on the Frame's lenses, and
tiring. While it draws, the eyes are given as the mono ones (that's 0 for it, and the 2D
offset onto the optical axis still works for those), and the whole HUD is shifted here
instead, to where vr_hud_distance says. A scope is mono already, so that is left alone.
===============
*/
static void CL_RedrawHUD( void )
{
const int eye = vr_stereo_side->integer;
float shift;
if( eye < VR_EYE_LEFT || eye > VR_EYE_RIGHT || isScopeEngaged( ))
{
CL_DrawCenterPrint ();
clgame.dllFuncs.pfnRedraw( cl.time, cl.refdef.intermission );
return;
}
shift = VR_GetHudShift( eye );
vr_stereo_side->value = eye + 2;
vr_stereo_side->integer = eye + 2;
R_SetHudShift( shift );
R_Set2DMode( true );
CL_DrawCenterPrint ();
clgame.dllFuncs.pfnRedraw( cl.time, cl.refdef.intermission );
vr_stereo_side->value = eye;
vr_stereo_side->integer = eye;
R_SetHudShift( 0.0f );
R_Set2DMode( true );
}
#endif
void CL_DrawHUD( int state )
{
if( state == CL_ACTIVE && !cl.video_prepped )
@@ -1161,14 +1207,22 @@ void CL_DrawHUD( int state )
case CL_ACTIVE:
CL_DrawScreenFade ();
CL_DrawCrosshair ();
#ifdef L1VR_STEAM_FRAME
CL_RedrawHUD ();
#else
CL_DrawCenterPrint ();
clgame.dllFuncs.pfnRedraw( cl.time, cl.refdef.intermission );
#endif
break;
case CL_PAUSED:
CL_DrawScreenFade ();
CL_DrawCrosshair ();
#ifdef L1VR_STEAM_FRAME
CL_RedrawHUD ();
#else
CL_DrawCenterPrint ();
clgame.dllFuncs.pfnRedraw( cl.time, cl.refdef.intermission );
#endif
CL_DrawPause();
break;
case CL_LOADING:
@@ -43,11 +43,20 @@ typedef struct
static dirty_t scr_dirty, scr_old_dirty[2];
static qboolean scr_init = false;
#ifdef L1VR_STEAM_FRAME
float VR_GetHudShift( int eye );
#endif
int GetStereoDepthOffset()
{
if (vr_stereo_side->value >= VR_EYE_LEFT_MONO)
return 0;
#ifdef L1VR_STEAM_FRAME
// the same place the HUD is put
return (int)VR_GetHudShift( vr_stereo_side->integer );
#endif
return (int)( ( vr_stereo_side->value * -2.0f ) + 1.0f) * (scr_width->integer / 36.0f);
}
@@ -283,6 +283,16 @@ two are not the same point, so 2D content anchored to the buffer centre would no
the eyes. Shifting the ortho window here moves every 2D item at once.
===============
*/
#ifdef L1VR_STEAM_FRAME
// extra shift for the HUD pass (see CL_RedrawHUD), in pixels, positive to the right
static float r_hudShift = 0.0f;
void R_SetHudShift( float pixels )
{
r_hudShift = pixels;
}
#endif
void R_Get2DOffset( float *dx, float *dy )
{
*dx = *dy = 0.0f;
@@ -292,6 +302,9 @@ void R_Get2DOffset( float *dx, float *dy )
return;
VR_Get2DOffset( vr_stereo_side->integer, glState.width, glState.height, dx, dy );
#ifdef L1VR_STEAM_FRAME
*dx += r_hudShift;
#endif
}
/*