PDA

View Full Version : Faces Shadowing Themselves



aviel
05-29-2011, 08:50 PM
So, I have a problem where certain polygons have faces that are shadowing themselves.
http://www.hereswhereyourewrong.net/self-shadow.png

As you can see, the faces of the sphere not facing the light are shadowing themselves, i.e. a face casting a shadow is casting that shadow on itself. How do I avoid this? I don't want to disable self-shadowing altogether, but I do want to eliminate this artifact. Here's my code:



glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);

glPushAttrib( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT | GL_POLYGON_BIT | GL_STENCIL_BUFFER_BIT );
glDepthMask( GL_FALSE );
glDepthFunc( GL_LEQUAL );
glEnable( GL_STENCIL_TEST );

glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );
glStencilFunc( GL_ALWAYS, 0, ~0);

glFrontFace( GL_CCW );
glStencilOp( GL_KEEP, GL_KEEP, GL_INCR );

/* draw shadow volumes, first pass */

glFrontFace(GL_CW);
glStencilOp(GL_KEEP, GL_KEEP, GL_DECR);

/* draw shadow volumes again */

Alfonse Reinheart
05-29-2011, 09:55 PM
As you can see, the faces of the sphere not facing the light are shadowing themselves, i.e. a face casting a shadow is casting that shadow on itself. How do I avoid this?

Why would you want to? If a surface is facing away from the light source, it does not receive any illumination from that light source. It is literally in the shadow of that light source, because the rest of the object (for closed surfaces) is blocking the light.

Well, it doesn't matter; you can't do this with shadow volumes. You might be able to do something with shadow maps by applying a bias, but shadow volumes can't do that.

aviel
05-29-2011, 09:59 PM
Those faces aren't dark because they're not in the light, they're dark because they're casting a shadow on themselves. But okay, I'll implement shadow maps.

Alfonse Reinheart
05-29-2011, 11:09 PM
Those faces aren't dark because they're not in the light, they're dark because they're casting a shadow on themselves.

They're facing away from the light, so it's the same thing. A surface facing away from the light should not be lit by that light. Whether it gets culled by the stencil test or the dot(N, L) is less than zero, in both cases it should result in precisely zero light from that light source.

aviel
05-29-2011, 11:22 PM
Okay, then what the hell is the artifact in the screenshot?

Alfonse Reinheart
05-30-2011, 12:19 AM
Okay, then what the hell is the artifact in the screenshot?

I don't know. All you posted was the code for setting up the stencil test.

How are you generating your stencil volumes? What shader are you using for lighting? What are your material parameters to that shader?

Your lighting equation should be moving towards zero as the light becomes more perpendicular to the surface point. Yet your light's brightness doesn't seem to fall off that much. My guess is that you have a particularly high ambient value, and you're not properly multi-passing to lay the ambient value down. This means that objects in shadow are perfectly black, rather than having any ambient value.

aviel
05-30-2011, 12:25 AM
So, right now I'm using a custom shader, but the same artifacts appear in the default shading so my shader isn't really relevant. Also, the problem is that the shadows are blocking ambient light, as well as light from any source that isn't causting the shadow to be cast.

As for how I render the volumes:




for(unsigned int i = 0; i < this->frameSize; i++) //for each face in this frame
{
int faceIndex = i + (this->currentFrame * this->frameSize);
face thisFace = this->faces[faceIndex];

if(!thisFace.facingLight)
continue;

for(int j = 0; j < 3; j++) //for each edge in this face
{
int neighbor = this->faces[faceIndex].edges[j].neighborFace;
if(neighbor != -1 and this->faces[neighbor].facingLight) //only draw quad if the edge is a silhouette edge
continue;

vertex v1 = *thisFace.edges[j].ev1; //vertices defining the edge
vertex v2 = *thisFace.edges[j].ev2;

if(this->currentFrame != this->totalFrames - 1) //just some code that interpolates vertices between keyframes
{
vertex i1 = *this->faces[faceIndex + this->frameSize].edges[j].ev1;
vertex i2 = *this->faces[faceIndex + this->frameSize].edges[j].ev2;

v1 = v1 + ((i1 - v1) * this->interpFrac);
v2 = v2 + ((i2 - v2) * this->interpFrac);
}

//far end of shadow volume
vertex v3(v1.x + lightPosition[0], v1.y + lightPosition[1], v1.z + lightPosition[2]);
vertex v4(v2.x + lightPosition[0], v2.y + lightPosition[1], v2.z + lightPosition[2]);

v3 = v3 * farclip;
v4 = v4 * farclip;

glBegin(GL_TRIANGLE_STRIP);
{
glVertex3f(v1.x, v1.y, v1.z);
glVertex3f(v1.x + v3.x, v1.y + v3.y, v1.z + v3.z);
glVertex3f(v2.x, v2.y, v2.z);
glVertex3f(v2.x + v4.x, v2.y + v4.y, v2.z + v4.z);
}
glEnd();

}
}

Alfonse Reinheart
05-30-2011, 01:29 AM
Also, the problem is that the shadows are blocking ambient light, as well as light from any source that isn't causting the shadow to be cast.

That's because you didn't turn off the stencil test.

Stencil shadows are inherently multipass. You have to render each light as a separate pass. You generally start by rendering the ambient reflectance into the framebuffer, so you need a shader that computes only the ambient lighting.

Then, for each shadowed light, you render the stencil shadows, then turn on the stencil test, then render the object with the shader that does lighting. You use an additive blend for all of these objects. Don't forget to turn off stencil tests after each light.

For the non-shadowed lights, you can render them all in one pass or multipass as you see fit. Again, turn off the stencil test.

aviel
05-30-2011, 02:11 AM
But doesn't that completely eliminate self-shadowing?

aviel
05-30-2011, 02:15 AM
Really, all I want is to eliminate drawing shadows over faces that are the ones used to start the shadow volumes.

EDIT: I think I fixed it. By zeroing out the stencil buffer for faces that aren't facing the light, I don't get those artifacts but still enable self shadowing.

Alfonse Reinheart
05-30-2011, 09:38 AM
But doesn't that completely eliminate self-shadowing?

No. Shadowing, whether self or from some other source, should not remove ambient lighting. If it is, you're doing it wrong.