Weapon field of view independent of 'fov': r_gunfov cvar

At high 'fov' values the weapon looked quite distorted.
Now it's rendered with an independent FOV, which looks better.
Note that the 'fov' cvar sets fov_x, while this is based on fov_y
(which is calculated from fov_x), so it's indeed different values:
r_gunfov seems to correspond to fov 90.
We use r_gunfov 80 as default, because it looks better.
This commit is contained in:
Daniel Gibson 2018-04-21 18:23:32 +02:00
parent d4b6e936ef
commit a5e97682a3
7 changed files with 49 additions and 31 deletions

View file

@ -77,6 +77,7 @@ cvar_t *r_fullbright;
cvar_t *r_novis;
cvar_t *r_lerpmodels;
cvar_t *gl_lefthand;
cvar_t *r_gunfov;
cvar_t *r_farsee;
cvar_t *r_lightlevel;
@ -1199,6 +1200,7 @@ void
R_Register(void)
{
gl_lefthand = ri.Cvar_Get("hand", "0", CVAR_USERINFO | CVAR_ARCHIVE);
r_gunfov = ri.Cvar_Get("r_gunfov", "80", CVAR_USERINFO | CVAR_ARCHIVE);
r_farsee = ri.Cvar_Get("r_farsee", "0", CVAR_LATCH | CVAR_ARCHIVE);
r_norefresh = ri.Cvar_Get("r_norefresh", "0", 0);
r_fullbright = ri.Cvar_Get("r_fullbright", "0", 0);

View file

@ -663,7 +663,7 @@ R_DrawAliasModel(entity_t *e)
glDepthRange(gldepthmin, gldepthmin + 0.3 * (gldepthmax - gldepthmin));
}
if ((currententity->flags & RF_WEAPONMODEL) && (gl_lefthand->value == 1.0F))
if (currententity->flags & RF_WEAPONMODEL)
{
extern void R_MYgluPerspective(GLdouble fovy, GLdouble aspect,
GLdouble zNear, GLdouble zFar);
@ -671,13 +671,16 @@ R_DrawAliasModel(entity_t *e)
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glScalef(-1, 1, 1);
R_MYgluPerspective(r_newrefdef.fov_y,
if (gl_lefthand->value == 1.0F)
glScalef(-1, 1, 1);
R_MYgluPerspective(r_gunfov->value, // render weapon with a different FOV so it's not distorted at high view FOV
(float)r_newrefdef.width / r_newrefdef.height,
4, 4096);
glMatrixMode(GL_MODELVIEW);
glCullFace(GL_BACK);
if (gl_lefthand->value == 1.0F)
glCullFace(GL_BACK);
}
glPushMatrix();
@ -772,12 +775,13 @@ R_DrawAliasModel(entity_t *e)
glEnable(GL_CULL_FACE);
}
if ((currententity->flags & RF_WEAPONMODEL) && (gl_lefthand->value == 1.0F))
if (currententity->flags & RF_WEAPONMODEL)
{
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glCullFace(GL_FRONT);
if (gl_lefthand->value == 1.0F)
glCullFace(GL_FRONT);
}
if (currententity->flags & RF_TRANSLUCENT)

View file

@ -166,6 +166,7 @@ extern int r_viewcluster, r_viewcluster2, r_oldviewcluster, r_oldviewcluster2;
extern cvar_t *r_norefresh;
extern cvar_t *gl_lefthand;
extern cvar_t *r_gunfov;
extern cvar_t *r_farsee;
extern cvar_t *r_drawentities;
extern cvar_t *r_drawworld;

View file

@ -63,9 +63,6 @@ vec3_t vpn;
vec3_t vright;
vec3_t gl3_origin;
hmm_mat4 gl3_projectionMatrix; // eye cord -> clip coord
hmm_mat4 gl3_world_matrix; // the view matrix: world coord -> eye coord
int gl3_visframecount; /* bumped when going to a new PVS */
int gl3_framecount; /* used for dlight push checking */
@ -99,6 +96,7 @@ cvar_t *gl3_particle_fade_factor;
cvar_t *gl3_particle_square;
cvar_t *gl_lefthand;
cvar_t *r_gunfov;
cvar_t *r_farsee;
cvar_t *gl3_intensity;
@ -193,6 +191,7 @@ static void
GL3_Register(void)
{
gl_lefthand = ri.Cvar_Get("hand", "0", CVAR_USERINFO | CVAR_ARCHIVE);
r_gunfov = ri.Cvar_Get("r_gunfov", "80", CVAR_USERINFO | CVAR_ARCHIVE);
r_farsee = ri.Cvar_Get("r_farsee", "0", CVAR_LATCH | CVAR_ARCHIVE);
gl_drawbuffer = ri.Cvar_Get("gl_drawbuffer", "GL_BACK", 0);
@ -1164,7 +1163,7 @@ static hmm_mat4 rotAroundAxisXYZ(float aroundXdeg, float aroundYdeg, float aroun
}
// equivalent to R_MYgluPerspective() but returning a matrix instead of setting internal OpenGL state
static hmm_mat4
hmm_mat4
GL3_MYgluPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar)
{
// calculation of left, right, bottom, top is from R_MYgluPerspective() of old gl backend
@ -1236,7 +1235,7 @@ SetupGL(void)
{
float screenaspect = (float)gl3_newrefdef.width / gl3_newrefdef.height;
float dist = (r_farsee->value == 0) ? 4096.0f : 8192.0f;
gl3_projectionMatrix = GL3_MYgluPerspective(gl3_newrefdef.fov_y, screenaspect, 4, dist);
gl3state.uni3DData.transProjMat4 = GL3_MYgluPerspective(gl3_newrefdef.fov_y, screenaspect, 4, dist);
}
glCullFace(GL_FRONT);
@ -1260,11 +1259,9 @@ SetupGL(void)
hmm_vec3 trans = HMM_Vec3(-gl3_newrefdef.vieworg[0], -gl3_newrefdef.vieworg[1], -gl3_newrefdef.vieworg[2]);
viewMat = HMM_MultiplyMat4( viewMat, HMM_Translate(trans) );
gl3_world_matrix = viewMat;
gl3state.uni3DData.transViewMat4 = viewMat;
}
gl3state.uni3DData.transProjMat4 = gl3_projectionMatrix;
gl3state.uni3DData.transViewMat4 = gl3_world_matrix;
gl3state.uni3DData.transModelMat4 = gl3_identityMat4;
gl3state.uni3DData.time = gl3_newrefdef.time;

View file

@ -809,18 +809,29 @@ GL3_DrawAliasModel(entity_t *entity)
glDepthRange(gl3depthmin, gl3depthmin + 0.3 * (gl3depthmax - gl3depthmin));
}
if ((entity->flags & RF_WEAPONMODEL) && (gl_lefthand->value == 1.0F))
if (entity->flags & RF_WEAPONMODEL)
{
origProjMat = gl3state.uni3DData.transProjMat4;
// to mirror gun so it's rendered left-handed, just invert X-axis column
// of projection matrix
for(int i=0; i<4; ++i)
{
gl3state.uni3DData.transProjMat4.Elements[0][i] = -gl3state.uni3DData.transProjMat4.Elements[0][i];
}
//GL3_UpdateUBO3D(); Note: GL3_RotateForEntity() will call this,no need to do it twice before drawing
extern hmm_mat4 GL3_MYgluPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar);
glCullFace(GL_BACK);
origProjMat = gl3state.uni3DData.transProjMat4;
// render weapon with a different FOV (r_gunfov) so it's not distorted at high view FOV
float screenaspect = (float)gl3_newrefdef.width / gl3_newrefdef.height;
float dist = (r_farsee->value == 0) ? 4096.0f : 8192.0f;
gl3state.uni3DData.transProjMat4 = GL3_MYgluPerspective(r_gunfov->value, screenaspect, 4, dist);
if(gl_lefthand->value == 1.0F)
{
// to mirror gun so it's rendered left-handed, just invert X-axis column
// of projection matrix
for(int i=0; i<4; ++i)
{
gl3state.uni3DData.transProjMat4.Elements[0][i] = -gl3state.uni3DData.transProjMat4.Elements[0][i];
}
//GL3_UpdateUBO3D(); Note: GL3_RotateForEntity() will call this,no need to do it twice before drawing
glCullFace(GL_BACK);
}
}
@ -891,11 +902,12 @@ GL3_DrawAliasModel(entity_t *entity)
gl3state.uni3DData.transModelMat4 = origModelMat;
GL3_UpdateUBO3D();
if ((entity->flags & RF_WEAPONMODEL) && (gl_lefthand->value == 1.0F))
if (entity->flags & RF_WEAPONMODEL)
{
gl3state.uni3DData.transProjMat4 = origProjMat;
GL3_UpdateUBO3D();
glCullFace(GL_FRONT);
if(gl_lefthand->value == 1.0F)
glCullFace(GL_FRONT);
}
if (entity->flags & RF_TRANSLUCENT)

View file

@ -305,9 +305,6 @@ extern cplane_t frustum[4];
extern vec3_t gl3_origin;
hmm_mat4 gl3_projectionMatrix; // eye cord -> clip coord
hmm_mat4 gl3_world_matrix; // the view matrix: world coord -> eye coord
extern gl3image_t *gl3_notexture; /* use for bad textures */
extern gl3image_t *gl3_particletexture; /* little dot for particles */
@ -497,6 +494,7 @@ extern cvar_t *r_fullbright;
extern cvar_t *r_norefresh;
extern cvar_t *gl_lefthand;
extern cvar_t *r_gunfov;
extern cvar_t *r_farsee;
extern cvar_t *r_drawworld;

View file

@ -119,8 +119,12 @@ Graphics (all renderers):
to `2` the gun is drawn regardless of the FOV. This is the default
in Yamagi Quake II.
* **fov**: Sets the field of view. If the *horplus* cvar is set to `1`,
this is forced to 90.
* **fov**: Sets the field of view.
* **r_gunfov**: The weapons are rendered with a custom field of view,
independently of the global **fov**, so they are not distorted at high FOVs.
A value of `75` should look identical to the old code at `fov 90`,
it defaults to `80` because that looks a bit better.
* **horplus**: If set to 1 (the default) the horplus algorithm is used
to calculate an optimal horizontal and vertical field of view, independent