Scissor for attenuated light

I am currently using per-pixel attenuated lights in my engine. I am having fill rate problems, so am trying to use scissor to limit the geometry drawn for each light.
I need to find the screen-space bounding rectangle of the sphere of influence of the light.

I am doing this at the moment by finding the vectors which will become screen space left and up, dx and dy.

Then I calculate centre+radiusdx, centre-radiusdx, centre+radiusdy, centre-radiusdy.

Then I mulitiply these by the modelview and projection matrices, and scale and bias so that [-1,1]->[0,window width] and the same for height.
However, using these projected values for the scissor box seems to make the box too small and at certain angles, it cuts off a lit part of the scene.

I think this method should work, does anyone have a reason why it shouldn’t?
Is there an easier way, or have I simply made a silly error?

this is because a sphere gets also distorted, when its verty close the the viewer and you use a wide perpective angle.

to get it correct running, you must compute the screenspace coordinates of the boundingbox for this light (6 points) and then use this 2d-coordinates to build a 2d-box for clipping(take min/max values of them)

Sorry, I’m not sure what you mean when you say:
“you must compute the screenspace coordinates of the boundingbox for this light (6 points)”

Could you please
elaborate?

Well I havn’t tried this code out yet but I think this will work (it looks ok to me so far).

void ProjectLightForScissor( const float radius, const vec3_t lpos, float *x, float *y, float *width, float *height )
{
GLint viewport[4];

GLdouble mvmatrix[16], projmatrix[16];

float px, py, pz;
vec2_t r1, r2, r3, r4;

vec3_t p1, p2, p3, p4;
vec3_t up( 0, 1, 0 ), right( 1, 0, 0 );

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

glGetIntegerv( GL_VIEWPORT, viewport );
glGetDoublev( GL_MODELVIEW_MATRIX, mvmatrix );
glGetDoublev( GL_PROJECTION_MATRIX, projmatrix );

gluProject( p1.x, p1.y, p1.z, mvmatrix, projmatrix, viewport, &px, &py, &pz );
r1 = vec2_t( px, py ) + ( radius * vec2_t( 0, 1 ) );

gluProject( p2.x, p2.y, p2.z, mvmatrix, projmatrix, viewport, &px, &py, &pz );
r2 = vec2_t( px, py ) + ( radius * vec2_t( -1, 0 ) );

gluProject( p3.x, p3.y, p3.z, mvmatrix, projmatrix, viewport, &px, &py, &pz );
r3 = vec2_t( px, py ) + ( radius * vec2_t( 0, -1 ) );

x = r3.x;
y = r3.y;

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

EDIT: I just wanted to add that this code, while doing all the math on paper and drawing it on some graph paper does compute the correct values to go into glScissor for clipping the shadow volume where needed. Now all I need to do to be doubly sure is pop it into a shadow program and see what happens. Maybe ill try to do that before my college classes start up again.

EDIT 2: Syntax error.

-SirKnight

[This message has been edited by SirKnight (edited 08-16-2002).]

[This message has been edited by SirKnight (edited 08-16-2002).]

float LPOS[3]; // light position
float LRAD; // light radius

float V[6][3] = {
-1,1,-1,
1,1,-1,
-1,1, 1,
1,1, 1,

-1,-1,-1,
1,-1,-1,
-1,-1, 1,
1,-1, 1,

};

//
// compute boundingbox:
//
for(t=0;t<6;t++)
for(i=0;i<3;i++)
box[t][i] = LPOS[i] + (V[t][i] * LRAD);

//
// compute 3D->2D projection here using
// current projection/modelview matrix.
// (using openGL or by yourself, there are
// many many threads about this topic in this
// forum… just look for gluProject)
//
// store your 2D-coordinates (you need only x and y.)
// in a new array:

float box2D[6][2];

// now create min/max of this vertices to get the 2D-boundingbox:

float min[3],max[3];

for(i=0;i<2;i++)
{ min[i] = 1000000;
max[i] = -1000000;
for(t=0;t<6;t++)
{
if (box2D[t][i] > max[i] ) max[i] = box2D[t][i];
if (box2D[t][i] < min[i] ) min[i] = box2D[t][i];
}
}

//
// now your clip-area in 2D is:
//

clip.left = min[0];
clip.right = max[0];

clip.top = max[1];
clip.bottom = min[1]

EDIT: syntax error removed…

[This message has been edited by AdrianD (edited 08-16-2002).]

Thanks very much.
I’ll try it tomorrow.