Casting Shadows Introduction

文章推薦指數: 80 %
投票人數:10人

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 } }



請為這篇文章評分?