Simple Projection. Shadow mapping ( projective shadowing ):. A popular real-time shadowing technique ( e.g. Toy Story ); Render the scene from the view ...
Syllabus
Blank
Homework
Quizzes
Notes
Labs
Scores
Blank
LectureNotesDr.TongLaiYu,20101.Introduction2.OpenGLShadingLanguage(GLSL)I3.GLSLII4.CurveandSurfaceDesign
5.ModelingShapeswithPolygonalMeshes6.TextureMapping7.CastingShadows8.ToolsforRasterDisplay9.ParsingExternalObjects
CastingShadows
Introduction
Shadowscanbecreatedbyray-tracingbuttooslow
Whyshadows?
Shadowsprovidevisualcuesaboutthespatialrelationshipsbetweenthe
differentcomponentsinascene.
Additionalinformationandviewsofobjects
Improved"realism".
Lightingenvironmentcues
Anchors:Withoutshadowsobjectsseemtofloat/hover.
Withoutshadows,objectslookhovered.
SimpleProjection
Shadowmapping(projectiveshadowing):
Apopularreal-timeshadowingtechnique(e.g.ToyStory)
Renderthescenefromtheviewpointofthelightsource.Storethe
z-bufferofeverypixelintoa"shadowmap".
Renderascenefromthecameraview.LetTbethetransform
re-aligningthecameracoordinatesystemtothecoordinatesystem
ofthelightsource.
LetP=(x,y,z)bethe3D
coordinatesofavisiblescenepointincameracoordinates.Transformthe
cameracoordinates(x,y,z)intolightsourcecoordinates(u,v,w):
i.e.(u,v,w)=T(x,y,z)
Letqbethe"z"valueatthe(u,v)pixelintheshadowmap.
If(q
#include
#include
voidinit(void)
{
glEnable(GL_DEPTH_TEST);
glClearStencil(0x0);
glEnable(GL_STENCIL_TEST);
glClear(GL_STENCIL_BUFFER_BIT);//fillstencilbufferwith0
}
//greendiamondinsideredsquare
voiddisplay(void)
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glStencilFunc(GL_NOTEQUAL,0x1,0x1); //failindiamond-region,passoutside
glStencilOp(GL_KEEP,GL_KEEP,GL_KEEP); //nochangeinstencilbuffervalues
glColor3f(1,0,0); //red
glBegin(GL_POLYGON);
glVertex3f(-1.0,1.0,-1); //z=-1,soredpolygonbehindgreen(below)
glVertex3f(1.0,1.0,-1);
glVertex3f(1.0,-1.0,-1);
glVertex3f(-1.0,-1.0,-1);
glEnd();
glStencilFunc(GL_EQUAL,0x1,0x1); //passindiamond-region,failoutside
glColor3f(0,1,0); //green
glBegin(GL_POLYGON);
glVertex3f(-1.0,1.0,0); //z=0,infrontofredpolygon
glVertex3f(1.0,1.0,0);
glVertex3f(1.0,-1.0,0);
glVertex3f(-1.0,-1.0,0);
glEnd();
}
/*Wheneverthewindowisreshaped,redefinethe
*coordinatesystemandredrawthestencilarea.
*/
voidreshape(intw,inth)
{
glViewport(0,0,(GLsizei)w,(GLsizei)h);
glClearColor(1.0f,1.0f,1.0f,0.0f);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if(w<=h)
gluOrtho2D(-3.0,3.0,-3.0*(GLfloat)h/(GLfloat)w,
3.0*(GLfloat)h/(GLfloat)w);
else
gluOrtho2D(-3.0*(GLfloat)w/(GLfloat)h,
3.0*(GLfloat)w/(GLfloat)h,-3.0,3.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
//createadiamondshapedstencilarea
glClear(GL_STENCIL_BUFFER_BIT); //fillstencilbufferwith0s
glStencilFunc(GL_ALWAYS,0x1,0x1);
glStencilOp(GL_REPLACE,GL_REPLACE,GL_REPLACE);
glBegin(GL_QUADS); //stencilbufferwillhavediamond-shapedregionfilledwith1s
glVertex2f(-1.0,0.0);
glVertex2f(0.0,1.0);
glVertex2f(1.0,0.0);
glVertex2f(0.0,-1.0);
glEnd();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0,(GLfloat)w/(GLfloat)h,3.0,7.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0,0.0,-5.0);
}
voidkeyboard(unsignedcharkey,intx,inty)
{
switch(key){
case27:
exit(0);
break;
}
}
/*MainLoop
*Becertaintorequeststencilbits.
*/
intmain(intargc,char**argv)
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB
|GLUT_DEPTH|GLUT_STENCIL);
glutInitWindowSize(400,400);
glutInitWindowPosition(100,100);
glutCreateWindow(argv[0]);
init();
glutReshapeFunc(reshape);
glutDisplayFunc(display);
glutKeyboardFunc(keyboard);
glutMainLoop();
return0;
}
Castingshadowusingstencilbuffer:
Limittherenderingoftheshadowsofthedesiredsurfacesusingthestencilbuffer.
(Drawthesurfaceinthestencilbuffer.)
Projecttheshadowonthesurface.
Turnofflightsandtexturemapping.
Turnoffdepthtest.
Enableblending.
Rendershadowsofobjects.
Restoreoldsettings.
ShadowVolume
Someofthematerialsareadoptedfrom
http://www.gamedev.net/reference/articles/article1873.asp
In1977,FranklinCrowproposedanalgorithmtogeneratepolygonsthatrepresentthe
shadowvolumeofobjectsinthescene,thenplacingthemintotherenderingdata
structureasinvisibleobjects
Stencilshadowvolume
Theshadedregionrepresentstheshadowvolume.
Resultedfromextrudingthesilhouetteedgesfromthepointofviewoflightsource
HowtofindShadowVolume?
First,needtogetthesilhouetteedgesoftheoccluderwithrespecttothelightsource.
Asilhouetteedgeisanedgethatseparatesafront-facingpolygonfromaback-facingpolygon (withrespecttothelightsource).
Fortriangles,thesilhouetteedgesofatriangleareequaltotheedgesofthetriangle.
Next,weextrudethesilhouetteedgesbyprojectingtheverticesawayfromthelightsource(assumingpointlightsource).
Theresultingquadrilateralsdefinetheshadowvolume.
Ausermayhavemanyviewingdirections
Depth-Passstenciloperation
Stencilbuffervaluesgeneratedfromdepth-pass(z-pass)stenciloperations:
Renderobjectsofscenesothatz-buffercontainsthe
'nearest'zvalueofobjectsforeachpixel.
Renderfrontfaceofshadowvolume:Ifdepthtestpasses,incrementstencilvalue,otherwisedoesnothing.(Notethatinthefigureabove,
onlytheshadedpartistheshadowvolume.)
Disabledrawtoframeanddepthbuffer.
Renderbackfaceofshadowvolume:Ifdepthtestpasses,decrementstencilvalue,otherwisedoesnothing.
Disabledrawtoframeanddepthbuffer.
Algorithmworksformultipleshadowvolumes.
Finitevolumemayfailtoshadowotherobjects
Depth-passstenciloperationfailswhentheeyecoordinateisinsidetheshadowvolume.
Carmack'sdepth-fail(z-fail)algorithm(reverseofabove):
Renderbackface:Ifdepthtestfails,incrementstencilvalue,otherwisedoesnothing.Disabledrawtoframeanddepthbuffer.
Renderfrontface:Ifdepthtestfails,decrementstencilvalue,otherwisedoesnothing.Disabledrawtoframeanddepthbuffer.
CappingForDepth-FailTest
Needcappingtoproducecorrectresultsforvariouseyepositions
Frontandbackcapscanbecreatedbyextruding
Needtoensurethattheprimitivesthatdefinetheentireshadowvolumeare
outwardfacing.
Summary
Renderalltheobjectsusingonlyambientlightingandanyothersurface-shadingattribute.
Foreachlightsource,clearthestencilbufferandcalculatethesilhouetteofalloccluders
withrespecttothelightsource.
Extrudethesilhouettetoformtheshadowvolume;generatescapsifnecessary
Rendertheshadowvolumesusingdepth-passordepth-failtest.
Usetheupdatedstencilbuffertothefragmentscorrespondingtononzerostencilvalues.
AnExample:StenciledShadowVolumeinOpenGL
Adoptedfrom
http://www.3ddrome.com/
Definesasurfacestructure:
//aquadsurface
structsurface{
floatvertices[4][3];//contains43Dtuplesrepresentingverticesofaquadrilateralsurface
//relativetopositionofsurface
};
Definesacubestructure:
structcube{
structsurface*surfaces[6];//acubehas6surfaces
floatposition[3];//positionofthecube
};
Renderingasurface'sshadowvolume:
voidrender_surface_shadow_volume(
structsurface*surf,//pointstoasurface
float*surf_pos,//pointstoa3Dtuplerepresentingthesurface'sposition
float*light_pos//pointstoa3Dvecotrrepresentingpositionoflightthat'sblockedbythesurface
){
Usealoopto
addthesurface'spositiontoeachofthesurface'sverticestoobtain
absoluteverticevalues(atthebeginning,averticeisdefined
relativetothe'center'ofthesurface(square))
subtractfromverticesthelightpositionsothatvvaluesarerelative
tothelightposition
storeinthevarraythesurface'sverticesextrudedtowardsinfinityin
thedirectionfromthelighttoeachvertex
inti;
floatv[4][3];
for(i=0;i<4;i++){
surf->vertices[i][0]+=surf_pos[0];
surf->vertices[i][1]+=surf_pos[1];
surf->vertices[i][2]+=surf_pos[2];
//moveorigintolightposition,i.e.T(-xl,-yl,-zl)
v[i][0]=(surf->vertices[i][0]-light_pos[0]); //relativetolightposition
v[i][1]=(surf->vertices[i][1]-light_pos[1]);
v[i][2]=(surf->vertices[i][2]-light_pos[2]);
normalize(v[i]);
v[i][0]*=M_INFINITY;
v[i][1]*=M_INFINITY;
v[i][2]*=M_INFINITY;
//moveoriginbacktooriginalplace,i.e.T(xl,yl,zl)
v[i][0]+=light_pos[0];
v[i][1]+=light_pos[1];
v[i][2]+=light_pos[2];
}
Next,werenderthebackandfrontcapsoftheshadowvolume;thefrontcap
isthesameasthesurfaceitself,andthebackcapisthesurfaceextrudedtowards
infinity.Thisinsuresthatwehaveaclosedshadowvolume,whichisrequiredforthe
stenciloperations.
//backcap(mayextendto'infinity')
glBegin(GL_QUADS);
glVertex3fv(v[3]);
glVertex3fv(v[2]);
glVertex3fv(v[1]);
glVertex3fv(v[0]);
glEnd();
//frontcap
glBegin(GL_QUADS);
glVertex3fv(surf->vertices[0]);
glVertex3fv(surf->vertices[1]);
glVertex3fv(surf->vertices[2]);
glVertex3fv(surf->vertices[3]);
glEnd();
Thenextlooprendersaquadrilateralforeachedgeofthesurface,resultingin
fourquads.Eachquadrilateralstartsattheedgeofthesurfaceitself,andendsat
thecorrespondingedgeoftheextrudedbackcapofthesurface.
glBegin(GL_QUAD_STRIP);
glVertex3fv(surf->vertices[0]);
glVertex3fv(v[0]);
for(i=1;i<=4;i++){
glVertex3fv(surf->vertices[i%4]);
glVertex3fv(v[i%4]);
}
glEnd();
Finally,werestoretheoriginalsurfaceverticesbysubtractingthesurface
positionfromeachofthevertices.
for(i=0;i<4;i++){
surf->vertices[i][0]-=surf_pos[0];
surf->vertices[i][1]-=surf_pos[1];
surf->vertices[i][2]-=surf_pos[2];
}
}
Usedepth-fail(z-fail)testtorendershadowvolume
Renderingashadowvolumeforeachcubesurfacewithfunction
render_cube_shadow(),startingwith:
//renderashadowforeachsurfaceofacube
voidrender_cube_shadow(structcube*c)
{
inti;
for(i=0;i<6;i++){
glColorMask(GL_FALSE,GL_FALSE,GL_FALSE,GL_FALSE);//disablewritingtocolorbuffer
glDepthMask(GL_FALSE);//disablewritingtodepthbuffer(weonlycarestencilbufferhere
glEnable(GL_CULL_FACE);//willenablebothfrontandbackculling(below)
glEnable(GL_STENCIL_TEST);//enablestenciltesting
glEnable(GL_POLYGON_OFFSET_FILL);//forworkingaroundforsomedepthbufferprecisionissues
glPolygonOffset(0.0f,100.0f);//somedepthbufferprecisionissues
Inorderforthestenciloperationstobecarriedoutcorrectly,we'llrendertheshadowvolumeintwopasses.
Infirstpass,whenthedepthtestfails(i.e.,apixelofthepolygonisfurther
awaythanthepixelthat'salreadystoredinitsplaceonthescreen),weincrement
thepixel'sstencilvalue.
glCullFace(GL_FRONT);//cullfrontfacesofshadowvolume;onlydrawsbackfaces
glStencilFunc(GL_ALWAYS,0x0,0xff);//alwayspasses,refvalue=0,mask=0xFF
//keepvaluewhenstenciltestfails,incrementvalueifdepthtestfails,keepvalueifboth
//stenciltestanddepthtestpass
glStencilOp(GL_KEEP,GL_INCR,GL_KEEP);
render_surface_shadow_volume(c->surfaces[i],c->position,light_pos);
Inthefigure,thebluelinesrepresentthecamera'sviewfrustum,soonlypixelsinsideofthatfrustumhavestencilvalues.
Theshadedportioniswherethestencilvaluewouldbeincremented.Becausethestencilvalueis
incrementedwhenthedepth-testfails,everythingbetweenthecameraandtherenderedbackfaces
hasitsstencilvalueincremented.
Asyoucansee,theentire"occludedsphere"isconsideredtobeshadowedatthispoint,whichis
notcorrect.Soweneedthesecondpass:
glCullFace(GL_BACK);//cullbackfaces;onlydrawfrontfacesofshadowvolume
glStencilFunc(GL_ALWAYS,0x0,0xff);
glStencilOp(GL_KEEP,GL_DECR,GL_KEEP);//decrementstencilvaluewhendepthtestfails
render_surface_shadow_volume(c->surfaces[i],c->position,light_pos);
Finishthefunctionwith:
glDisable(GL_POLYGON_OFFSET_FILL);//disablepolygonoffset
glDisable(GL_CULL_FACE);//disablefront/backculling
glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE);//reanblewritingtocolorbuffer
glDepthMask(GL_TRUE);//renablewritingtodepthbuffer
glStencilFunc(GL_NOTEQUAL,0x0,0xff);//reseteachpixel'sstencilvalue
glStencilOp(GL_REPLACE,GL_REPLACE,GL_REPLACE);//foranythingwedraw.
draw_shadow();//drawtheshadow(darkquad)
glDisable(GL_STENCIL_TEST);//disablestenciltesting
}
}