Tutorial 43 - Multipass Shadow Mapping With Point Lights
文章推薦指數: 80 %
In tutorial 24 we learned the basics of Shadow Mapping - first a rendering pass from the light point of view using the light direction as the viewing vector ...
Background
Intutorial24welearnedthebasicsofShadowMapping-firstarenderingpassfromthelight
pointofviewusingthelightdirectionastheviewingvectorandthenasecondpassfrom
thecamerapointofviewusingthedatafromthefirstpassforshadowcalculation.Atthis
pointmostprogrammerswillaskthemselves:thisisfinefordirectional/spotlightbutwhat
ifIwanttogenerateshadowsfromapointlight?Thereisnospecificlightdirectioninthis
case.Solvingthisproblemisthetopicofthistutorial.
Thesolutiontothisproblemistorecognizethatapointlightbasicallycastsitslightin
alldirections,soratherthanplacearectangularshadowmaptexturesomewherethatwillonly
receiveasmallportionofthatlight,wecanplacethelightsourceinamiddleofatexture
cube.Wenowhavesixrectangularshadowmapsandthelighthasnowheretoescape.Everylight
"beam"hastolandononeofthesesixshadowmapsandwecansamplefromittodoourstandard
shadowcalculations.Wehavealreadyseenthecubemapinactionintheskyboxtutorialsowe
arealreadyfamiliarwithit.
Inpractice,inordertosimulatethenotionofspreadinglightalloverwewilldosixshadow
maprenderingpassesfromthelocationofthelightsourcebuteachrenderingpasswilltarget
adifferentdirection.Wearegoingtomakethisverysimpleandtargetthefollowingaxis
aligneddirections:positive/negativeX,positive/negativeYandpositive/negativeZ.Eventually
thecubemapfaceswillcontainthedistanceofallpixelsinthescenethatareclosesttothe
lightsource.Bycomparingthisvaluetothedistanceofeachpixeltothelightduringthe
lightingpasswecantellwhetherthatpixelisinlightorshadow.
Takealookatthefollowingpicture:
Ourscenecontainsabluesphereandapointlight(theyellowlightbulb)isstationed
nearby.Inthefirstrenderingpassweuseatexturecubeastheframebuffer.Rememberthat
atthisstagewedon'tcareabouttheoriginalcameralocationordirection.Weplacethe
cameraatthepositionofthepointlightsoitalwayslookslikeitislocatedatthemiddle
ofthetexturecube.Intheexampleaboveweseethatthecurrentrenderingdirectionisthe
positiveZaxis(intotheyellowface).Atthispointwearebacktothestandardshadow
mappingprocesssousingthedepthvaluesintheyellowfacewecangeneratetheproper
shadowforthebluesphere(thesedepthvaluesarelocatedintheblackcirclebuttheactual
shadowwillberenderedinthesecondpass).
Thefollowingpicturedemonstratesthesixcameradirectionsthatwewillusein
thefirstrenderingpass:
Sincethesamesceneisrenderedsixtimesinthefirstrenderingpasswecallthis
MultipassShadowMapping.
Sourcewalkthru
(shadow_map_fbo.h)
classShadowMapFBO
{
public:
ShadowMapFBO();
~ShadowMapFBO();
boolInit(unsignedintWindowWidth,unsignedintWindowHeight);
voidBindForWriting(GLenumCubeFace);
voidBindForReading(GLenumTextureUnit);
private:
GLuintm_fbo;
GLuintm_shadowMap;
GLuintm_depth;
};
Let'sstartthecodewalkthrubyreviewingthechangesinourshadowmapFBO.
TheFBOismostlythesamewithtwominorchanges:theBindForWriting()method
nowtakesacubefaceenumerator.Sincewearedoingamultipassrendering
intothecubemapthisishowwewilltelltheGLwhichcubefacewearegoing
torender.Thesecondchangeistheadditionofaseparatedepthbuffer.Previously
weusedthem_shadowMapclassmemberastheshadowmapobject(whichisactually
adepthbuffer).Nowm_shadowMapisgoingtobeusedasacubemapandwe
needadedicateddepthbuffer.Foreachofthesixpassesintothecubemapfaces
wewillusethisdepthbuffer(andnaturallywewillclearitbeforeeachpass).
(shadow_map_fbo.cpp:46)
boolShadowMapFBO::Init(unsignedintWindowWidth,unsignedintWindowHeight)
{
//CreatetheFBO
glGenFramebuffers(1,&m_fbo);
//Createthedepthbuffer
glGenTextures(1,&m_depth);
glBindTexture(GL_TEXTURE_2D,m_depth);
glTexImage2D(GL_TEXTURE_2D,0,GL_DEPTH_COMPONENT32,WindowWidth,WindowHeight,0,GL_DEPTH_COMPONENT,GL_FLOAT,NULL);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
glBindTexture(GL_TEXTURE_2D,0);
//Createthecubemap
glGenTextures(1,&m_shadowMap);
glBindTexture(GL_TEXTURE_CUBE_MAP,m_shadowMap);
glTexParameteri(GL_TEXTURE_CUBE_MAP,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP,GL_TEXTURE_WRAP_R,GL_CLAMP_TO_EDGE);
for(uinti=0;i<6;i++){
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X+i,0,GL_R32F,WindowWidth,WindowHeight,0,GL_RED,GL_FLOAT,NULL);
}
glBindFramebuffer(GL_FRAMEBUFFER,m_fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER,GL_DEPTH_ATTACHMENT,GL_TEXTURE_2D,m_depth,0);
//Disablewritestothecolorbuffer
glDrawBuffer(GL_NONE);
//Disablereadsfromthecolorbuffer
glReadBuffer(GL_NONE);
GLenumStatus=glCheckFramebufferStatus(GL_FRAMEBUFFER);
if(Status!=GL_FRAMEBUFFER_COMPLETE){
printf("FBerror,status:0x%x\n",Status);
returnfalse;
}
glBindFramebuffer(GL_FRAMEBUFFER,0);
returnGLCheckError();
}
Thisishowweinitializetheshadowmap.Firstwecreateandsetupthedepth
buffer.Nothingnewhere.Nextcomesthecubemaptexture.GL_TEXTURE_CUBE_MAP
isusedasthetarget.Theinterestingparthereisthewayweinitialize
thesixcubefaces.OpenGLprovidesamacroforeachface:GL_TEXTURE_CUBE_MAP_POSITIVE_X,
GL_TEXTURE_CUBE_MAP_NEGATIVE_X,etc.
Theyhappentobedefinessequentiallywhichmakestheloopabovepossible(seeglew.h
fortheremainingmacros;aroundline1319intheversionIhave).Eachface
isinitializedwithasingle32bitfloatingpointvalueineachtexel.
(tutorial43.cpp:183)
virtualvoidRenderSceneCB()
{
CalcFPS();
m_scale+=0.05f;
m_pGameCamera->OnRender();
ShadowMapPass();
RenderPass();
RenderFPS();
glutSwapBuffers();
}
Thisisthemainrenderscenefunctionandasyoucansee,thereisnochange
incomparisontopreviousshadowmappingtutorials.Atthehighlevelwehave
thesametwopassesofshadowmapgenerationandrendering.
(tutorial43.cpp:200)
voidShadowMapPass()
{
glCullFace(GL_FRONT);
m_shadowMapEffect.Enable();
PersProjInfoProjInfo;
ProjInfo.FOV=90.0f;
ProjInfo.Height=WINDOW_HEIGHT;
ProjInfo.Width=WINDOW_WIDTH;
ProjInfo.zNear=1.0f;
ProjInfo.zFar=100.0f;
Pipelinep;
p.SetPerspectiveProj(m_persProjInfo);
glClearColor(FLT_MAX,FLT_MAX,FLT_MAX,FLT_MAX);
for(uinti=0;i
延伸文章資訊
- 1Point Shadows - LearnOpenGL
The technique is mostly similar to directional shadow mapping: we generate a depth map from the l...
- 2Tutorial 43 - Multipass Shadow Mapping With Point Lights
In tutorial 24 we learned the basics of Shadow Mapping - first a rendering pass from the light po...
- 3Tutorial 16 : Shadow mapping
Light-space perspective Shadow Maps
- 4View matrix for point light shadows - Graphics - Community
This is because I wanted more fine control over the individual textures that a cube map was givin...
- 5More Efficient Virtual Shadow Maps for Many Lights - newq.net
To this end we use. Clustered Deferred Shading [3], as our starting point. This algorithm offers ...