A lot of the effect of FOV is on how fast you seem to move through the world (it's still the same speed; this is purely perceptional). With too wide a horizontal FOV you'll seem to move very fast, with too narrow you'll seem to move very slow. 90 degrees horizontal appears to be the "sweet spot", and the game developer can tune a desired movement speed for individual games from there.
It's also the case that 4 times 90 degrees is 360 degrees, which is a circle. Setting up horizontal FOV so that it maps nicely to the front/left/back/right quadrants appears to make sense.
And finally there's the old chestnut of precedence and inertia. I'm not sure if any games offered player-adjustable FOV before Quake, but Quake did and it defaulted to 90 degrees horizontal; it's easy to imagine other games just picking up on 90 degrees from there.
It's worth noting that nowadays 90 degrees is becoming less common, with games (particularly modern FPSs) setting on a slightly lower value - in or around 80.
If you want to aspect-correct your FOV you can use something like this (I don't pretend it's the only or best way, but it is consistent with the FOV calculator at http://www.emsai.net/projects/widescreen/fovcalc/; this assumes relative to a base aspect ratio of 4:3 (you can adjust that in the call to CalcFovY below))
float CalcFovX (float fov_y, float width, float height)
{
float a;
float y;
if (fov_y < 1) fov_y = 1;
if (fov_y > 179) fov_y = 179;
y = height / tan (fov_y / 360 * M_PI);
a = atan (width / y);
a = a * 360 / M_PI;
return a;
}
float CalcFovY (float fov_x, float width, float height)
{
float a;
float x;
if (fov_x < 1) fov_x = 1;
if (fov_x > 179) fov_x = 179;
x = width / tan (fov_x / 360 * M_PI);
a = atan (height / x);
a = a * 360 / M_PI;
return a;
}
Then call it like:
// you should use #define of const instead of magic numbers here, which are just here for illustration purposes in this sample
fov_y = CalcFovY (playerAdjustableFOV, 4, 3); // this is your base aspect that adjusted FOV should be relative to
fov_x = CalcFovX (fov_y, width, height); // this is your actual window width and height
The calculated fov_x and fov_y can then be plugged into the following perspective matrix (OpenGL convention):
1.0f / tan (DEG2RAD (fov_x) * 0.5f),
0,
0,
0,
0,
1.0f / tan (DEG2RAD (fov_y) * 0.5f),
0,
0,
0,
0,
(zFar + zNear) / (zNear - zFar),
-1,
0,
0,
(2.0f * zFar * zNear) / (zNear - zFar),
0
This will give you an aspect-adjusted horizontal FOV that maintains vertical FOV irrespective of resolution and aspect ratio.