Hi, I got the paper “RobustShadowVolumes” at developer.nvidia.com. And I tryed it, but failed. Now I post the main source code. I hope somebody can help me. Thanks.
typedef struct _TRIANGLELIST
{
ATVECTOR V[3];
GLboolean backfacing;
GLuint adjacent[3];
}TRIANGLELIST;
TRIANGLELIST trianglelist[4];
void DrawGLScene()
{
glLoadIdentity();
//1. Clear the depth buffer to 1.0; clear the color buffer.
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen And Depth Buffer
//2. Load the projection with Pinf given the aspect ratio, field of
// view, and near clip plane distance in eye-space.
GLfloat Pinf[4][4];
Pinf[1][0] = Pinf[2][0] = Pinf[3][0] = Pinf[0][1] =
Pinf[2][1] = Pinf[3][1] = Pinf[0][2] = Pinf[1][2] =
Pinf[0][3] = Pinf[1][3] = Pinf[3][3] = 0;
Pinf[0][0] = 1.0f / ((GLfloat)tan(fov) * aspect);
Pinf[1][1] = 1.0f / (GLfloat)tan(fov);
Pinf[3][2] = -2.0f * z_near; Pinf[2][2] = Pinf[2][3] = -1;
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(&Pinf[0][0]);
//3. Load the modelview matrix with the scene¡¯s viewing
// transform.
glMatrixMode(GL_MODELVIEW);
gluLookAt(m_Camera.mPosition.x, m_Camera.mPosition.y, m_Camera.mPosition.z,
m_Camera.mView.x, m_Camera.mView.y, m_Camera.mView.z,
m_Camera.mUpVector.x, m_Camera.mUpVector.y, m_Camera.mUpVector.z);
//4. Render the scene with depth testing, back-face culling, and
// all light sources disabled (ambient & emissive illumination
// only).
glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS);
glEnable(GL_CULL_FACE); glCullFace(GL_BACK);
glEnable(GL_LIGHTING); glDisable(GL_LIGHT0);
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, global_ambient);
display();
//5. Disable depth writes, enable additive blending, and set the
// global ambient light contribution to zero (and zero any
// emissive contribution if present).
glDepthMask(0);
glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE);
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, zero);
//6. For each light source:
// A. Clear the stencil buffer to zero.
glClear(GL_STENCIL_BUFFER_BIT);
// B. Disable color buffer writes and enable stencil testing
// with the always stencil function and writing stencil…
glColorMask(0, 0, 0, 0);
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_ALWAYS, 0, ~0); glStencilMask(~0);
// C. For each occluder:
// a. Determine whether each triangle in the occluder¡¯s
// model is front- or back-facing with respect to the
// light¡¯s position. Update triList[].backfacing.
UpdateBackfacing();
// b. Configure zfail stencil testing to increment stencil
// for back-facing polygons that fail the depth test.
glCullFace(GL_FRONT); glStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
// c. Render all possible silhouette edges as quads that
// project from the edge away from the light to
// infinity.
ATVECTOR L = ATVECTOR(light_position[0], light_position[1], light_position[2]);
glBegin(GL_QUADS);
{
for (int i = 0; i < 4; i++) // for each triangle
{
// if triangle is front-facing with respect to the light
if (!trianglelist[i].backfacing)
{
for (int j = 0; j < 3; j++) // for each triangle edge
{
// if adjacent triangle is back-facing
// with respect to the light
if (trianglelist[trianglelist[i].adjacent[j]].backfacing)
{
// found possible silhouette edge
ATVECTOR A = trianglelist[i].V[j];
ATVECTOR B = trianglelist[i].V[(j + 1) % 3]; // next vertex
glVertex4f(B.x, B.y, B.z, 1.0f);
glVertex4f(A.x, A.y, A.z, 1.0f);
glVertex4f(A.x - L.x, A.y - L.y, A.z - L.z, 0.0f); // infinite
glVertex4f(B.x - L.x, B.y - L.y, B.z - L.z, 0.0f); // infinite
}
}
}
}
}
glEnd(); // quads
// d. Specially render all occluder triangles. Project and
// render back facing triangles away from the light to
// infinity. Render front-facing triangles directly.
#define Vertex trianglelist[i].V[j] // macro used in Vertex4f calls
glBegin(GL_TRIANGLES);
{
for (int i = 0; i < 4; i++) // for each triangle
{
// if triangle is back-facing with respect to the light
if (trianglelist[i].backfacing)
for (int j = 0; j < 3; j++) // for each triangle vertex
glVertex4f(Vertex.x - L.x, Vertex.y - L.y, Vertex.z - L.z, 0); // infinite
else
for (int j = 0; j < 3; j++) // for each triangle vertex
glVertex4f(Vertex.x, Vertex.y, Vertex.z, 1.0f);
}
}
glEnd(); // triangles
// e. Configure zfail stencil testing to decrement stencil
// for front-facing polygons that fail the depth test.
glCullFace(GL_BACK); glStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
// f. Repeat steps (c) and (d) above, this time rendering
// front facing polygons rather than back facing ones.
glBegin(GL_QUADS);
{
for (int i = 0; i < 4; i++) // for each triangle
{
// if triangle is front-facing with respect to the light
if (!trianglelist[i].backfacing)
{
for (int j = 0; j < 3; j++) // for each triangle edge
{
// if adjacent triangle is back-facing
// with respect to the light
if (trianglelist[trianglelist[i].adjacent[j]].backfacing)
{
// found possible silhouette edge
ATVECTOR A = trianglelist[i].V[j];
ATVECTOR B = trianglelist[i].V[(j + 1) % 3]; // next vertex
glVertex4f(B.x, B.y, B.z, 1.0f);
glVertex4f(A.x, A.y, A.z, 1.0f);
glVertex4f(A.x - L.x, A.y - L.y, A.z - L.z, 0.0f); // infinite
glVertex4f(B.x - L.x, B.y - L.y, B.z - L.z, 0.0f); // infinite
}
}
}
}
}
glEnd(); // quads
glBegin(GL_TRIANGLES);
{
for (int i = 0; i < 4; i++) // for each triangle
{
// if triangle is back-facing with respect to the light
if (trianglelist[i].backfacing)
for (int j = 0; j < 3; j++) // for each triangle vertex
glVertex4f(Vertex.x - L.x, Vertex.y - L.y, Vertex.z - L.z, 0); // infinite
else
for (int j = 0; j < 3; j++) // for each triangle vertex
glVertex4f(Vertex.x, Vertex.y, Vertex.z, 1.0f);
}
}
glEnd(); // triangles
//D. Position and enable the current light (and otherwise
// configure the light¡¯s attenuation, color, etc.).
glEnable(GL_LIGHT0);
glLightfv(GL_LIGHT0, GL_POSITION, light_position);
glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
//E. Set stencil testing to render only pixels with a zero
// stencil value, i.e., visible fragments illuminated by the
// current light. Use equal depth testing to update only the
// visible fragments, and then, increment stencil to avoid
// double blending. Re-enable color buffer writes again.
glStencilFunc(GL_EQUAL, 0, ~0); glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
glDepthFunc(GL_EQUAL); glColorMask(1,1,1,1);
//F. Re-draw the scene to add the contribution of the current
// light to illuminated (non-shadowed) regions of the
// scene.
display();
// G. Restore the depth test to less.
glDepthFunc(GL_LESS);
//7. Disable blending and stencil testing; re-enable depth writes.
glDisable(GL_BLEND); glDisable(GL_STENCIL_TEST); glDepthMask(1);
…
}