How to only render fragments with Z from 0 to 1 in OpenGL?

I have been using OpenGL for a year now, but I just recently found out that OpenGL only clips vertices when the absolute value of the x,y or z coordinate is less than the absolute value of w coordinate. Previously I had assumed that the z coordinate would have to be 0 < z < w to be rendered. Is there any way to clip vertices with z less than 0, without a performance hit?

I am using OpenGL 4.4

I believe that OpenGL's standard clipping volume is [-1, 1] x [-1, 1] x [-1, 1]. You want to clip at [-1, 1] x [-1, 1] x [0, 1]. You can achieve this by transforming the z-coordinate after all transformations have been applied to the vertex position (model, view and projection transforms). In other words, you want to operate on the screen coordinates of the vertex.

On Homogeneous Coordinates

I'll quickly go over the w coordinate you are mentioning, so you understand what is happening. The w-coordinate is used to represent a 3D point in a 4D homogeneous representation. This representation is used to make matrix math more simple. Specifically, it lets you use a 4x4 matrix to perform translations, something which you can not do with a 3x3 matrix and 3D point representations.

As you are using a 4D representation for a 3D point, many combinations of 4 coordinates will describe the same 3D point. The actual position of your point can be obtained by dividing all components of the 4D representation by w. So for example, point [x,y,z,w] is located at the following 3D coordinates: [x/w, y/w, z/w].

This explains why you observed clipping at z > w. As in fact, the z-coordinate becomes z/w. Knowing that clipping occurs at z-coordinate > 1, you'll find that this is at:

z-coordinate > 1
<=> z/w > 1
<=> z > w

Solution: Clipping Between Z-Values 0 and 1

If you want to clip in range [0, 1] instead of the default [-1, 1], you simply need to remap the z-coordinate to this range. You'll want to do this after all vertex transformations have been applied in your vertex shader, so that you are working with screen coordinates. These are the coordinates where clipping is applied.

To remap, simply do:

z_new = (z_old * 2) - 1;

This will make sure, vertices which originally had z-coordinate 0, get mapped to -1. Coordinates with an original z-coordinate of 1 stay at 1. Everything in between is a linear interpolation of the two.

As you are just doing a small additional calculation per vertex in your vertex shader, you won't notice a hit in performance.

• Your solution is perfectly adequate, however I also need the increased precision floats have near the 0 value so a simple remapping is not enough. I have found this, but I am working on Linux and currently restrained to OpenGL 4.4. – Andreas May 11 '15 at 22:12
• I see, that's more difficult to solve indeed. You could try a logarithmic remapping to get more precision near 0. However, doing this will give you most precision at your far plane. Typically, you want most precision in the focus-point/ center (depth-wise) of your view, rather than at your near or far plane. Are you developing a very specific use case that requires precision for distant geometry? – Jelle van Campen May 12 '15 at 6:50
• The short answer is yes. The long answer is a bit more complicated, but essentially what I need is for every vertex with z<0 to be discarded. I will try to use the ARB_clip_control extension, but I have no idea how to use OpenGL extensions as of this moment. – Andreas May 12 '15 at 13:14