Jump to content
  • Advertisement
Sign in to follow this  
vexe

What makes a vertical FOV from a horizontal one?

This topic is 566 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Greetings all,

 

I have a working software renderer but I'm trying to understand what makes a FOV vertical vs horizontal.

First a bit of background on my setup. My calculations for the camera are as follow: I assume a normalized projection plane that has a height of 2. So from the middle going up 1, and from the middle going down is 1 too, total 2.

We know aspect_ratio = width/height = width/2. Thus width=2*aspect_ratio. So the size of the projection plane (or viewplane, whatever you want to call it) is `2*ar x 2`

From similar triangles relationships when calculating the projected coordinates, we get that d (distance to the projection plane) is `1/Tan(Fov/2)` which is how much we need to scale the unprojected y coordinate by. Divide that by aspect_ratio and that's how much we need to scale x by (because width is 2*ar, so we divide by ar to normalize it)

All of that makes sense to me and it works. Here's my camera setup function (not using matrices):
 

    void CameraInit(camera *Camera, vec WorldP, fixed Aspect, fixed FOV)
    {
        Camera->Position = WorldP;
        Camera->FOV = FOV;
    
        // tan fov/2
        Camera->Tan = Math_Tan(Camera->FOV / 2);
    
        // distance to the projection plane (which is of size=2*ar x 2).
        Camera->ScaleY = 1 / Camera->Tan;
    
        // we divide x by ar because we want to normalize things on the x too
        // otherwise we'd still be left in the range [-ar, +ar]
        Camera->ScaleX = Camera->ScaleY / Aspect;
    
        // near/far clipping planes
        Camera->NearZ = (fixed)0.01f;
        Camera->FarZ = (fixed)100.0f;
    }

And here's my perspective projection function:

    INLINE vec CameraToPerspective(vec CameraP, camera *Camera)
    {
        vec Result;
    
        Result = CameraP;
        fix ZInv = 1/Result.z;
        Result.x = (Result.x * Camera->ScaleX) * ZInv;
        Result.y = (Result.y * Camera->ScaleY) * ZInv;
    
        return(Result);
    }

My question is: What is this 'FOV' that I'm using? Is it a vertical field of view or horizontal? What makes a vertical FOV vs a horizontal one?
 

Can someone provide a better explanation than "it's because of how you calculate stuff" or "it's because that's how you write it in the matrix" (as given to me here, see comments in the answer...). Throughout this entire software renderer, there is NOT a single line of code that I don't understand deeply and thoroughly (except for quaternions which are still new to me), and I'd like to keep it this way.

Thanks a lot in advance!

Edited by vexe

Share this post


Link to post
Share on other sites
Advertisement

The FOV of the perspective camera is the horizontal FOV, you have to take account of the aspect ratio to compute the vertical FOV.
When you compute the distance to show a bounding sphere the use of the two and take the max is needed because of the aspect ratio (if the window is taller than wide).
Here how do that :

const float DistanceHorizontalFOV = Radius / tan(0.5f * FOV);
const float DistanceVerticalFOV = Radius / tan(0.5f * FOV * AspectRatio);
const float Distance = max(DistanceHorizontalFOV, DistanceVerticalFOV);
Edited by Alundra

Share this post


Link to post
Share on other sites

I was just telling someone how becoming a 3D artist helps me as a 3D programmer. Here's a pretty good example because I actually learned what I'm about to talk about in art, not programming.

 

When you  draw on paper or canvas or whatever, you are drawing on a 2D surface. About the beginning of the Renaissance, people figured out how to use perspective (mostly 1 point at first I believe) to make images appear 3D on a 2D surface. It's interesting how the mathematically proved perspective drawing. But basically they figured out that all the lines parallel to the viewer converge at a single point on the horizon called a vanishing point. By making all the lines converge like this you make 3D drawing possible. Lines that are parallel to the picture may become shorter because of depth, but they remain horizontal or vertical and never converge.

Reality, is probably closer to at least 4 point perspective with 4 vanishing points and probably even a bit more complex than that.

 

In two point perspective, things don't have to be exactly parallel or perpendicular to the viewer or picture. I think this picture is actually 3 point perspective with the third point above. But it's so slight, I'm not sure. Ignoring that, basically notice you have two vanishing points where lines converge. One off the page on the right and another off the page on the left. Look especially at the fence.

b2774db07a86ad1a22a5ec6207451111.jpg

 

The cone of vision is what determines where the two vanishing points are placed.

 

https://www.handprint.com/HP/WCL/perspect1.html

 

From the spot of the viewer (outside of the picture) to the vanishing points on the horizon forms an angle. That is the cone of vision, if I recall correctly. Often they will use a 90 degree cone of vision in art. This is basically the same thing as Field of View (FOV) although I recommend an FOV between 45 and 55 degrees for game programming.

 

It may help to think of cone of vision in terms of a camera rather than a person. The COV/FOV is the angle formed by the two horizontal vanishing points which are likely outside of the actual picture area. The closest object in the photo may be some distance away. So, the camera is some distance in front of the photo, if you imagine it that way. And it's the camera's position where the cone of vision begins and is measured.

 

And reality is that in the real world you have 4+ point perspective where there's more than two vanishing points. But you're not that likely to see the one above and the one below in most cases unless you are way above the area or way below it or you have a super wide FOV that gives you a fish-eye perspective. The picture above is a good example, because I think it's actually 3 point perspective with the lines pointing straight up slightly converging way outside of the picture.

 

With the Cone of Vision(COV), or FOV, the wider the cone becomes, the greater the angle, and the more the vanishing points spread apart. As they spread apart, everything in the scene widens much like looking through a zoom lens and zooming in. As the COV widens, things that were previously on the page are now off the page. As the COV narrows and the angle decreases, things that were previously not on the page are now on the page like zooming out or using a wide angle lens. Eventually, it starts really warping the image like a fish-eye lens.

 

The cone of vision is a cone. But you are often drawing on a rectangular piece of paper or canvas. Usually, the cone and vanishing points are outside of the frame of the picture. So, really this angle is just the angle between the vanishing points and is generally entirely outside of the picture area.

 

Since it's a cone, there's not really a horizontal or vertical because it's a circle and so horizontal and vertical are the same thing. People talking about the "horizontal" and "vertical" are probably imaging the angle to be between the horizon at the edges of the screen. I believe that is incorrect and that the vanishing points are generally off screen and it's really the angle between vanishing points that we're talking about here.

 

Oh. And is there a reason you are not using a perspective projection matrix which will do all this math for you? ;-)

 

EDIT: I just read the thread you connected from and see why you are not using matrices. You're going to want to start using matrices as quickly as possible, but I applaud your efforts to learn here. Your render is looking pretty nice. (I watched the video.) And yes, I think you just have the FOV set wrong. I've found angles between roughly 45 degrees and 55 degrees to look the most natural to my eye with game programming. You're getting some slight "fish-eye lens" distortion probably because of the FOV.

 

You may want to check out my videos on vectors and matrices if you are fairly new to the subjects.

I might also point out that I'm not absolutely certain that COV and FOV are equivalent. A 90 degree COV seems pretty popular in art, probably mostly because it's an easy angle to work with more than it looks right. Most artists just "eye ball" it anyway and don't actually measure anything. But again, I like a 45 degree FOV and that's a pretty big difference.

Edited by BBeck

Share this post


Link to post
Share on other sites

I happened to stumble across Jorge Rodriguez's YouTube channel,  probably because I searched for COV today. I thought there was some interesting insight as he goes into all the math involved in the perspective projection matrix. I have a vague idea of what's inside, but I've never actually coded it or figured out the exact math. He goes through it in great detail. His YouTube channel is just awesome in general, but this might be something you specifically might like and get some good mileage out of.

 

I was going through that and this:

https://unspecified.wordpress.com/2012/06/21/calculating-the-gluperspective-matrix-and-other-opengl-matrix-maths/

 

and it looks like there is a vertical and horizontal FOV because the screen is not square and you have to draw in the screen's aspect ratio. So, it's one FOV angle, but apparently the vertical is the angle by itself and the horizontal gets the aspect ratio change.

 

If I'm understanding it right, the horizontal FOV calculation would be almost twice the vertical FOV calculation with a 16:9 aspect ratio. That seems to be the explanation of why 45 to 55 degrees seems about right because that's going to be near 90 degrees horizontally, I think.

 

So yes, it appears that there is a bit of a difference between FOV and COV although I think it's still basically the same idea.

Edited by BBeck

Share this post


Link to post
Share on other sites

 

The FOV of the perspective camera is the horizontal FOV, you have to take account of the aspect ratio to compute the vertical FOV.
When you compute the distance to show a bounding sphere the use of the two and take the max is needed because of the aspect ratio (if the window is taller than wide).
Here how do that :

const float DistanceHorizontalFOV = Radius / tan(0.5f * FOV);
const float DistanceVerticalFOV = Radius / tan(0.5f * FOV * AspectRatio);
const float Distance = max(DistanceHorizontalFOV, DistanceVerticalFOV);

that is not how vertical fov is calculated. the aspect ratio should not be applied to the angular fov value but to the linear "Distance" value.

Share this post


Link to post
Share on other sites
What is this 'FOV' that I'm using?   Is it a vertical field of view or horizontal?

Most engines  use horizontal FOV.

 

 

 

What makes a vertical FOV vs a horizontal one?

Typically you select a horizontal FOV, which - combined with the aspect ratio - results in some corresponding vertical FOV.

 

Been a while since i had to write a software renderer (DX1 era), but as i recall...

H_FOV = 90 deg

AR = 2:1   ( w / h )

when looking down Z, at z=2, x= -2 or 2 for the left and right frustum planes. but y = -1 or 1 for the upper and lower frustum planes.

so H_FOV = 2 * atan(2/2) = 90 deg

and V_FOV = 2 * atan(1/2) = 53 deg.

 

Also, as i recall, you transform to homogeneous clipping space (-1 thru 1 in x and y), apply the sutherland-hodgemann clipping algo, then transform to screen space, which is where AR comes into play.

Edited by Norman Barrows

Share this post


Link to post
Share on other sites
Most engines  use horizontal FOV.

 

Most games I know use vertical FOV to get "Horizontal+" behavior on wider screens, i.e., wider screen (relative to height) means wider horizontal fov.

In any case, here's the variant using angles directly instead of going via the frustum planes for calculating vfov from hfov:

Basic trigonometry gives us

w / d = 2 * tan(hfov / 2)

h / d = 2 * tan(vfov / 2)

Which we can divide by one another to remove the distance

w / h = tan(hfov / 2) / tan(vfov / 2)

This can then be transformed into

vfov = 2 * tan-1(h/w * tan(hfov / 2))

or

hfov = 2 * tan-1(w/h * tan(vfov / 2))

So if hfov is 90? and w/h = 2

vfov = 2 * tan-1(0.5 * tan(45?)) = 53.13?

To the OP: Which FOV you use is mostly a matter of convention. For every aspect ratio you can compute an equivalent vertical FOV from a horizontal FOV or vice versa (you could even split the difference and use a diagonal FOV!). As mentioned above, many games specify a vertical FOV so that wider screens automatically result in a wider (horizontal) FOV. The physically correct FOV is determined by the user's distance to the screen (d above) and it's actual physical width and height (w and h above). With such a FOV you get a distortion free "window" into virtual 3D space (assuming the user is centered in front of the screen, if not you need a skewed projection matrix). However, most games use much higher FOVs than what would be physically correct, especially first person shooters.

IMO, the description of the OpenGL projection matrix here is pretty good: http://www.songho.ca/opengl/gl_projectionmatrix.html

Edited by l0calh05t

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!