View Full Version : artifacts in stencil shadows

01-28-2003, 08:26 AM
ive been racking by brain for weeks, i cant seem to figure out what is causing these artifacts in my demo:

as the light gets closer it messes up evan more.

its very simple demo using zpass.
i have extesevily tested the silhouette routine and know that the outline is being calculated correctly, so it must be something to do with the stencil buffer.

heres what the outline looks like

heres what the mesh looks like when light is up close. the first screeny was taken when the light is far away

heres the main drawing routine:

//Set up iniial z values
glDepthFunc(GL_LEQUAL );

Rect1();//the green rectangle


bool backf = 0;

glStencilFunc(GL_ALWAYS, 0, ~0);

//project the outline

bool frontf = 0;

glStencilFunc(GL_ALWAYS, 0, ~0);

//project the outline

bool color = 1;

glStencilFunc(GL_EQUAL , 0, ~0);

//Draw thegreen rectangle


all help appreciated

[This message has been edited by break_stuff247 (edited 01-28-2003).]

[This message has been edited by break_stuff247 (edited 01-28-2003).]

01-28-2003, 12:44 PM
It looks like it could be stencil overflow.

How many bits of stencil do you have? You need more than one for this.

01-28-2003, 12:54 PM
Your outline also appears to have gaps, this alone may be your problem. The outline must be enclosed.

01-28-2003, 01:13 PM
Originally posted by dorbie:
Your outline also appears to have gaps, this alone may be your problem. The outline must be enclosed.

Yeah that's what I noticed.

How are you computing the adjacency info for the triangles? Some how you either have open edges (but since you are using the knight md2 model I doubt it, but it's ways nice to check for it and fix if any are found) or the way you calculate the edges has a bug. Post some code about how you calcuate the edges and/or how you calculate the adjacency graph of the model.


01-28-2003, 06:24 PM
If he's extruding the front-faces for the volume, then the model itself doesnt need to be closed.

Make sure youre extruding both the edges which have only 1 triangle on them, and that triangle is front-facing to the light, and the edges which have multiple triangles on them, where 1 is facing the light.

Also add checks to your code to make sure that each edge only has 2 triangles on it. Ive come across 3 triangles sharing a single edge before, and that WILL cause rendering problems.

01-28-2003, 08:18 PM
The extruded volume needs to be closed. The outline represents the bounds of that volume, that's why he posted the image. As for extruding front faces, the point is to detect the silhouette edges to minimize the rendering overhead for the extruded hulls, it's actually the edges that get extruded and the outline represents a rationalization of the set of extruded faces, if correctly generated the outline will naturally be closed unless there are cracks in the model (or 3 tri edges as you say) but it depends on the implementation. There is clearly a problem with unclosed silhouettes in this guy's implementation particularly when you view something like the gap on the foot of the warrior outline, that is clearly an error in the generation of the silhouette edges prior to extrusion.

[This message has been edited by dorbie (edited 01-28-2003).]

01-29-2003, 12:45 PM
Hi again, thanks for all the input guys.

Dorbie: the stencil depth bit is 16, 32 gives the same errors.

you guys are right, the outline is incorrect, ive spent all day stepping through the code with no luck.

when the light is far away, the outline seems correct, this shot is taken with the light at (0,0,100)- it seems perfect no gaps

when the light is moved to (0,0,0) the image looks like this:

(note the model is at (0,0,-75))

heres the code you requested sir knight

the planes are calculated as:

for (i=0;i<obj->numFaces;i++)
vPoly[0] = obj->pVerts[obj->pFace[i].vertexIndex[0]];
vPoly[1] = obj->pVerts[obj->pFace[i].vertexIndex[1]];
vPoly[2] = obj->pVerts[obj->pFace[i].vertexIndex[2]];

vVector1 = Vector(vPoly[0], vPoly[2]); // Get the vector of the polygon (we just need 2 sides for the normal)
vVector2 = Vector(vPoly[2], vPoly[1]); // Get a second vector of the polygon

vNormal = Cross(vVector1, vVector2); // Return the cross product of the 2 vectors (normalize vector, but not a unit vector)
pTempNormals[i] = vNormal; // Save the un-normalized normal for the vertex normals
vNormal = Normalize(vNormal); // Normalize the cross product to give us the polygons normal

obj->pPlanes[i].normal = vNormal;
obj->pPlanes[i].d = (vNormal * vPoly[0]);

pNormals[i] = vNormal; // Assign the normal to the list of normals

/////**the sihloutte routine:**//////////////

void CModelMD2::ProjectSiloute(CVector3 &amp;lpos,CModel3d *pModel,float time,bool outline)

CVector3 olight;

int currFrame = pModel->currentFrame;
int nextFrame = pModel->nextFrame;

//get the object space light

for (int i=0; i< pModel->pObject[0].numFaces; i++)

if(SideOfPlane(pModel->pObject[0].pPlanes[i],olight) !=-1)
for(int j=0;j<3;j++)
PLANE plane;

int faceNeighbour = pModel->pObject[0].pFace[i].faceNeighbour[j];

plane = pModel->pObject[0].pPlanes[faceNeighbour];

//the first vertex of shadow volume
int index = pModel->pObject[0].pFace[i].vertexIndex[j];

CVector3 vPoint1 = pModel->pObject[currFrame].pVerts[index];
CVector3 vPoint2 = pModel->pObject[nextFrame].pVerts[index];

CVector3 v1,v2;

//interpolate for animatoin
v1.x = vPoint1.x + time * (vPoint2.x - vPoint1.x);
v1.y = vPoint1.y + time * (vPoint2.y - vPoint1.y);
v1.z = vPoint1.z + time * (vPoint2.z - vPoint1.z);

//the second vert
index = pModel->pObject[0].pFace[i].vertexIndex[(j+1)%3];

vPoint1 = pModel->pObject[currFrame].pVerts[index];
vPoint2 = pModel->pObject[nextFrame].pVerts[index];

v2.x = vPoint1.x + time * (vPoint2.x - vPoint1.x);
v2.y = vPoint1.y + time * (vPoint2.y - vPoint1.y);
v2.z = vPoint1.z + time * (vPoint2.z - vPoint1.z);

CVector3 p3 = (v1 - olight);
CVector3 p4 = (v2 - olight);

p3 = p3 *50000;
p4 = p4 *50000;

//draw the volume





///***Side of plane routine***///
SideOfPlane(const PLANE &amp;plane, const CVector3 &amp;pos)
float distance;

distance = (plane.normal.x * pos.x +
plane.normal.y * pos.y +
plane.normal.z * pos.z) - plane.d;

if(distance > 0)
return 1;
return -1;


all help appreciated

[This message has been edited by break_stuff247 (edited 01-29-2003).]

01-29-2003, 01:33 PM
This is not the answer, but a general suggestion :
the good-old shadow (silhouette) volume fails when near clipping plane intersects it. So, would it solve this problem if we cap the volume at the near clip plane? I tried this approuch, using the algorithm found in "Red Book", and it is satisfactoring, as long as volumes doesn't intersect each other; since this isn't a real request, I'll try the different approuch... But I want to know what you think about the idea? (not using Carmack's reverse)

01-29-2003, 02:08 PM
Originally posted by break_stuff247:

obj->pPlanes[i].d = (vNormal * vPoly[0]);

Shouldn't this be...

obj->pPlanes[i].d = -(vNormal * vPoly[0]);


Ax + By + Cz + D = 0


Ax + By + Cz = -D

or in your case

pN = -D

where p = point on plane and N = Normal of plane...

[This message has been edited by rgpc (edited 01-29-2003).]

01-29-2003, 03:35 PM
The formula , in my text book, is Ax+By+Cz =D
i.e D = the normal of the plane dotted with any point on the plane.

i tried your way just to be safe and it began to outline the back of the model.

thanks anyway.

01-29-2003, 04:01 PM
Try this...

If you have a plane with equation...

(0.0f)x + (1.0f)y + (0.0f)z - 25 = 0

then it is...

y = 25

But by your text book it would actually be

y = -25

---------+--------- y=25
--------------+-------------- x
---------+--------- y=-25

When you get to collision detection (particularly ray/plane collision) this is going to be fairly significant.

All that being said. Your code looks fine to me, are you sure that the model is in fact closed (Check
your verts to make sure you haven't got any duplicate positions with different UV's etc).

[This message has been edited by rgpc (edited 01-29-2003).]