Java Cool Dude

06-09-2005, 07:31 PM

A while ago when I was implementing shadow volumes in my rendering engine I came up with an algorithm to compute a given light's bounding screen-rectangle. According to my tests, it works pretty darn well, however, having said that I'm still wondering if there are cases out there that could break it.

Anyway here it is, I would appreciate any commments:

Tuple4i Renderer::getScissorRect(const Tuple3f &lightPosition,

float lightRange)

{

Tuple4i scissor;

//Retrieve the current view port to extract the screen width and height

glGetIntegerv(GL_VIEWPORT,viewport);

//Get the camera world position

Tuple3f cameraPosition = getCameraPosition(),

lightPos = lightPosition,

diagonal;

//If the camera distance to the light source is lesser than

//the light range, return the description of the whole screen

if(cameraPosition.getDistance(lightPos) - lightRange <= EPSILON)

return viewport;

//Retrieve the projection matrix, we will use it later to project

//our corners points onto the screen

glGetFloatv(GL_PROJECTION_MATRIX, projectionMatrix);

//Retrieve the modelview matrix, we will extract the up and right

//vectors from it

glGetFloatv(GL_MODELVIEW_MATRIX , modelviewMatrix);

/**************************************/

/* + Upper corner */

/* / */

/* / */

/* / */

/* / */

/* / */

/* / */

/* ( ) Light position */

/* / */

/* / */

/* / */

/* / */

/* / */

/* / */

/* + Lower corner */

/**************************************/

//Multiply the light range by square root of two since we will compute

//the corners of square

lightRange *= 1.42f;

diagonal.set(modelviewMatrix[0] + modelviewMatrix[1],

modelviewMatrix[4] + modelviewMatrix[5],

modelviewMatrix[8] + modelviewMatrix[9]);

diagonal *= lightRange;

//Compute the lower corner

corners[0].set(lightPosition.x - diagonal.x,

lightPosition.y - diagonal.y,

lightPosition.z - diagonal.z,

1.0f);

//Compute the upper corner

corners[1].set(lightPosition.x + diagonal.x,

lightPosition.y + diagonal.y,

lightPosition.z + diagonal.z,

1.0f);

//Project both onto the screen surface

for(int i = 0; i < 2; i++)

{

corners[i] *= modelviewMatrix;

corners[i] *= projectionMatrix;

corners[i] /= corners[i].w;

corners[i].x = viewport[0] + float(viewport[2])*(corners[i].x + 1.0f)/2.0f;

corners[i].y = viewport[1] + float(viewport[3])*(corners[i].y + 1.0f)/2.0f;

corners[i].z = 0.5f*corners[i].z + 0.5f;

}

//Set up the scissor info

scissor[0] = int(corners[0].x);

scissor[1] = int(corners[0].y);

scissor[2] = int(corners[1].x);

scissor[3] = int(corners[1].y);

scissor[0] = scissor[0] < 0 ? 0 : scissor[0];

scissor[1] = scissor[1] < 0 ? 0 : scissor[1];

return scissor;

}

Anyway here it is, I would appreciate any commments:

Tuple4i Renderer::getScissorRect(const Tuple3f &lightPosition,

float lightRange)

{

Tuple4i scissor;

//Retrieve the current view port to extract the screen width and height

glGetIntegerv(GL_VIEWPORT,viewport);

//Get the camera world position

Tuple3f cameraPosition = getCameraPosition(),

lightPos = lightPosition,

diagonal;

//If the camera distance to the light source is lesser than

//the light range, return the description of the whole screen

if(cameraPosition.getDistance(lightPos) - lightRange <= EPSILON)

return viewport;

//Retrieve the projection matrix, we will use it later to project

//our corners points onto the screen

glGetFloatv(GL_PROJECTION_MATRIX, projectionMatrix);

//Retrieve the modelview matrix, we will extract the up and right

//vectors from it

glGetFloatv(GL_MODELVIEW_MATRIX , modelviewMatrix);

/**************************************/

/* + Upper corner */

/* / */

/* / */

/* / */

/* / */

/* / */

/* / */

/* ( ) Light position */

/* / */

/* / */

/* / */

/* / */

/* / */

/* / */

/* + Lower corner */

/**************************************/

//Multiply the light range by square root of two since we will compute

//the corners of square

lightRange *= 1.42f;

diagonal.set(modelviewMatrix[0] + modelviewMatrix[1],

modelviewMatrix[4] + modelviewMatrix[5],

modelviewMatrix[8] + modelviewMatrix[9]);

diagonal *= lightRange;

//Compute the lower corner

corners[0].set(lightPosition.x - diagonal.x,

lightPosition.y - diagonal.y,

lightPosition.z - diagonal.z,

1.0f);

//Compute the upper corner

corners[1].set(lightPosition.x + diagonal.x,

lightPosition.y + diagonal.y,

lightPosition.z + diagonal.z,

1.0f);

//Project both onto the screen surface

for(int i = 0; i < 2; i++)

{

corners[i] *= modelviewMatrix;

corners[i] *= projectionMatrix;

corners[i] /= corners[i].w;

corners[i].x = viewport[0] + float(viewport[2])*(corners[i].x + 1.0f)/2.0f;

corners[i].y = viewport[1] + float(viewport[3])*(corners[i].y + 1.0f)/2.0f;

corners[i].z = 0.5f*corners[i].z + 0.5f;

}

//Set up the scissor info

scissor[0] = int(corners[0].x);

scissor[1] = int(corners[0].y);

scissor[2] = int(corners[1].x);

scissor[3] = int(corners[1].y);

scissor[0] = scissor[0] < 0 ? 0 : scissor[0];

scissor[1] = scissor[1] < 0 ? 0 : scissor[1];

return scissor;

}