Render to Far Plane (gl_Position.z = 1)

Hi,

this is a basic question but requires some in depth knowledge that I am missing.

I want to render a texture on the far plane, that is gl_Position.z = 1 & gl_Position.w = 1. Hard Coded and without Matrices.

It appears that GL clips including the far plane.

Can I modify the clipping comparison?
Is there a standard way to place geometry on the far plane?

Best Regards.

I don’t really know what you want to achieve.
But from what I understand, the easiest thing would be to render a full-screen image using a 2D orthographic projection, with disabling writing to the z-buffer.

Unfortunately, I do not want to fake the effect.
I want to render on the far plane of the perspective frustum.

For scientific reasons.

The largest possible depth value appears to be: 0.99999991059303297

Interestingly, the largest value provided by <math.h> and nextafter(1.0f, 0.0f) is 0.99999994039535522

I would have thought that the precision would be the same by now, can anyone elaborate on thi? Or point to some documentation.

glDepthRange (1, 1);

I presume that you mean:
glDepthRange (-1, 1);

Which is rather pointless, as it is the default GL mapping.

Use glDepthFunc(GL_LEQUAL) instead of default GL_LESS.
If you want in advance all your fragments (not part of them) to be in the far plane, try GL_ALWAYS.

[QUOTE=Christoph.LGDV;1286156]The largest possible depth value appears to be: 0.99999991059303297

Interestingly, the largest value provided by <math.h> and nextafter(1.0f, 0.0f) is 0.99999994039535522

I would have thought that the precision would be the same by now, can anyone elaborate on thi? Or point to some documentation.[/QUOTE]

The depth buffer typically stores unsigned normalised values. These are converted to floating-point by dividing by 2b-1, where b is the number of bits (so by 224-1=16777215 for a 24-bit depth buffer). A value of 1.0 is possible, the next largest value is ~0.99999994039535, but it’s possible that conversion to single-precision floating point results in an extra rounding error (normalised values use 2b-1 as the denominator while floating-point uses 2b).

Technically, the near and far planes should be within the clip volume (the clip test uses inequalities, -w<=z<=w), but GLSL doesn’t require that floating-point arithmetic follows IEEE-754 to the letter. In particular, while the results of addition, subtraction and multiplication are required to be correctly rounded, division is only required to be accurate to within 2.5 ULP (§4.7.1), and clipping implicitly performs a division.

[QUOTE=Christoph.LGDV;1286163]I presume that you mean:
glDepthRange (-1, 1);

Which is rather pointless, as it is the default GL mapping.[/QUOTE]
No; the default GL values are (0, 1); please see glDepthRange - OpenGL 4 Reference Pages

nearVal Specifies the mapping of the near clipping plane to window coordinates. The initial value is 0.
farVal Specifies the mapping of the far clipping plane to window coordinates. The initial value is 1.

The (-1, 1) range comes from the projection matrix.

I do mean glDepthRange (1, 1) which will position anything you draw exactly at the far clipping plane.

OK, there appears to be some confusion.

I want to prevent clipping of geometry on the far plane.
That means I do not care about the deph values.
I am concerned with the stage prior to window mapping.

If you are in doubt, you can check easily enough. Just place a quad in NDC and modify z. glDepthRange will have no effect on clipping

In my understanding, glDepthRange(a,b) will configure mapping from clipspace [-1 , 1-ulp] ->[a,b].

t

[QUOTE=Christoph.LGDV;1286168]OK, there appears to be some confusion.

I want to prevent clipping of geometry on the far plane. [/QUOTE]

Ok, that’s different from what you originally asked for. You said:

I want to render a texture on the far plane,

mhagain told you how. You just need to send down in-frustum primitives, and it will smash them onto the far plane.

To prevent clipping of geometry beyond the far plane you can use depth clamping (see ARB_depth_clamp, NV_depth_clamp, and AMD_depth_clamp_separate, or this section in the OpenGL Wiki: Vertex_Post-Processing#Depth_clamping). Looks like depth clamp has been supported in core since OpenGL 3.2.

Unless you use the AMD extension, be aware that this disables near-plane clipping as well. So (if you’re using a perspective projection), fragments between the camera and the near clip plane will still be rendered and will be clamped onto the near clip plane, but fragments behind the eye (or more generally, fragments which are behind one or more of the left/right/bottom/top clip planes) will still be clipped away.

Another solution you could consider is using a perspective projection transform with an infinite far clip distance. Websearch for details. This effectively disables far plane clipping, at the cost of a bit of Z precision.

You are right, I was imprecise.

I will check and edit.

A question on your last remark on using a “perspective projection transform with an infinite far clip distance”: This is not what I want (I believe, if I understand correctly). I want to position a textured quad on the far plane, e.g. z=1. How would a transform help with that?

Edit: some interesting observations!

First, some statments, that I would like to have verified.

  1. The clipping volume is limited by [-1,1].

  2. I disable/use clipping via:


	glEnable(GL_DEPTH_CLAMP); 
	drawQuadOnZ(1);
	glDisable(GL_DEPTH_CLAMP);

  1. Depth clamping allows drawing of all values z>=-1

  2. The wiki claims: “So objects that go behind the camera are still clipped.”
    I understand, that “behind the camera” qualifies for all values z < -1

With this caveat, I am surprised do observe that depth clamping fails to work for values z>=1 !!!
However, z<=-1 works as a charm.

The question is then: Has my understanding of NDC been wrong all along?

Is z==1 the near plane and z==-1 far?
Where is the camera in NDC?

Edit2:

“The internet” indeed claims that the viewing direction is towards -z ( for RHS or LHS?), which would concur with my observertaions of the clamping behaviour.
However, fiddling with the .z value of the plane and default GL setup, the quad is closest when z=-1 and farthest for z= 1-ulp.
I will try changing GLs handedness for the plane, maybe that will make a difference.
(Allways wanted to play with that, yay for opportunities.)

Edit3:
This is getting a bit long, I hope you will take the time and bear with me.
Assuming that


glClipControl(GL_UPPER_LEFT, GL_NEGATIVE_ONE_TO_ONE);

allows me to flip the handedness and remembering the sentence "where f=1 when origin is GL_LOWER_LEFT, and f=−1 when origin is GL_UPPER_LEFT. " I am surprised to discover, that it has no effect on clipping and depth mapping (tp and bottom are flipped though), smaller is closer, higher is farther.

Edit4:

OK, after some heated discussions with a colleague of mine, we have come to the conclusion that the documentation and scecification around far clipping is … dubious.
First, the spec defines the clip volume as zmin <= zc <= wc.

And this should include far=1 !

Further, the wiki defines the behaviour of depthclamp : “Depth clamping turns a frustum into a pyramid, and pyramids still end at the tip” And this corresponds with my observation, that values <-1 are not clipped.
The questions remain, where is the near plane, far plane and camera position on that pyramid.

The spec on depth clamp also states: “(effectively, there is no near or far plane clipping).” which contradicts my observed behaviour that there is still clipping on 1 (Also, requires the definition of a pyramid a bottom?).

Finally, does depth clamping require the fixed function projection magic to work effectively?

Best Regards

In this context, “behind the camera” means a negative W coordinate. If w[sub]c[/sub] (clip-space W) is negative, it’s impossible for either the X or Y clip tests to pass:
-w[sub]c[/sub] <= x[sub]c[/sub] <= w[sub]c[/sub]
-w[sub]c[/sub] <= y[sub]c[/sub] <= w[sub]c[/sub]

A negative value for w[sub]c[/sub] means that each of x[sub]c[/sub] and y[sub]c[/sub] would have to be greater than -w[sub]c[/sub], which is positive, while less than w[sub]c[/sub], which is negative. Which is impossible.

If you consider the “double pyramid” formed by projecting the edges of the viewport (i.e. the X and Y clip planes) to NDC, the part that’s “behind” the viewpoint has negative volume. For the part that’s in front, the inside of the pyramid is “inside” all four clip planes (i.e. all four inequalities are true), the rest of the space is outside at least one clip plane. For the part that’s behind, the inside of the pyramid is outside all four clip planes (all four inequalities are false), while the rest of the space is outside at least two (at least one of the X inequalities is false, likewise for Y).

Clipping is performed before conversion from clip-space to NDC. It has to; one of the reasons for clipping is to avoid the singularity at W=0 and the inversion for W<0.

No. In clip space, the near plane is z[sub]c[/sub]=-w[sub]c[/sub] and the far plane is z[sub]c[/sub]=w[sub]c[/sub]. This basically corresponds to a near plane of z[sub]ndc[/sub]=-1 and a far plane of z[sub]ndc[/sub]=1.

The “conventional” projection matrices established by glOrtho, glFrustum, gluOrtho2D and gluPerspective all invert the Z direction, so that z[sub]ndc[/sub] decreases as z[sub]eye[/sub] increases. This results in eye space being right-handed, with the positive Z axis toward the near plane and negative Z toward the far plane. But note that the “near” and “far” planes are themselves conventions which can effectively be reversed e.g. with glDephRange(1,0) or glDepthFunc(GL_GREATER).

OpenGL doesn’t have a “camera”. Even less so in NDC. The projective origin is (0,0,0,0) in clip space, which maps to the entire 3D space of NDC.

[QUOTE=Christoph.LGDV;1286177]
“The internet” indeed claims that the viewing direction is towards -z ( for RHS or LHS?), which would concur with my observertaions of the clamping behaviour.[/QUOTE]
That’s only true for the eye space set up by the conventional projection matrices. It isn’t a requirement, and isn’t true (or even meaningful) for clip space or NDC.

The choice of “f” as the variable name in the description of the first parameter is perhaps rather unfortunate. It’s unrelated to the use of “f” as the far plane distance in the description of the second parameter. Neither option changes the direction of Z (in any space) or depth. The first one flips the Y coordinate, which flips the handedness. The second one changes the near plane equation from z[sub]c[/sub]=-w[sub]c[/sub] to z[sub]c[/sub]=0 (roughly, changing it from z[sub]ndc[/sub]=-1 to z[sub]ndc[/sub]=0).

It does. But it doesn’t include far=1+epsilon for positive epsilon. Even for really, really small positive epsilon. And I don’t believe that there’s anything that requires Z/Z<=1.0; by my reading, It might actually be 1.0 plus 2.5 ULP.

No.

Oh boy, I will nead some reading iterations to parse this fully.

First of, thank you for your detailed explanations.

But jumping on your exclamation that the clipping volume includes z=1.

Can you please rephrase this paragraph:

It does. But it doesn’t include far=1+epsilon for positive epsilon. Even for really, really small positive epsilon. And I don’t believe that there’s anything that requires Z/Z<=1.0; by my reading, It might actually be 1.0 plus 2.5 ULP.

My question is if GL shouls allow the rendering of quads on gl_Position.zw=[1,1]?

I wouldn’t rely upon it. I’d consider it to be effectively random as to whether the quad is inside or outside the clip volume.