Frustum Vs Perspective

0 views
Skip to first unread message

Ailene Goldhirsh

unread,
Aug 3, 2024, 6:08:38 PM8/3/24
to neusibmala

In 3D computer graphics, a viewing frustum[1] or view frustum[2] is the region of space in the modeled world that may appear on the screen; it is the field of view of a perspective virtual camera system.[2]

The exact shape of this region varies depending on what kind of camera lens is being simulated, but typically it is a frustum of a rectangular pyramid (hence the name). The planes that cut the frustum perpendicular to the viewing direction are called the near plane and the far plane. Objects closer to the camera than the near plane or beyond the far plane are not drawn. Sometimes, the far plane is placed infinitely far away from the camera so all objects within the frustum are drawn regardless of their distance from the camera.

Viewing-frustum culling is the process of removing from the rendering process those objects that lie completely outside the viewing frustum.[6] Rendering these objects would be a waste of resources since they are not directly visible. To make culling fast, it is usually done using bounding volumes surrounding the objects rather than the objects themselves.

The geometry is defined by a field of view angle (in the 'y' direction), as well as an aspect ratio. Further, a set of z-planes define the near and far bounds of the frustum. Together this information can be used to calculate a projection matrix for rendering transformation in a graphics pipeline.

What dimensions should you use for a perspective projection frustum? Initially I created a perspective matrix based on the width and height of the screen, with a calculated zNear value based on a 45degree FOV.

But then I realised that this isn't a sensible idea and you shouldn't base your frustum on pixels, and you should use logical units instead (else when the window / screen changes size, objects will change position or size).

So now I'm wondering what dimensions I should use for the logical planes of the frustum? How do you choose a zNear value? Is it sensible to base it on the desired FOV? I'm aware that having a small zNear value can mess with the z-buffer, which is why I initially based it on the FOV.

zNear and zFar are measured in world space, not in anything to do with pixels. Their scale will depend on the scale of the scene you're rendering and how close/far the camera will be to the geometry. For instance, if your scene is modeled in meters, you might set zNear to 0.1 and zFar to 1000 or so. This would let you get the camera as close as 10 cm from the geometry before it starts clipping, and let you see distances of up to 1 km. You can adjust these values if you have a smaller or larger scene or if you use different units.

For most cases, it's simpler to use gluPerspective instead of glFrustum. That lets you work in terms of the FOV and aspect ratio, which is more convenient than the width/height of the image on the near plane. If you compare the formulas listed in the docs for gluPerspective and glFrustum you can see how these functions correspond to each other. They do the same thing, except that gluPerspective has more convenient parameters, and doesn't handle off-center frusta (which are uncommon anyway).

zNear is not really related to field of view. FOV specifies the angle of the frustrum, while zNear describes the distance to the nearest clipping plane. As an example, here are two frustrums with the same FOV, but different near clipping planes.

A good approach to clipping planes is simply to put the zNear as far away as possible and the zFar as near as possible, while still encompassing your world. Putting zNear closer to the camera than any world object will ever sit is a waste of Z-buffer values that will never be used. If your world isn't very large, you don't need to worry about this too much, as you have plenty of Z-buffer to spare. If you're trying to render an insect 1cm from the camera at the same time as mountains 10km away... you'll probably experience some issues with Z-buffer precision!

And finally, a tip that really helped me: there are helper functions to ease the calculation of frustrums. Check out gluPerspective(). Instead of doing the math yourself, you just pass it FOV, aspect ratio, zNear, and zFar, and it will helpfully calculate the other 4 boundaries of the frustrum for you.

The word frustum refers to a solid shape that looks like a pyramid with the top cut off parallel to the base. This is the shape of the region that can be seen and rendered by a perspective cameraA component which creates an image of a particular viewpoint in your scene. The output is either drawn to the screen or captured as a texture. More info
See in Glossary. The following thought experiment should help to explain why this is the case.

Imagine holding a straight rod (a broom handle or a pencil, for example) end-on to a camera and then taking a picture. If the rod were held in the centre of the picture, perpendicular to the camera lens, then only its end would be visible as a circle on the picture; all other parts of it would be obscured. If you moved it upward, the lower side would start to become visible but you could hide it again by angling the rod upward. If you continued moving the rod up and angling it further upward, the circular end would eventually reach the top edge of the picture. At this point, any object above the line traced by the rod in world space would not be visible on the picture.

Unity calculates lights and shadows with the world space position as the reference point, for example 0, 0, 0 in a 3D scene. Flickering occurs when lights and shadows are far away from the world space position. To minimise flickering, you can enable camera-relative culling, so Unity uses the camera position as the relative position for shadow calculations. See Culling settings in Graphics settings.

Perspective projections render a virtual scene to make it appearlike a view from a real-world camera. Objects further from the camera appear tobe smaller and all lines appear to project toward vanishing points whichskew parallel lines. Perspective projections are almost always usedin gaming, movie special effects, and visualizations of virtual worlds.

A perspective projection defines a 3D area that projects out from thelocation of the camera along four boundary rays. The rays form a viewing frustumas shown in the image to the right. The frustum includes a front andback clipping plane that is parallel to the X-Y plane. Any models insidethis viewing frustum will be rendered. Any models outside thisviewing frustum will be clipped away.

The 3D points (left, bottom, near) and (right, top, near) define the lower-leftand upper-right corners of the viewing window. If you calculate the centerof the viewing window and cast this point back to the X-Y plane, this pointis the apex of the frustum. Casting rays from the apex through thefour points of the viewing window forms the frustum. (The location of theapex is displayed in the demo below as a small black dot.)

A projection matrix must get the verticesin a scene into the clipping volume, which is a 2 unit wide cube shown inthe image to the right. Doing this for a perspective projection is more challengingthan an orthographic projection because much more manipulation of thevertices is needed. The math is easy, but it requires some special tricksto get the math into a 4x4 transformation matrix. We need to perform the followingsteps to create a perspective projection transformation matrix:

A perspective frustum can be offset from the global origin along the X or Y axes.We need to place the apex of the frustum at the global origin for the perspective calculationsto work. The apex is located in the center of the viewing window in the XY plane.Therefore we calculate the center point of the viewing window and translateit to the origin. Notice that the z value is unchanged.

We need to project every vertex in our scene to its correct location in the2D viewing window. The 2D viewing window is the near planeof the frustum. Study the diagram to the right. Notice that the vertex (x,y,z)is projected to the viewing window by projecting a ray tothe camera (shown as an orange ray). The rendering location for the vertex is (x',y',near).From the diagram you can see that the y and y' values are related by proportionalright-triangles. These two triangles must have the same ratio of side lengths.Therefore, y'/near must be equal to y/z. Solving for y' gives(y/z)*near, or y' = (y*near)/z. Notethat near is a constant for a particular scene, while y and z are differentfor each vertex in a scene. Using the same logic, x' = (x*near)/z.

You will probably never implement code to create a perspective projection.It has been implemented for you in the learn_wegbl_matrix.js codefile. So what value was there in going through all of the above discussion?Many operations in computer graphics are performed by transformation matrices.If you can master the art of creating combinations of transformations,you can create amazing computer graphics programs. The previousdiscussion has hopefully helped you think in terms of chaining matrixtransformations to achieve a particular goal.

When you break down a perspective projection into its basic componentsit is very understandable how the math is accomplishing the desired manipulations.If you want to understand complex transformations, break them down into theirelementary steps.

I was looking on Three.js API and I found that the Frustum is used for the camera visible area. I was wondering if I can access the view frustum of my PerspectiveCamera and declare the frustum as an object. Basically, my goal is to color the frustum of the camera.

If you want to visualize the frustum of your camera, you can use a THREE.CameraHelper. It essentially does what you're describing in the question: it lets you color the frustum so you can visualize it.

If you want to read the data used to build the helper, you can access its .pointmap property. It's got lots of points that determine the position of the near plane (n1, n2, n3...), far plane (f1, f2, f3...), target, etc. To get better acquainted with what each key means, you can look at its constructor from line 38 to 83. The code is very well-documented in there.

c80f0f1006
Reply all
Reply to author
Forward
0 new messages