PDA

View Full Version : Casting shadow on teapot



Lanfear
02-22-2004, 06:40 PM
Hi, i am a novice with opengl and i would really welcome some advices. I want to cast a shadow of say, a sphere, on a teapot, but i am not sure how to go about doing it.

I intend to use projection to cast the shadow. That requires me to know the surface equation of the teapot. How could i go about defining the teapot surface?

Thanks!

147-2
02-22-2004, 10:21 PM
It is a lot easier with a model of an object, and not a GLUT primitive.

This site should tell you everything you need to know about shadows. Make sure to note Carmack's reverse, that's critical for shadow accuracy.
http://developer.nvidia.com/object/cedec_stencil.html

Lanfear
02-23-2004, 09:18 AM
harlo! thanks for giving me the website link, i am examining the article now.

just like to ask, what do u mean by:
"It is a lot easier with a model of an object, and not a GLUT primitive. "
Do you mean it is easier if i din call glutSolidTeapot(), but build it myself?

147-2
02-25-2004, 07:57 AM
I hadn't actually read what you typed correctly. You can render a shadow ONTO a teapot, but rendering the shadow of the teapot would be difficult because you don't have the necessary information about the teapot (the faces and whatnot)... unless you had the model of the teapot.

BUT, to render a shadow onto the teapot is easy, just follow the text there.

Lanfear
02-26-2004, 05:01 AM
Thanks! i have trying to write the code now. http://www.opengl.org/discussion_boards/ubb/smile.gif

Lanfear
02-27-2004, 02:50 AM
hmm, i am rather confused now. It doesnt work when i implement the stenciling approach, so i must have intepretated something wrongly. I have a few questions:

1) Do we need to look at the scene from the light position before we fill the depth buffer with the depth values in the scene? it is not stated in the description but i thought it makes sense to do that...

2)The stenciling approach takes care of the shadow volume right? DO i need to explicitly find the polygons defining the shadow volume?

3)I am using a 2D polygonal plane as the occluder. will it affect the stencil value within the shadow volume, as it has only 1 face (no front and back faces)?

Thanks...

[This message has been edited by Lanfear (edited 02-27-2004).]

Descenterace
02-28-2004, 12:28 PM
Now, I'm a DirectX programmer until today, but the technique is usually the same.

To draw a shadow, you have to work out what objects are inside the shadow. To do this, you project the object casting the shadow from the light source, creating a 'shadow volume'. You need to find the outer edges of the object as seen from the light source and build a solid out of them. For a sphere this resolves to a simple cylinder, or more accurately a cone with the top cut off.
For polygonal objects this 'projection' can be very computationally-intensive, but for simple things like spheres and cubiods there's normally a short cut.

Now you have a polygon model of the shadow. Render the scene from the final viewpoint (there is no reason at all to render from the light source) to fill the depth buffer. You now have a scene minus the shadow.
For the next stage, you must not render to the framebuffer and you must turn off Z-buffer updates. Instead, you have to zero the stencil buffer then render to that.
Set up OGL so that stencil buffer pixels are incremented when rendered, then render the front faces of your shadow volume.
Set up OGL to that stencil buffer pixels are decremented when rendered, then render the back faces of your shadow volume.

Now, every pixel with a positive value in the stencil buffer is in shadow. Set up a black texture and render it to the whole framebuffer with an alpha value of about .5, but tell OGL to only render a pixel if the equivalent pixel in the stencil buffer has a positive value. This will darken the pixels in shadow.
All done.


Here's how it works:
Since the depth buffer has been filled by the time the shadow volume is rendered, only parts of the shadow volume that are not occluded will be rendered, so we don't have to worry about shadows behind the visible objects.
If a 'ray' from the screen intersects only a front facing of the shadow volume before hitting an object, that means that object is inside the shadow. If it intersects both a front facing and a rear facing, then the object is on the other side of the shadow volume but still in the light.
So we total the number of intersected front facings and subtract the number of intersected rear facings, and if the value is positive, the target pixel lies inside the shadow volume and should be darkened.
The other reason we need a filled Z-buffer for this to work is to make the renderer ignore any shadow volume faces behind the object. Without the depth buffer information, these would be totalled up too and every stencil buffer pixel would be zero.


There are other ways of rendering shadow volumes (one of which involves two passes per light source plus another pass for texturing, but comes as close to perfection as is possible at present). This is the usual one and is also probably the most efficient.

Lanfear
02-29-2004, 05:21 AM
I followed the shadow volume algorithms given in numerous website, but it doesnt work. There are no shadowing at all. Does anybody know what i have done wrongly?
------------------------------------------
glClearStencil(0);//clear stencil buffer to 0
glClearDepth(1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

glPushMatrix();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();

gluPerspective(55,1,1,200.0);
glMatrixMode(GL_MODELVIEW);

DisplayImage(); //this is a background image
Lighting();

DrawObjects();
//My objects are a polygon, a teapot and a cube below the teapot

//disable color buffer and depth buffer
glColorMask(GL_FALSE,GL_FALSE,GL_FALSE,GL_FALSE); glDepthMask(GL_FALSE);

glClearStencil(0);
glClear(GL_STENCIL_BUFFER_BIT);

//Increment when depth test passes
glStencilFunc(GL_ALWAYS, 1, 1);
glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
glEnable(GL_STENCIL_TEST);
glCullFace(GL_BACK);
glEnable(GL_CULL_FACE );

glMatrixMode(GL_PROJECTION);
glLoadIdentity();

gluPerspective(55,1,1,200.0);
glMatrixMode(GL_MODELVIEW);
DrawObjects();

glDisable(GL_CULL_FACE );
glDisable(GL_STENCIL_TEST);


glCullFace(GL_FRONT);
glEnable(GL_CULL_FACE );

//decrement with front face culling
glStencilFunc(GL_ALWAYS, 1, 1);
glStencilOp(GL_KEEP, GL_KEEP, GL_DECR);
glEnable(GL_STENCIL_TEST);

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(55,1,1,200.0);
glMatrixMode(GL_MODELVIEW);
DrawObjects();
glDisable(GL_CULL_FACE );


glStencilFunc(GL_GREATER, 0, 1);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);

glClear(GL_DEPTH_BUFFER_BIT);
//Enable color buffer and depth buffer
glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE); //dun update color
glDepthMask(GL_TRUE);

glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
glColor4f(0.0,0.0,0.0,0.5); //50% black

DrawObjects();

glDisable(GL_STENCIL_TEST);
glDisable(GL_BLEND);

glPopMatrix();
------------------------------------------

ps: Thanx a lot Descenterace for your explanation. http://www.opengl.org/discussion_boards/ubb/smile.gif

pps: forgot to say, any help wld be very welcome, and thanks!

[This message has been edited by Lanfear (edited 02-29-2004).]

[This message has been edited by Lanfear (edited 02-29-2004).]