Implementation of real-fake 6DoF

https://www.youtube.com/watch?v=zBjC2FHuC7Q

This video explains it (in the comments)
This commit is contained in:
Simon 2022-02-27 15:45:20 +00:00
parent f112cfe88a
commit 62f54f8986
12 changed files with 128 additions and 63 deletions

View file

@ -1991,9 +1991,9 @@ static void CG_DrawCrosshair3D(void)
vec3_t viewaxis[3];
vec3_t weaponangles;
vec3_t origin;
CG_CalculateVRWeaponPosition(origin, weaponangles, qtrue);
CG_CalculateVRWeaponPosition(origin, weaponangles, qfalse);
AnglesToAxis(weaponangles, viewaxis);
maxdist = cgs.glconfig.vidWidth * stereoSep * zProj / (2 * xmax);
maxdist = (cgs.glconfig.vidWidth * stereoSep * zProj / (2 * xmax)) * 1.5f;
VectorMA(origin, maxdist, viewaxis[0], endpos);
CG_Trace(&trace, origin, NULL, NULL, endpos, 0, MASK_SHOT);
@ -2544,7 +2544,8 @@ CG_DrawWeapReticle
static void CG_DrawWeapReticle( void )
{
int weap;
vec4_t color = {0, 0, 0, 1};
vec4_t light_color = {0.7, 0.7, 0.7, 1};
vec4_t black = {0.0, 0.0, 0.0, 1};
float indent = 0.16;
float X_WIDTH=640;
@ -2555,11 +2556,11 @@ static void CG_DrawWeapReticle( void )
CG_AdjustFrom640( &x, &y, &w, &h );
// sides
CG_FillRect( 0, 0, (X_WIDTH * indent), Y_HEIGHT, color );
CG_FillRect( X_WIDTH * (1 - indent), 0, (X_WIDTH * indent), Y_HEIGHT, color );
CG_FillRect( 0, 0, (X_WIDTH * indent), Y_HEIGHT, black );
CG_FillRect( X_WIDTH * (1 - indent), 0, (X_WIDTH * indent), Y_HEIGHT, black );
// top/bottom
CG_FillRect( X_WIDTH * indent, 0, X_WIDTH * (1-indent), Y_HEIGHT * indent, color );
CG_FillRect( X_WIDTH * indent, Y_HEIGHT * (1-indent), X_WIDTH * (1-indent), Y_HEIGHT * indent, color );
CG_FillRect( X_WIDTH * indent, 0, X_WIDTH * (1-indent), Y_HEIGHT * indent, black );
CG_FillRect( X_WIDTH * indent, Y_HEIGHT * (1-indent), X_WIDTH * (1-indent), Y_HEIGHT * indent, black );
{
// center
@ -2571,10 +2572,10 @@ static void CG_DrawWeapReticle( void )
}
// hairs
CG_FillRect( 84, 239, 177, 2, color ); // left
CG_FillRect( 320, 242, 1, 58, color ); // center top
CG_FillRect( 319, 300, 2, 178, color ); // center bot
CG_FillRect( 380, 239, 177, 2, color ); // right
CG_FillRect( 84, 239, 177, 2, light_color ); // left
CG_FillRect( 320, 242, 1, 58, light_color ); // center top
CG_FillRect( 319, 300, 2, 178, light_color ); // center bot
CG_FillRect( 380, 239, 177, 2, light_color ); // right
}
}
@ -2741,7 +2742,7 @@ void CG_DrawActive( stereoFrame_t stereoView ) {
VectorClear(pos);
VectorSubtract(vr->hmdposition, vr->hmdorigin, hmdposition);
rotateAboutOrigin(hmdposition[2], hmdposition[0],
cg.refdefViewAngles[YAW] - vr->weaponangles[YAW], pos);
cg.refdefViewAngles[YAW] - vr->calculated_weaponangles[YAW], pos);
VectorScale(pos, worldscale, pos);
VectorSubtract(cg.refdef.vieworg, pos, vieworg);

View file

@ -837,7 +837,7 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) {
DEBUGNAME("EV_CHANGE_WEAPON");
trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.selectSound );
if ( clientNum == cg.predictedPlayerState.clientNum ) {
vr->realign = 4; // auto trigger weapon re-align in 4 frames
vr->realign = 3; // auto trigger weapon re-align in 4 frames
int position = vr->weapon_stabilised ? 4 : (vr->right_handed ? 1 : 2);
trap_HapticEvent("weapon_switch", 0, 0, 100, 0, 0);
}
@ -922,7 +922,7 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) {
trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.teleInSound );
CG_SpawnEffect( position);
if (clientNum == cg.predictedPlayerState.clientNum) {
vr->realign = 4; // auto trigger weapon re-align in 4 frames
vr->realign = 3; // auto trigger weapon re-align in 4 frames
trap_HapticEvent("spark", 0, 0, 80, 0, 0);
}
break;

View file

@ -1110,6 +1110,7 @@ extern vmCvar_t cg_drawTimer;
extern vmCvar_t cg_drawFPS;
extern vmCvar_t cg_drawSnapshot;
extern vmCvar_t cg_draw3dIcons;
extern vmCvar_t cg_debugWeaponAiming;
extern vmCvar_t cg_drawIcons;
extern vmCvar_t cg_drawAmmoWarning;
extern vmCvar_t cg_drawCrosshair;

View file

@ -116,6 +116,7 @@ vmCvar_t cg_drawIcons;
vmCvar_t cg_drawAmmoWarning;
vmCvar_t cg_drawCrosshair;
vmCvar_t cg_drawCrosshairNames;
vmCvar_t cg_debugWeaponAiming;
vmCvar_t cg_fragMessage;
vmCvar_t cg_drawRewards;
vmCvar_t cg_crosshairSize;
@ -234,6 +235,7 @@ static cvarTable_t cvarTable[] = {
{ &cg_drawFPS, "cg_drawFPS", "0", CVAR_ARCHIVE },
{ &cg_drawSnapshot, "cg_drawSnapshot", "0", CVAR_ARCHIVE },
{ &cg_draw3dIcons, "cg_draw3dIcons", "1", CVAR_ARCHIVE },
{ &cg_debugWeaponAiming, "cg_debugWeaponAiming", "0", CVAR_ARCHIVE },
{ &cg_drawIcons, "cg_drawIcons", "1", CVAR_ARCHIVE },
{ &cg_drawAmmoWarning, "cg_drawAmmoWarning", "1", CVAR_ARCHIVE },
{ &cg_drawAttacker, "cg_drawAttacker", "0", CVAR_ARCHIVE },

View file

@ -1646,11 +1646,18 @@ void CG_CalculateVROffHandPosition( vec3_t origin, vec3_t angles )
origin[2] += vr->hmdposition[1] * worldscale;
}
VectorCopy(vr->offhandangles, angles);
// if ( cgs.localServer )
if ( !cgs.localServer )
{
angles[YAW] += cg.refdefViewAngles[YAW] - vr->weaponangles[YAW];
//Calculate the offhand angles from "first principles"
float deltaYaw = SHORT2ANGLE(cg.predictedPlayerState.delta_angles[YAW]);
angles[YAW] = deltaYaw + (vr->clientviewangles[YAW] - vr->hmdorientation[YAW]) + vr->offhandangles[YAW];
float deltaPitch = SHORT2ANGLE(cg.predictedPlayerState.delta_angles[PITCH]);
angles[PITCH] = vr->realign_pitch + deltaPitch + (vr->clientviewangles[PITCH] - vr->hmdorientation[PITCH]) + vr->offhandangles[PITCH];
angles[ROLL] = vr->offhandangles[ROLL];
} else
{
VectorCopy(vr->offhandangles, angles);
angles[YAW] += (cg.refdefViewAngles[YAW] - vr->hmdorientation[YAW]);
}
}

View file

@ -621,7 +621,8 @@ CG_CalcViewValues
Sets cg.refdef view values
===============
*/
static int CG_CalcViewValues( void ) {
void CG_RailTrail2( clientInfo_t *ci, vec3_t start, vec3_t end );
static int CG_CalcViewValues( stereoFrame_t stereoView ) {
playerState_t *ps;
memset( &cg.refdef, 0, sizeof( cg.refdef ) );
@ -635,21 +636,6 @@ static int CG_CalcViewValues( void ) {
ps = &cg.predictedPlayerState;
/*
vec3_t weaponorigin, weaponangles;
CG_CalculateVRWeaponPosition(weaponorigin, weaponangles, qfalse);
vec3_t forward, end, dir;
AngleVectors(weaponangles, forward, NULL, NULL);
VectorMA(weaponorigin, 2048, forward, end);
trace_t trace;
CG_Trace( &trace, ps->origin, NULL, NULL, end, cg.predictedPlayerState.clientNum, MASK_SOLID );
VectorSubtract(trace.endpos, ps->origin, dir);
VectorCopy(vr->calculated_weaponangles, vr->last_calculated_weaponangles);
vectoangles(dir, vr->calculated_weaponangles);
//convert to real-world angles
vr->calculated_weaponangles[YAW] -= (cg.refdefViewAngles[YAW] - vr->last_calculated_weaponangles[YAW]);
*/
//HACK!! - should change this to a renderer function call
//Indicate to renderer whether we are in deathcam mode, We don't want sky in death cam mode
trap_Cvar_Set( "vr_deathCam", ((ps->stats[STAT_HEALTH] <= 0) &&
@ -719,6 +705,69 @@ static int CG_CalcViewValues( void ) {
CG_OffsetFirstPersonView();
}
if (stereoView == STEREO_LEFT)
{
//Have to do this here so we can use the predicted player state
if (--vr->realign == 0)
{
VectorCopy(vr->hmdposition, vr->hmdorigin);
vr->realign_pitch -= (cg.predictedPlayerState.viewangles[PITCH]-vr->calculated_weaponangles[PITCH]) ;
vr->realign_pitch = AngleNormalize180(vr->realign_pitch);
}
VectorCopy(vr->calculated_weaponangles, vr->last_calculated_weaponangles);
vec3_t weaponorigin, weaponangles;
CG_CalculateVRWeaponPosition(weaponorigin, weaponangles, qfalse);
vec3_t forward, end, dir;
AngleVectors(weaponangles, forward, NULL, NULL);
VectorMA(weaponorigin, 4096, forward, end);
trace_t trace;
CG_Trace(&trace, weaponorigin, NULL, NULL, end, cg.predictedPlayerState.clientNum,
MASK_SOLID);
if (cg_debugWeaponAiming.integer)
{
clientInfo_t ci;
VectorSet(ci.color1, 1, 0, 0); // Forward is red
CG_RailTrail2(&ci, weaponorigin, trace.endpos);
}
{
VectorSubtract(trace.endpos, cg.refdef.vieworg, dir);
vectoangles(dir, vr->calculated_weaponangles);
vec3_t origin;
VectorCopy(ps->origin, origin);
origin[2] += cg.predictedPlayerState.viewheight;
int timeDelta = cg.time - cg.duckTime;
if ( timeDelta < DUCK_TIME) {
origin[2] -= cg.duckChange * (DUCK_TIME - timeDelta) / DUCK_TIME;
}
vec3_t forward2, end2, dir2;
AngleVectors(vr->calculated_weaponangles, forward2, NULL, NULL);
VectorMA(origin, 4096, forward2, end2);
trace_t trace2;
CG_Trace(&trace2, cg.refdef.vieworg, NULL, NULL, end2, cg.predictedPlayerState.clientNum,
MASK_SOLID);
if (cg_debugWeaponAiming.integer)
{
clientInfo_t ci;
VectorSet(ci.color1, 0, 1, 0);
CG_RailTrail2(&ci, cg.refdef.vieworg, trace2.endpos);
}
//convert to real-world angles - should be very close to real weapon angles
float deltaYaw = SHORT2ANGLE(cg.predictedPlayerState.delta_angles[YAW]);
vr->calculated_weaponangles[YAW] -= (deltaYaw + (vr->clientviewangles[YAW] -
vr->hmdorientation[YAW]));
}
}
// position eye relative to origin
if (!cgs.localServer)
{
@ -734,7 +783,7 @@ static int CG_CalcViewValues( void ) {
vec3_t angles;
VectorCopy(vr->hmdorientation, angles);
angles[YAW] =
(cg.refdefViewAngles[YAW] + vr->hmdorientation[YAW]) - vr->weaponangles[YAW];
(cg.refdefViewAngles[YAW] + vr->hmdorientation[YAW]) - vr->last_calculated_weaponangles[YAW];
AnglesToAxis(angles, cg.refdef.viewaxis);
}
} else {
@ -742,7 +791,7 @@ static int CG_CalcViewValues( void ) {
vec3_t angles;
angles[ROLL] = vr->hmdorientation[ROLL];
angles[PITCH] = vr->weaponangles[PITCH];
angles[YAW] = (cg.refdefViewAngles[YAW] - vr->hmdorientation[YAW]) + vr->weaponangles[YAW];
angles[YAW] = (cg.refdefViewAngles[YAW] - vr->hmdorientation[YAW]) + vr->last_calculated_weaponangles[YAW];
AnglesToAxis(angles, cg.refdef.viewaxis);
} else {
AnglesToAxis(cg.refdefViewAngles, cg.refdef.viewaxis);
@ -869,7 +918,7 @@ void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demo
&& cg_thirdPerson.integer;
// build cg.refdef
inwater = CG_CalcViewValues();
inwater = CG_CalcViewValues( stereoView );
// first person blend blobs, done after AnglesToAxis
if ( !cg.renderingThirdPerson ) {

View file

@ -234,7 +234,9 @@ void CG_ConvertFromVR(vec3_t in, vec3_t offset, vec3_t out)
{
//We are connected to a multiplayer server, so make the appropriate adjustment to the view
//angles as we send orientation to the server that includes the weapon angles
rotateAboutOrigin(vrSpace[0], vrSpace[1], cg.refdefViewAngles[YAW] - vr->weaponangles[YAW], r);
float deltaYaw = SHORT2ANGLE(cg.predictedPlayerState.delta_angles[YAW]);
float angleYaw = deltaYaw + (vr->clientviewangles[YAW] - vr->hmdorientation[YAW]);
rotateAboutOrigin(vrSpace[0], vrSpace[1], angleYaw, r);
} else {
rotateAboutOrigin(vrSpace[0], vrSpace[1], cg.refdefViewAngles[YAW] - vr->hmdorientation[YAW], r);
}
@ -262,11 +264,10 @@ void CG_CalculateVRWeaponPosition( vec3_t origin, vec3_t angles, qboolean crossh
if (!crosshair)
{
//Use absolute position for the faked 6DoF for multiplayer
vec3_t offset, weaponposition;
VectorSubtract(vr->weaponposition, vr->hmdorigin, weaponposition);
VectorCopy(weaponposition, offset);
offset[1] = vr->weaponoffset[1]; // up/down is index 1 in this case
CG_ConvertFromVR(offset, cg.refdef.vieworg, origin);
vec3_t weaponoffset;
VectorSubtract(vr->weaponposition, vr->hmdorigin, weaponoffset);
weaponoffset[1] = vr->weaponoffset[1]; // up/down is index 1 in this case
CG_ConvertFromVR(weaponoffset, cg.refdef.vieworg, origin);
origin[2] -= PLAYER_HEIGHT;
origin[2] += vr->hmdposition[1] * worldscale;
}
@ -286,15 +287,18 @@ void CG_CalculateVRWeaponPosition( vec3_t origin, vec3_t angles, qboolean crossh
}
VectorCopy(vr->weaponangles, angles);
if ( !cgs.localServer )
{
//take player state angles provided by server
angles[YAW] = cg.predictedPlayerState.viewangles[YAW]; //cg.snap->ps.viewangles[YAW];
angles[PITCH] = cg.predictedPlayerState.viewangles[PITCH]; //cg.snap->ps.viewangles[PITCH];
} else
//Calculate the weapon angles from "first principles"
float deltaYaw = SHORT2ANGLE(cg.predictedPlayerState.delta_angles[YAW]);
angles[YAW] = deltaYaw + (vr->clientviewangles[YAW] - vr->hmdorientation[YAW]) + vr->weaponangles[YAW];
float deltaPitch = SHORT2ANGLE(cg.predictedPlayerState.delta_angles[PITCH]);
angles[PITCH] = vr->realign_pitch + deltaPitch + vr->weaponangles[PITCH];
angles[ROLL] = vr->weaponangles[ROLL];
} else
{
VectorCopy(vr->weaponangles, angles);
angles[YAW] += (cg.refdefViewAngles[YAW] - vr->hmdorientation[YAW]);
}
}
@ -497,7 +501,7 @@ void CG_RailTrail2( clientInfo_t *ci, vec3_t start, vec3_t end ) {
le->leType = LE_FADE_RGB;
le->startTime = cg.time;
le->endTime = cg.time + 25;
le->endTime = cg.time + 15;
le->lifeRate = 1.0 / ( le->endTime - le->startTime );
re->shaderTime = cg.time / 1000.0f;

View file

@ -312,6 +312,7 @@ void CL_AdjustAngles( void ) {
cl.viewangles[PITCH] -= speed*cl_pitchspeed->value * CL_KeyState (&in_lookup);
cl.viewangles[PITCH] += speed*cl_pitchspeed->value * CL_KeyState (&in_lookdown);
*/
cl.viewangles[YAW] -= vr.hmdorientation_delta[YAW];
//Make angles good
@ -322,6 +323,8 @@ void CL_AdjustAngles( void ) {
cl.viewangles[PITCH] = vr.hmdorientation[PITCH];
cl.viewangles[ROLL] = vr.hmdorientation[ROLL];
VectorCopy(cl.viewangles, vr.clientviewangles);
}
/*
@ -602,13 +605,10 @@ void CL_FinishMove( usercmd_t *cmd ) {
vr.local_server = qfalse;
vec3_t angles;
VectorCopy(vr.weaponangles, angles);
VectorCopy(vr.calculated_weaponangles, angles);
if (--vr.realign == 0)
{
VectorCopy(vr.hmdposition, vr.hmdorigin);
vr.realign_pitch -= (cl.snap.ps.viewangles[PITCH]-vr.weaponangles[PITCH]) ;
}
float deltaPitch = SHORT2ANGLE(cl.snap.ps.delta_angles[PITCH]);
Com_Printf("realign_pitch: %f, delta pitch: %f", vr.realign_pitch, deltaPitch);
angles[PITCH] += vr.realign_pitch;
angles[YAW] += (cl.viewangles[YAW] - vr.hmdorientation[YAW]);
@ -619,7 +619,7 @@ void CL_FinishMove( usercmd_t *cmd ) {
}
vec3_t out;
rotateAboutOrigin(cmd->rightmove, cmd->forwardmove, -vr.weaponangles[YAW], out);
rotateAboutOrigin(cmd->rightmove, cmd->forwardmove, -vr.calculated_weaponangles[YAW], out);
cmd->rightmove = out[0];
cmd->forwardmove = out[1];
}

View file

@ -59,7 +59,7 @@ void VR_InitCvars( void )
vr_weaponPitch = Cvar_Get ("vr_weaponPitch", "-20", CVAR_ARCHIVE);
vr_heightAdjust = Cvar_Get ("vr_heightAdjust", "0.0", CVAR_ARCHIVE);
vr_twoHandedWeapons = Cvar_Get ("vr_twoHandedWeapons", "1", CVAR_ARCHIVE);
vr_refreshrate = Cvar_Get ("vr_refreshrate", "0", CVAR_ARCHIVE);
vr_refreshrate = Cvar_Get ("vr_refreshrate", "72", CVAR_ARCHIVE);
vr_weaponScope = Cvar_Get ("vr_weaponScope", "1", CVAR_ARCHIVE);
vr_rollWhenHit = Cvar_Get ("vr_rollWhenHit", "0", CVAR_ARCHIVE);
vr_hudYOffset = Cvar_Get ("vr_hudYOffset", "0", CVAR_ARCHIVE);

View file

@ -14,9 +14,10 @@ typedef struct {
qboolean local_server; // used in bg_pmove.c
int realign; // used to realign the weapon/playspace in a multiplayer game
int realign_pitch; // used to realign the weapon pitch in a multiplayer game
float realign_pitch; // used to realign the weapon pitch in a multiplayer game
int clientNum;
vec3_t clientviewangles; //orientation in the client - we use this in the cgame
vec3_t hmdposition;
vec3_t hmdorigin; //used to recenter the mp fake 6DoF playspace
@ -28,8 +29,8 @@ typedef struct {
vec3_t hmdorientation_delta;
vec3_t weaponangles;
// vec3_t calculated_weaponangles;
// vec3_t last_calculated_weaponangles;
vec3_t last_calculated_weaponangles;
vec3_t calculated_weaponangles; //Calculated as the angle required to hit the point that the controller is pointing at, but coming from the view origin
vec3_t weaponangles_last; // Don't use this, it is just for calculating delta!
vec3_t weaponangles_delta;

View file

@ -587,14 +587,14 @@ static void IN_VRButtonsChanged( qboolean isRightController, uint32_t buttons )
if (isRightController == !vr_righthanded->integer)
{
if ((buttons & ovrButton_RThumb) && !(controller->buttons & ovrButton_RThumb)) {
if ((buttons & ovrButton_LThumb) && !(controller->buttons & ovrButton_LThumb)) {
if (IN_GetButtonAction("SECONDARYTHUMBSTICK", action))
{
IN_SendButtonAction(action, qtrue);
}
vr.realign = 4;
} else if (!(buttons & ovrButton_RThumb) && (controller->buttons & ovrButton_RThumb)) {
vr.realign = 3;
} else if (!(buttons & ovrButton_LThumb) && (controller->buttons & ovrButton_LThumb)) {
if (IN_GetButtonAction("SECONDARYTHUMBSTICK", action))
{
IN_SendButtonAction(action, qfalse);

BIN
ui.zip

Binary file not shown.