The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Hi,

I am wondering what is the normal way shadow volumes are done for attenuated lights. It seems a great waste of fill rate to project the volumes to infinity (far clip plane). If you clipped the volume to the light's sphere of influence it would go much faster.

I'm sure I read somewhere that JC is doing this in Doom3 but I can't find much else in the way of a mention of it.

I have tried a few approaches one of which did have the desired effect. For each triangle that intersects the light's sphere, classify according to how many vertices lie inside the sphere. either 0, 1, 2 or 3. Each case was a piece of code that dealt with each situation, and produced the smallest possible volume.

The problem really though is combining it with possible shadow silhouettes to really speed it up. Obviously my solution is a bit naive and there needs to be a more general one.

Thanks in advance for any help,
Richard

a good optimization is to clip your shadowvolume in screenspace.(keyword: scissor rectangle)
so you can define infinite volumes, but draw only needed parts of the volume.

do a search on this forum for:
"siluette clipping" or

Hey thanks, that sounds like a good idea. So basically you would project your sphere onto the screen, then create a 2d bounding box in window space around it and use normal glScissor?

I just found http://www.flipcode.com/cgi-bin/msg....3dtheory&id=-1
and it looks like he puts an OBB around the sphere then projects that to the screen. Is that a better way to do it?

Thanks,
Richard

if the boundingbox is axisaligned to the screen, yes.. why? because its rather difficult to project a sphere.. but its not to project a cube.. (if its not screenaligned, it will get larger than needed due to projection, i _think_, never tried )

There is a post somewhere on this board which is quite recent i think where i posted some code that will compute the values that glScissor needs for doing just this. Also in that same post someone else posted some code that also computes this bounding box. His code was quite a bit different than mine but both work.

While the attenuated light does make a sphere of light, when you compute the box, you dont need to worry about a sphere. Just a circle really. A circle that has the radius of the light. Just check my code in the other post i talked about and you should see what i mean there. Well....I say circle but it may be more correct if i were to say a thin _slice_ of the sphere right down the middle. Imagine this and it will look like a circle.

Basically what i do is compute three points on this circle which is centered at the light position and has the radius of my light and take those three points (which are of course 3D points) and put those into gluProject to project them to screen space. Take those, compute a bounding box from that, then take those bounding box points and do a few simple math ops to setup what glScissor needs. Again my code should clearly show what im trying to describe here.

-SirKnight

That won't work SirKnight. Acutally, a sphere ( perspectively ) projected onto a plane is not a circle. I had the same error in my own code, I just use a box now ( the sphere code that I worked on would have been too expensive ).

Well poo. I forgot to take in account for perspective divide. I guess thats what i get for not trying it out first. I did the math on paper and it worked great, but i didnt realize that i was not taking into account the perspective. My math would work if it was _not_ perspective. I see this now, thanks for the heads up on that PH! O well, i know how i can do this using a box like you say that will probably end up faster anyway.

Ok so dont worry about looking at my code on that other post and forget my other post i just made up there.

-SirKnight

Hmm. I've been think about this, are you sure the way i do it wont work? Maybe take a look at my code. Because i compute those points on that circle there then feed that into gluProject. I dont project anything myself before the gluProject call. Or unless this 'light sphere' to begin with is already not a roundish sphere. Maybe because of the perspective frustum its more like a...there is a better word for this...3d oval? heh.

-SirKnight

Ok to make your life easier here is the code i have.

Code :
```void ProjectLightForScissor( const float radius, VECTOR lpos, float *x, float *y, float *width, float *height )
{
GLint viewport[4];
GLdouble mvmatrix[16], projmatrix[16];

double px, py, pz;

vector_t r1, r2, r3, r4;
vector_t p1, p2, p3, p4;
vector_t up( 0, 1, 0 ), right( 1, 0, 0 );
vector_t tempResult, projPt;
projPt.z = 0.0f;

vector_t vec_zero_one( 0, 1 ), vec_negone_zero( -1, 0 ), vec_zero_negone( 0, -1 );

//p1 = lpos + ( radius * ( ( cos(0) * right ) + ( sin(0) * up ) ) );
//p1 = lpos + ( right * radius );

//p2 = lpos + ( radius * ( ( cos(PI / 2) * right ) + ( sin(PI / 2) * up ) ) );
//p2 = lpos + ( up * radius );

//p3 = lpos + ( radius * ( ( cos(PI) * right ) + ( sin(PI) * up ) ) );
//p3 = lpos + ( -right * radius );
VectorInvert( &amp;tempResult, right );

//p4 = lpos + ( radius * ( ( cos(3 * PI / 2) * right ) + ( sin( 3 * PI / 2) * up ) ) );
//p4 = lpos + ( radius * -up );  // Not used

//
/// Get the matricies and viewport that gluProject needs to project to window space
//
glGetIntegerv( GL_VIEWPORT, viewport );
glGetDoublev( GL_MODELVIEW_MATRIX, mvmatrix );
glGetDoublev( GL_PROJECTION_MATRIX, projmatrix );

//
/// Project points to window space
//
gluProject( p1.x, p1.y, p1.z, mvmatrix, projmatrix, viewport, &amp;px, &amp;py, &amp;pz );
//r1 = VECTOR( px, py ) + ( VectorMUL( VECTOR( 0, 1 ), radius ) );
projPt.x  = (float)px; projPt.y  = (float)py;

gluProject( p2.x, p2.y, p2.z, mvmatrix, projmatrix, viewport, &amp;px, &amp;py, &amp;pz );
//r2 = VECTOR( px, py ) + ( VectorMUL( VECTOR( -1, 0 ), radius )  );
projPt.x  = (float)px; projPt.y  = (float)py;

gluProject( p3.x, p3.y, p3.z, mvmatrix, projmatrix, viewport, &amp;px, &amp;py, &amp;pz );
//r3 = VECTOR( px, py ) + ( VectorMUL( VECTOR( 0, -1 ), radius )  );
projPt.x  = (float)px; projPt.y  = (float)py;

// Not used
//gluProject( p4.x, p4.y, p4.z, mvmatrix, projmatrix, viewport, px, py, pz );
//r4 = vec2_t( px, py ) + ( radius * vec2_t( 1, 0 ) );

//
/// Setup the data for glScissor
//
*x = r3.x;
*y = r3.y;

*width = r1.x - r2.x;
*height = r2.y - r3.y;
}```
-SirKnight