I’m implementing stencil shadows in my engine: everything works fine, but I still have some unshadowed isolated pixels appearing sometimes, normally on the edges of shadow projections. It’s a bit like having some pixels tracing a line between two triangles.
It’s sounds like a precision problem, is it?
I’m using the ancient trick to display shadows: a flat black-blendend quad over the scene after stencil-buffer filling: it’s that a problem?
I’m using the technique descibed in your article [Practical and Robust Stencil Shadows]*, but, instead of drawing first the scene with just ambient light and then adding each light, I do:
draw the scene with everything (full lights, geometry, blah blah)
for each light:
a) clear stencil buffer, settings stencil ops (exactly like in your article)
b) drawing volumes (silhouette projection with both caps [always])
c) instead of rendering the scene again with lights, I put a 2d black blended quad over the screen to add darkness to shadowed areas
And that works fine. No “parity” error when the camera is inside the volume, more lights sources cast additive shadows (if two shadows overlap, this region become darker). It seems that I’ve some precision problem when rendering the volumes: the pixel artifacts appear generally along a edge shared by more triangles.
I already tried:
poligon offset —> nothing (but I eliminate some Z-fighting when rendering more lights… )
change projection matrix —> nothing
improve z-buffer precision —> nothing
The demo I downloaded don’t have this problem. I dunno.
I noticed that this problem appear when I draw shadow coming from a “boxed” objet, that is whit angle of 90° or more. When I draw shadows coming from, for exemple, a sphere it’s perfect.
Thanks! The one thing that jumps out at me is, do you have the far plane exactly at infinity or slightly beond it? There are occasionally some clipping artifacts that occur when you’re projecting exactly to the far clip plane.
This is an overview of the scene: very simple geometry, exported from 3d studio max throught a home-made plugin. The pyramid is casting shadows over the boxes: the geometry of the pyramid is really basic (I don’t think that my problem is related to geometry, in this case). http://www23.brinkster.com/unil/scene1.jpg
Here is a zoom over the area under the pyramid: notice the small segment of unshadowed pixel that appears (THIS is my problem… ): http://www23.brinkster.com/unil/scene2.jpg
Ah, I forgot to say that I have a shadow of the whole scene projected “in the void”, away at the “infinity” (that is at the end of the visible side of my viewport). This shadow is higly z-fighting. Is that a normal consequence of the reversed algorithm or it’s just the root of all my problems?
I agree with dorbie – it looks like your model has cracks in it. You need to make sure that adjacent faces are actually sharing the exact same vertex positions for the edge at which they meet.
I had the same kind of problem with my shadow volumes. After rewriting the volume creation part of my code the cracks were gone. i had some shadow volume polygons rendered twice (the caps, i think). this caused these ugly lines of unshadowed pixels across the volume because of precision errors on the edges of the double rendered polys.
i’m pretty sure you’ve encountered the same problem.
hope this helps
[This message has been edited by Jens Scheddin (edited 02-20-2004).]
To Eric: Wow! I used your article on Gamasutra and Cass’ article to build up my solution: it’s really nice to read your answers, thanks a lot!
In facts, my shadow volumes routine is quite hold and come from an ancient tutorial found on Nehe site (about 2 years ago). I think it’s time to modify this code with somethings more recent (and Jens’ contribution seems to be really interesting). I think that my volume creation code is wrong, because all the other stuffs are working fine.
I’ll try first to modify my silhouette determination algorithm. Hope the problem is “only” here…
Yes, I would definitely use EricL’s
P’inf matrix that includes the slop
factor. If this doesn’t fix the problem, then it’s almost certainly cracks in the geometry.
Maybe you have polygon offset turned on when you render the shadow polys… I found cracks in mine when I made that mistake, but when I zeroed glpolyoffset, cracks disappeared… if you flip glpolyoffset around the other way, you’ll prolly take care of all that fighting too.
[This message has been edited by 147-2 (edited 02-22-2004).]
The problem was during the connectivity generation in the plugin I developped: when you apply a texture to a box (for exemple), 3dsmax creates more vertices to allow a correct texture UV specification for each face. That is, your box with 8 vertices and 12 faces becomes a 32 vertices/12 faces box… The problem was there: I was casting shadows on opened meshes, or creating geometrical redundant shadow volumes. Now not only my shadows look fine, but my code runs a lot faster!
[In every case, my framerate fall to ~1/4 when shadows are active, but I know that this algorithm is fillrate expensive]
Again, thanks a lot!
[This message has been edited by Bibobibobibo22 (edited 02-23-2004).]
You have to generate your shadow volume by only paying attention to position, not texture. This is basically “welding” the entire mesh, programatically, when exporting the shadow geometry.
If you also pay attention to normals (which you probably should) then you should insert degenerate quads along edges where two differently-normaled faces meet (different smoothing groups).
Hi, I resolved the problem with a procedure witch remove similar surfaces (triangles) but with different normals or UV coords (different normals too because I need to add more vertices to the geometry when two surfaces share some of them with an angle of 90°).
It’s quite easy to do. Here my solution (brute force, bad coded, but maybe useful to you):
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool xvexp::SimplifyMesh(Point3 *vertexArray, WORD numberOfVertices, XFACE *faceArray, WORD numberOfFaces, XFACE **returnedArray, WORD returnedFaces)
/
** ?: remove redundant surfaces
** P: array ptr, # of vertices, face ptr, # of faces, # to a new face array, # to new face count
** <: TF
*/
{
// Alloc memory:
Point3 *_vertexArray = (Point3 *) exfMalloc(numberOfVertices * sizeof(Point3));
memcpy(_vertexArray, vertexArray, sizeof(Point3) * numberOfVertices);
XFACE *_faceArray = (XFACE *) exfMalloc(numberOfFaces * sizeof(XFACE));
memcpy(_faceArray, faceArray, sizeof(XFACE) * numberOfFaces);
// Find doubled vertices:
int modified = 0;
for (int c=0; c<numberOfVertices-1; c++)
for (int d=c+1; d<numberOfVertices; d++)
{
if (_vertexArray[c].x == _vertexArray[d].x &&
_vertexArray[c].y == _vertexArray[d].y &&
_vertexArray[c].z == _vertexArray[d].z)
if (_vertexArray[d].x != 99999.99999f)
{
for (int l=0; l<numberOfFaces; l++)
{
if (_faceArray[l].a == d) _faceArray[l].a = c;
if (_faceArray[l].b == d) _faceArray[l].b = c;
if (_faceArray[l].c == d) _faceArray[l].c = c;
}
_vertexArray[d].x = 99999.99999f;
modified++;
}
}
// Remove unuseful triangles:
int removed = 0;
for (int c=0; c<numberOfFaces-1; c++)
for (int d=c+1; d<numberOfFaces; d++)
{
if (_faceArray[c].a == _faceArray[d].a &&
_faceArray[c].b == _faceArray[d].b &&
_faceArray[c].c == _faceArray[d].c)
if (_faceArray[d].a != 65535)
{
_faceArray[d].a = 65535;
removed++;
}
}
*returnedArray = _faceArray;
*returnedFaces = numberOfFaces-removed;
exfFree(_vertexArray);
//exfFree(_faceArray);
exfLog("Removed %d triangles, modified %d
Your problem looks very similar to a problem I had, which turned out to render redundant shadow volume sides.
And yes, 3Dmax meshes suck.
I would like to add that if you render all your scene with an infinity-projection, you can render the front cap bit-excact and do not need a polygon offset.