Gyro tightening

A practical way to avoid a noisy gyro signal, or shaky hands.
Unlike a deadzone, inputs below the threshold are "squeezed towards
zero", so they are not completely ignored. Source:
http://gyrowiki.jibbsmart.com/blog:good-gyro-controls-part-1:the-gyro-is-a-mouse#toc9
This commit is contained in:
Jaime Moreira 2024-06-04 15:48:42 -04:00
parent 0e63bad7d9
commit 24b03b61f8
4 changed files with 85 additions and 10 deletions

View file

@ -598,6 +598,10 @@ Set `0` by default.
for people who hold the controller upright, or use a device with the
controller attached to the screen, e.g. Steam Deck.
* **gyro_tightening**: Threshold of rotation in degrees per second,
where gyro inputs below it will be dampened. Meant to counter a
noisy gyro and involuntary hand movements. Default `3.5`.
* **gyro_calibration_(x/y/z)**: Offset values on each axis of the gyro
which helps it reach true "zero movement", complete stillness. These
values are wrong if you see your in-game view "drift" when leaving

View file

@ -162,6 +162,7 @@ cvar_t *gyro_turning_axis; // yaw or roll
// Gyro sensitivity
static cvar_t *gyro_yawsensitivity;
static cvar_t *gyro_pitchsensitivity;
static cvar_t *gyro_tightening;
// Gyro is being used in this very moment
static qboolean gyro_active = false;
@ -1069,6 +1070,30 @@ IN_ApplyExpo(thumbstick_t stick, float exponent)
return result;
}
/*
* Minimize gyro movement when under a small threshold.
* http://gyrowiki.jibbsmart.com/blog:good-gyro-controls-part-1:the-gyro-is-a-mouse#toc9
*/
static thumbstick_t
IN_TightenInput(float yaw, float pitch)
{
thumbstick_t input = { yaw, pitch };
const float magnitude = IN_StickMagnitude(input);
#ifdef NATIVE_SDL_GYRO
const float threshold = (M_PI / 180.0f) * gyro_tightening->value;
#else
const float threshold = (2560.0f / 180.0f) * gyro_tightening->value;
#endif
if (magnitude < threshold)
{
const float scale = magnitude / threshold;
input.x *= scale;
input.y *= scale;
}
return input;
}
/*
* Delete flick stick's buffer of angle samples for smoothing
*/
@ -1198,6 +1223,7 @@ IN_Move(usercmd_t *cmd)
static float joystick_yaw, joystick_pitch;
static float joystick_forwardmove, joystick_sidemove;
static thumbstick_t left_stick = {0}, right_stick = {0};
thumbstick_t gyro_in = {0};
if (m_filter->value)
{
@ -1378,16 +1404,21 @@ IN_Move(usercmd_t *cmd)
* cl_sidespeed->value * 2.0f * joystick_sidemove;
}
if (gyro_yaw)
if (gyro_yaw || gyro_pitch)
{
cl.viewangles[YAW] += m_yaw->value * gyro_yawsensitivity->value
* cl_yawspeed->value * gyro_yaw * gyroViewFactor;
gyro_in = IN_TightenInput(gyro_yaw, gyro_pitch);
}
if (gyro_pitch)
if (gyro_in.x)
{
cl.viewangles[YAW] += m_yaw->value * gyro_yawsensitivity->value
* cl_yawspeed->value * gyro_in.x * gyroViewFactor;
}
if (gyro_in.y)
{
cl.viewangles[PITCH] -= m_pitch->value * gyro_pitchsensitivity->value
* cl_pitchspeed->value * gyro_pitch * gyroViewFactor;
* cl_pitchspeed->value * gyro_in.y * gyroViewFactor;
}
// Flick Stick: flick in progress, changing the yaw angle to the target progressively
@ -2286,6 +2317,7 @@ IN_Init(void)
gyro_yawsensitivity = Cvar_Get("gyro_yawsensitivity", "1.0", CVAR_ARCHIVE);
gyro_pitchsensitivity = Cvar_Get("gyro_pitchsensitivity", "1.0", CVAR_ARCHIVE);
gyro_tightening = Cvar_Get("gyro_tightening", "3.5", CVAR_ARCHIVE);
gyro_turning_axis = Cvar_Get("gyro_turning_axis", "0", CVAR_ARCHIVE);
gyro_mode = Cvar_Get("gyro_mode", "2", CVAR_ARCHIVE);

View file

@ -165,6 +165,7 @@ cvar_t *gyro_turning_axis; // yaw or roll
// Gyro sensitivity
static cvar_t *gyro_yawsensitivity;
static cvar_t *gyro_pitchsensitivity;
static cvar_t *gyro_tightening;
// Gyro is being used in this very moment
static qboolean gyro_active = false;
@ -1058,6 +1059,26 @@ IN_ApplyExpo(thumbstick_t stick, float exponent)
return result;
}
/*
* Minimize gyro movement when under a small threshold.
* http://gyrowiki.jibbsmart.com/blog:good-gyro-controls-part-1:the-gyro-is-a-mouse#toc9
*/
static thumbstick_t
IN_TightenInput(float yaw, float pitch)
{
thumbstick_t input = { yaw, pitch };
const float magnitude = IN_StickMagnitude(input);
const float threshold = (M_PI / 180.0f) * gyro_tightening->value;
if (magnitude < threshold)
{
const float scale = magnitude / threshold;
input.x *= scale;
input.y *= scale;
}
return input;
}
/*
* Delete flick stick's buffer of angle samples for smoothing
*/
@ -1187,6 +1208,7 @@ IN_Move(usercmd_t *cmd)
static float joystick_yaw, joystick_pitch;
static float joystick_forwardmove, joystick_sidemove;
static thumbstick_t left_stick = {0}, right_stick = {0};
thumbstick_t gyro_in = {0};
if (m_filter->value)
{
@ -1367,16 +1389,21 @@ IN_Move(usercmd_t *cmd)
* cl_sidespeed->value * 2.0f * joystick_sidemove;
}
if (gyro_yaw)
if (gyro_yaw || gyro_pitch)
{
cl.viewangles[YAW] += m_yaw->value * gyro_yawsensitivity->value
* cl_yawspeed->value * gyro_yaw * gyroViewFactor;
gyro_in = IN_TightenInput(gyro_yaw, gyro_pitch);
}
if (gyro_pitch)
if (gyro_in.x)
{
cl.viewangles[YAW] += m_yaw->value * gyro_yawsensitivity->value
* cl_yawspeed->value * gyro_in.x * gyroViewFactor;
}
if (gyro_in.y)
{
cl.viewangles[PITCH] -= m_pitch->value * gyro_pitchsensitivity->value
* cl_pitchspeed->value * gyro_pitch * gyroViewFactor;
* cl_pitchspeed->value * gyro_in.y * gyroViewFactor;
}
// Flick Stick: flick in progress, changing the yaw angle to the target progressively
@ -2278,6 +2305,7 @@ IN_Init(void)
gyro_yawsensitivity = Cvar_Get("gyro_yawsensitivity", "1.0", CVAR_ARCHIVE);
gyro_pitchsensitivity = Cvar_Get("gyro_pitchsensitivity", "1.0", CVAR_ARCHIVE);
gyro_tightening = Cvar_Get("gyro_tightening", "3.5", CVAR_ARCHIVE);
gyro_turning_axis = Cvar_Get("gyro_turning_axis", "0", CVAR_ARCHIVE);
gyro_mode = Cvar_Get("gyro_mode", "2", CVAR_ARCHIVE);

View file

@ -1780,6 +1780,7 @@ static menuslider_s s_gyro_yawsensitivity_slider;
static menuslider_s s_gyro_pitchsensitivity_slider;
static menulist_s s_gyro_invertyaw_box;
static menulist_s s_gyro_invertpitch_box;
static menuslider_s s_gyro_tightening_slider;
static menuseparator_s s_calibrating_text[2];
static menuaction_s s_calibrate_gyro;
@ -1917,6 +1918,15 @@ Gyro_MenuInit(void)
s_gyro_invertpitch_box.itemnames = yesno_names;
s_gyro_invertpitch_box.curvalue = (Cvar_VariableValue("gyro_pitchsensitivity") < 0);
s_gyro_tightening_slider.generic.type = MTYPE_SLIDER;
s_gyro_tightening_slider.generic.x = 0;
s_gyro_tightening_slider.generic.y = (y += 20);
s_gyro_tightening_slider.generic.name = "tightening thresh";
s_gyro_tightening_slider.cvar = "gyro_tightening";
s_gyro_tightening_slider.minvalue = 0.0f;
s_gyro_tightening_slider.maxvalue = 12.0f;
s_gyro_tightening_slider.slidestep = 0.5f;
s_calibrating_text[0].generic.type = MTYPE_SEPARATOR;
s_calibrating_text[0].generic.x = 48 * scale + 32;
s_calibrating_text[0].generic.y = (y += 20);
@ -1939,6 +1949,7 @@ Gyro_MenuInit(void)
Menu_AddItem(&s_gyro_menu, (void *)&s_gyro_pitchsensitivity_slider);
Menu_AddItem(&s_gyro_menu, (void *)&s_gyro_invertyaw_box);
Menu_AddItem(&s_gyro_menu, (void *)&s_gyro_invertpitch_box);
Menu_AddItem(&s_gyro_menu, (void *)&s_gyro_tightening_slider);
Menu_AddItem(&s_gyro_menu, (void *)&s_calibrating_text[0]);
Menu_AddItem(&s_gyro_menu, (void *)&s_calibrating_text[1]);
Menu_AddItem(&s_gyro_menu, (void *)&s_calibrate_gyro);