GL_DEPTH_CLAMP_NV extension

I find this extension very useful, expecially when working on shadow volumes. I con’t understand why ati did not implement it yet. Or do you know any workaround to accomplish the same effect of this extension ?

Hi penetrator,

You can use an infinite projection matrix to eliminate far plane clipping. That is often sufficient for hardware/drivers that do not support NV_depth_clamp.

Hardware that does not support disabling the near/far clip planes simply cannot support NV_depth_clamp.

Thanks -
Cass

Thank you Cass. How can i implement inifinite near/far clip planes ?

http://www.gamasutra.com/features/20021011/lengyel_01.htm

I know the Gamasutra article, but i can’t solve the math which transform the current projection matrix into an infinite one…

ok i managed to get the following code:

float fAspect = (float)screen_x / (float)screen_y, fFOV = float(M_PI/4);
float fNear = 0.001f, fFar = 10.0f;
float fTop = fNear*(float)tan(double(fFOV/2.0f)), fBottom = -fTop, fRight = fAspect * fTop, fLeft = fAspect * fBottom;

result_mt[0]=2*fNear/(fRight-fLeft);
result_mt[1]=0.0f;
result_mt[2]=(fRight+fLeft)/(fRight-fLeft);
result_mt[3]=0.0f;

result_mt[4]=0.0f;
result_mt[5]=2*fNear/(fTop-fBottom);
result_mt[6]=(fTop+fBottom)/(fTop-fBottom);
result_mt[7]=0.0f;

result_mt[8]=0.0f;
result_mt[9]=0.0f;
result_mt[10]=1.0f;
result_mt[11]=fNear;

result_mt[12]=0.0f;
result_mt[13]=0.0f;
result_mt[14]=-1.0f;
result_mt[15]=0.0f;
glLoadMatrixd((GLdouble *)result_mt);

I have put this code in my drawglscene() function, but when gl_depth_clamp is disabled shadows still dont appear.

Take a look at the source here.
http://developer.nvidia.com/object/inf_shadow_volumes.html

Code is unreadable, at least for me. But thank you anyway.

After looking at your code more closely, I see the following problems.

  1. Your matrix entries are stored in the wrong order. OpenGL uses column-major ordering, meaning that incrementing a pointer to an entry moves you down a column, not across a row.

  2. Some of the matrix entries are incorrect (see below).

  3. You’re casting result_mt to a pointer to GLdouble and passing it to the glLoadMatrixd function. Is result_mt an array of double? I ask because you seem to be using floats everywhere else. If result_mt is an array of floats, use glLoadMatrixf and don’t do any cast, or else you’ll be sending garbage to OpenGL.

The correct matrix entries are:

result_mt[0] = 2.0f*fNear/(fRight-fLeft);
result_mt[1] = 0.0f;
result_mt[2] = 0.0f;
result_mt[3] = 0.0f;

result_mt[4] = 0.0f;
result_mt[5] = 2.0f*fNear/(fTop-fBottom);
result_mt[6] = 0.0f;
result_mt[7] = 0.0f;

result_mt[8] = (fRight+fLeft)/(fRight-fLeft);
result_mt[9] = (fTop+fBottom)/(fTop-fBottom);
result_mt[10] = -1.0f;
result_mt[11] = -1.0f;

result_mt[12] = 0.0f;
result_mt[13] = 0.0f;
result_mt[14] = -2.0f*fNear;
result_mt[15] = 0.0f;

With depth clamp turned off, you may run into precision problems at the far plane that look like random holes in your shadow volumes. To fix this, use the following matrix, as described in the Gamasutra article, where epsilon is a small positive constant (I use 3.0e-5F).

result_mt[0] = 2.0f*fNear/(fRight-fLeft);
result_mt[1] = 0.0f;
result_mt[2] = 0.0f;
result_mt[3] = 0.0f;

result_mt[4] = 0.0f;
result_mt[5] = 2.0f*fNear/(fTop-fBottom);
result_mt[6] = 0.0f;
result_mt[7] = 0.0f;

result_mt[8] = (fRight+fLeft)/(fRight-fLeft);
result_mt[9] = (fTop+fBottom)/(fTop-fBottom);
result_mt[10] = epsilon-1.0f;
result_mt[11] = -1.0f;

result_mt[12] = 0.0f;
result_mt[13] = 0.0f;
result_mt[14] = (epsilon-2.0f)*fNear;
result_mt[15] = 0.0f;

– Eric Lengyel

Hi Eric, thanks for your help. Yes messed up all the code, so now i corrected it following your indications. I also checked out point 3, just to be sure i converted all the pointer to float. But i still have this problem: as you can see from the screenshot (http://www.web-discovery.net/temp/problem.jpg), when depth clamp is disabled and minimum clip distance is at 0.1 , depth buffer is broken.
If i set minimum clip distance at 1.0, everything is rendered correctly but shadows are no longer displayed.

This is the code i use to render the scene:

glMatrixMode(GL_PROJECTION);
ReSizeGLScene(screen_x, screen_y, perspective_angle, 1, 50000);

float fAspect = (float)screen_x / (float)screen_y, fFOV = float(M_PI/4);
float fNear = 0.001f, fFar = 10.0f;
float fTop = fNear*(float)tan(double(fFOV/2.0f)), fBottom = -fTop, fRight = fAspect * fTop, fLeft = fAspect * fBottom;
float epsilon=.00003;

result_mt[0] = 2.0f*fNear/(fRight-fLeft);
result_mt[1] = 0.0f;
result_mt[2] = 0.0f;
result_mt[3] = 0.0f;

result_mt[4] = 0.0f;
result_mt[5] = 2.0f*fNear/(fTop-fBottom);
result_mt[6] = 0.0f;
result_mt[7] = 0.0f;

result_mt[8] = (fRight+fLeft)/(fRight-fLeft);
result_mt[9] = (fTop+fBottom)/(fTop-fBottom);
result_mt[10] = epsilon-1.0f;
result_mt[11] = -1.0f;

result_mt[12] = 0.0f;
result_mt[13] = 0.0f;
result_mt[14] = (epsilon-2.0f)*fNear;
result_mt[15] = 0.0f;

glLoadMatrixf((GLfloat *)result_mt);
glMatrixMode(GL_MODELVIEW);

render_terrain();
render_airbase();
render_F22();

It looks to me like you’re simply running out of depth buffer precision. That’ll happen when you’ve set your near plane at 0.1 feet and you’re rendering mountains 10 miles away. Moving the near plane out increases the precision at far distances, but as it sounds like you’re seeing, it makes it difficult to render objects close-up at the same time. I’ve seen suggestions that you render this kind of scene in two waves – the first wave renders all the distant geometry with the near plane moved out sufficiently to prevent artifacts. Then you clear the depth buffer and render all of the closer stuff in a second wave with the near plane set much closer. As long as you know that your aircraft will be rendered in front of the terrain, you shouldn’t have any visibility problems. The only case I can think of in which this would fail is if you want to see a distant aircraft fly behind a mountain or something.

Originally posted by penetrator:
Code is unreadable, at least for me. But thank you anyway.

Is this part readable?

// The infinite frustum set-up code.

matrix4f infinite_frustum(float left, float right,
						  float bottom, float top,
						  float zNear)
{
	matrix4f m;
	m.make_identity();
	
	m(0,0) = (2*zNear) / (right - left);
	m(0,2) = (right + left) / (right - left);
	
	m(1,1) = (2*zNear) / (top - bottom);
	m(1,2) = (top + bottom) / (top - bottom);
	
    // nudge infinity in just slightly for lsb slop
    float nudge = 1 - 1.0 / (1<<23);

	m(2,2) = -1  * nudge;
	m(2,3) = -2*zNear * nudge;
	
	m(3,2) = -1;
	m(3,3) = 0;
	
	return m;
}

>>It looks to me like you’re simply running out of depth buffer precision.

Yes that is the problem ! I followed your instructions, first rendering terrain and then resetting to near clip plane to a lower value so that shadows are rendered. However there is still one issue: shadows are not rendered over the terrain (but only on the aircraft) because i reset the depth buffer (maybe) before drawing shadows.
Anyway thank you guys for your help, at least i have shadows on the aircraft !