2
\$\begingroup\$

I'm trying to understand the tutorial 27th in Nehe website. This is about how to cast a shadow of an object using stencil buffer in OpenGL. The idea here is checking the directions of all the faces of the object with the direction of light, and the result will define whether or not this face make a shadow. In the case of making a shadow, we will draw "shadow" into the stencil buffer as the following code.

// First Pass. Increase Stencil Value In The Shadow
glFrontFace( GL_CCW );
glStencilOp( GL_KEEP, GL_KEEP, GL_INCR );
doShadowPass( object, lightPosition );
// Second Pass. Decrease Stencil Value In The Shadow
glFrontFace( GL_CW );
glStencilOp( GL_KEEP, GL_KEEP, GL_DECR );
doShadowPass( object, lightPosition );

My question here is why "glFrontFace" function in the second pass help remove shadow between objects in the scene?

I Hope to see your answer. Thanks so much!

P/S:this is the explanation in the tutorial, but I don't get it

"They are rendered in two passes as you can see, one incrementing the stencil buffer with the front faces (casting the shadow), the second decrementing the stencil buffer with the backfaces ("turning off" the shadow between the object and any other surfaces)."

\$\endgroup\$
1
\$\begingroup\$

For staters this technique is quite outdated, actually all of NeHe is outdated. You might want to look at something like OpenGL 3 and OpenGL 4 with GLSL. I recently had to unlearn allot of stuff, you should learn the correct OpenGL from the start.

Back to your question. If you look at the code in CastShadow (3Dobject.h) you will see that the object is not rendered normally, but each edge (line between two vertices) is extended in the direction of the shadow. (Away from the light.)

That is what this code does:

glBegin(GL_TRIANGLE_STRIP);
    glVertex3f(o->points[p1].x,
                o->points[p1].y,
                o->points[p1].z);
    glVertex3f(o->points[p1].x + v1.x,
                o->points[p1].y + v1.y,
                o->points[p1].z + v1.z);

    glVertex3f(o->points[p2].x,
                o->points[p2].y,
                o->points[p2].z);
    glVertex3f(o->points[p2].x + v2.x,
                o->points[p2].y + v2.y,
                o->points[p2].z + v2.z);
glEnd();

The first pass sets the stencil buffer to 1 where the outer shell is. The rendering is obstructed by the depth buffer. This currently looks a little bit like the cone of a spotlight. (That would be fig1 in the NeHe article if the image was not AWOL.)

To make this the actual shadow the bits of the cone are not in shadow must be put back to 0. To do this the same thing is done as in pass one, but with the faces revered. Since only front face is rendered now the cone is rendered "from the inside".

So the shadow comes into being by the interaction of the two passes and the the depth buffer. Take the test scene, the back plane is first rendered and thus the depth buffer is filled. The first pass is rendered and only the bit of the cone that faces you and is visible is rendered filling the stencil buffer with 1 and then the bit of the cone that is visible that away from you is rendered setting the buffer back to 0. The result is that only the bits between the two and "on the depth buffer" are not set to 1 and now the scene can either be darkened or lit based on that.

\$\endgroup\$
  • \$\begingroup\$ thanks so much. Your careful explanation helps me a lot, and the same goes for the link you provided me. By the way, I've learned OpenGL about two months, mostly by examples. Could you show me some other websites which contains projects covering basic topics for starters like me. Hope to see your answer \$\endgroup\$ – khanhhh89 Oct 15 '13 at 8:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.