Overlap and Depth Buffering
文章推薦指數: 80 %
Like the color buffer, the depth buffer for the main window is created automatically by OpenGL when OpenGL is initialized. OpenGL can even be created ... OverlapandDepthBufferingPrev Chapter 5. ObjectsinDepth NextOverlapandDepthBuffering Regardlessofhowwerendertheobjects,thereisastrangevisualproblemwithwhat we'rerendering: Ifthesmallerobjectistrulybehindthelargerone,whyisitbeingrenderedontop ofthelargerone?Well,toanswerthatquestion,weneedtorememberwhatOpenGL is. TheOpenGLspecificationdefinesarasterization-basedrenderer.Rasterizersoffer greatopportunitiesforoptimizationsandhardwareimplementation,andusingthem providesgreatpowertotheprogrammer.However,they'reverystupid.Arasterizeris basicallyjustatriangledrawer.Vertexshaderstellitwhatvertexpositionsare,and fragmentshaderstellitwhatcolorstoputwithinthattriangle.Butnomatterhow fancy,arasterization-basedrenderisjustdrawingtriangles. That'sfineingeneralbecauserasterizersareveryfast.Theyareverygoodat drawingtriangles. Butrasterizersdoexactlyandonlywhattheusersays.Theydraweachtriangle intheordergiven.Thismeansthat,ifthereisoverlap betweenmultipletrianglesinwindowspace,thetrianglethatisrenderedlastwillbe theonethatisseen. Thisproblemiscalledhiddensurfaceelimination. Thefirstthingyoumightthinkofwhensolvingthisproblemistosimplyrenderthe mostdistantobjectsfirst.Thisiscalleddepthsorting.Asyou mightimagine,this“solution”scalesincrediblypoorly.Doingitforeach triangleisprohibitive,particularlywithsceneswithmillionsoftriangles. Andtheworstpartisthatevenifyouputinalltheeffort,itdoesnotactually work.Notallthetimeatanyrate.Manytrivialcasescanbesolvedviadepthsorting, butnon-trivialcaseshaverealproblems.Youcanhaveanarrangementof3triangles whereeachoverlapstheother,suchthattheresimplyisnoorderyoucanrenderthemin toachievetherighteffect. Figure 5.2. ThreeOverlappingTriangles Evenworse,itdoesnothingforinter-penetratingtriangles;thatis,trianglesthat passthrougheachotherin3Dspace(asopposedtojustfromtheperspectiveofthe camera). Depthsortingisnotgoingtocutit;clearly,weneedsomethingbetter. Onesolutionmightbetotagfragmentswiththedistancefromtheviewer.Then,ifa fragmentthatisabouttobewrittenhasafartherdistance(ie:thefragmentisbehind whatwasalreadydrawn),wesimplydonotwritethatfragmenttotheoutputimage.That way,ifyoudrawatrianglebehindothertriangles,thefragmentdistancesthatwere alreadywrittenwillbeclosertothecamerathanthefragmentdistancesofthenew triangle.Andthus,theparticularfragmentsofthattrianglewillnotbedrawn.And sincethisworksatthefragmentlevel,itwillworkjustaswellforintersecting trianglesorthe3trianglearrangementdepictedabove. The“tag”isthewindow-spaceZvalue.Youmayrecallfromtheintroductionthatthewindow-spaceZ positionofafragmentrangesfrom0to1,where0istheclosestand1isthe farthest. Colorsoutputfromthefragmentshaderareoutputintothecolorimagebuffer. Thereforeitnaturallyfollowsthatdepthvalueswouldbestoredinadepth buffer(alsocalledazbuffer,becauseitstores Zvalues).Thedepthbufferisanimagethatisthesamesizeasthemaincolorbuffer, thatstoresdepthvaluesaspixelsratherthancolors.Whereacolorisa4-component vector,adepthisjustasinglefloating-pointvalue. Likethecolorbuffer,thedepthbufferforthemainwindowiscreatedautomatically byOpenGLwhenOpenGLisinitialized.OpenGLcanevenbecreatedwithoutadepthbuffer. SinceFreeGLUTtakescareofinitializingOpenGLforus,wetellitinthestandard initializationcodetocreateOpenGLwithadepthbuffer. Writingthedepthisnotenough.Thesuggestedidearequiresstoppingthefragment fromwritinganythingifthecurrentdepthatthatlocationisinfrontofthis fragment'sdepth.Thisiscalledthedepthtest.InOpenGL,the testdoesnothavetobeinanyparticulardirection;anyofthetypicalnumerical relationoperator(greaterthan,lessthan,etc)willworkfine.Ifthetestpasses, thenthefragment'soutputs(bothcoloranddepth)willbewrittentotheirappropriate buffer.Ifitfails,thentheywillnot. Toactivatedepthtesting,wemustcall glEnable(GL_DEPTH_TEST);thecorresponding glDisablecallwillcausedepthtestingtocease.After activatingtesting,weneedtocallglDepthFunctosettherelation ofthedepthtest.Whenthetestistrue,theincomingfragmentiswritten. ThetestfunctionscanbeGL_ALWAYS(alwayswritethefragment), GL_NEVER(nofragmentsarewritten),GL_LESS, GL_GREATER,GL_LEQUAL(<=), GL_GEQUAL(>=),GL_EQUAL,or GL_NOTEQUAL.Thetestfunctionputstheincomingfragment'sdepth ontheleftoftheequationandontherightisthedepthfromthedepthbuffer.So GL_LESSmeansthat,whentheincomingfragment'sdepthislessthanthedepthfromthe depthbuffer,theincomingfragmentiswritten. Withthefragmentdepthbeingsomethingthatispartofafragment'soutput,youmight imaginethatthisissomethingyouhavetocomputeinafragmentshader.Youcertainly can,butthefragment'sdepthisnormallyjustthewindow-spaceZcoordinateofthe fragment.ThisiscomputedautomaticallywhentheXandYarecomputed. Usingthewindow-spaceZvalueasthefragment'soutputdepthissocommonthat,if youdonotdeliberatelywriteadepthvaluefromthefragmentshader,thisvaluewillbe usedbydefault. DepthandtheViewport Speakingofwindowcoordinates,thereisonemoreissueweneedtodealwithwhen dealingwithdepth.TheglViewportfunctiondefinesthe transformbetweennormalizeddevicecoordinates(therange[-1,1])towindow coordinates.ButglViewportonlydefinesthetransformforthe XandYcoordinatesoftheNDC-spacevertexpositions. Thewindow-spaceZcoordinaterangesfrom[0,1];thetransformationfromNDC's [-1,1]rangeisdefinedwiththeglDepthRangefunction.This functiontakes2floating-pointparameters:therangezNear andtherangezFar.Thesevaluesareinwindow-space;they defineasimplelinearmappingfromNDCspacetowindowspace.SoifzNearis0.5 andzFaris1.0,NDCvaluesof-1willmapto0.5andvaluesof1willresultin 1.0. Note DonotconfusetherangezNear/zFarwiththecamera zNear/zFarusedintheperspectiveprojectionmatrixcomputation. TherangezNearcanbegreaterthantherangezFar;ifitis,thenthe window-spacevalueswillbereversed,intermsofwhatconstitutesclosestor farthestfromtheviewer. Earlier,itwassaidthatthewindow-spaceZvalueof0isclosestand1is farthest.However,ifourclip-spaceZvalueswerenegated,thedepthof1wouldbe closesttotheviewandthedepthof0wouldbefarthest.Yet,ifweflipthe directionofthedepthtest(GL_LESStoGL_GREATER,etc),wegettheexactsame result.Similarly,ifwereversetheglDepthRangesothat1isthedepthzNearand0 isthedepthzFar,wegetthesameresultifweuseGL_GREATER.Soit'sreallyjust aconvention. Z-Flip:NeverDoThis Intheelderdaysofgraphicscards,callingglClearwas aslowoperation.Andthismakessense;clearingimagesmeanshavingtogo througheverypixelofimagedataandwritingavaluetoit.Evenwithhardware optimizedroutines,ifyoucanavoiddoingit,yousavesomeperformance. Therefore,gamedevelopersfoundcleverwaystoavoidclearinganything.They avoidedclearingtheimagebufferbyensuringthattheywoulddrawtoevery pixelonthescreeneveryframe.Avoidingclearingthedepthbufferwasrather moredifficult.Butdepthrangeandthedepthtestgavethemawaytodo it. Thetechniqueisquitesimple.Theywouldneedtoclearthebuffersexactly once,atthebeginningoftheprogram.Fromthenon,theywoulddothe following. TheywouldrenderthefirstframewithaGL_LESSdepth test.However,thedepthrangewouldbe[0,0.5];thiswouldonlydrawtohalf ofthedepthbuffer.Sincethedepthtestisless,itdoesnotmatterwhat valuesjustsohappenedtobebetween0.5and1.0inthedepthbuffer beforehand.Andsinceeverypixelwasbeingrenderedtoasabove,thedepth bufferisguaranteedtobefilledwithvaluesthatarelessthan0.5. Onthenextframe,theywouldrenderwithaGL_GREATER depthtest.Onlythistime,thedepthrangewouldbe[1,0.5].Becausethelast framefilledthedepthbufferwithvalueslessthan0.5,allofthosedepth valuesareautomatically“behind”everythingrenderednow.This fillsthedepthbufferwithvaluesgreaterthan0.5. Rinseandrepeat.Thisultimatelysacrificesonebitofdepthprecision,since eachrenderingonlyuseshalfofthedepthbuffer.Butitresultsinnever needingtoclearthedepthorcolorbuffers. Oh,andyoushouldneverdothis. See,hardwaredevelopersgotreallysmart.Theyrealizedthatacleardidnot reallyhavetogotoeachpixelandwriteavaluetoit.Instead,theycould simplypretendthattheyhad.Theybuiltspeciallogicintothememory architecture,suchthatattemptingtoreadfromlocationsthathavebeen “cleared”resultsingettingtheclearcolorordepth value. Becauseofthat,thisz-fliptechniqueisuseless.Butit'sratherworsethan that;onmosthardwaremadeinthelast7years,itactuallyslowsdown rendering.Afterall,gettingaclearedvaluedoesn'trequireactuallyreading memory;theveryfirstvalueyougetfromthedepthbufferisfree.Thereare other,hardware-specific,optimizationsthatmakez-flipactivelydamagingto performance. RenderingwithDepth TheDepthBufferingprojectshowsoffhowto turnonandusethedepthbuffer.ItisbasedontheBaseVertexrenderingofthe objects. Theinitializationroutinehasallofthebasicdepthtestingcodeinit: Example 5.10. DepthBufferSetup glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); glDepthFunc(GL_LEQUAL); glDepthRange(0.0f,1.0f); Thesearethemostcommondepthtestingparameters.Itturnsondepthtesting, setsthetestfunctiontolessthanorequalto,andsetstherangemappingtothe fullacceptedrange. ItiscommontouseGL_LEQUALinsteadof GL_LESS.Thisallowsfortheuseofmultipassalgorithms, whereyourenderthesamegeometrywiththesamevertexshader,butlinkedwitha differentfragmentshader.We'lllookatthosemuch,muchlater. ThecalltoglDepthMaskcausesrenderingtowritethedepth valuefromthefragmenttothedepthbuffer.Theactivationofdepthtestingalone isnotsufficienttoactuallywritedepthvalues.Thisallowsustohavedepth testingforobjectswheretheirowndepth(theincoming fragment'sdepth)isnotwrittentothedepthbuffer,evenwhentheircoloroutputs arewritten.Wedonotusethishere,butaspecialalgorithmmightneedthis feature. Note DuetoanoddquirkofOpenGL,writingtothedepthbufferisalwaysinactive ifGL_DEPTH_TESTisdisabled,regardlessofthedepthmask. Ifyoujustwanttowritetothedepthbuffer,withoutactuallydoingatest, youmustenableGL_DEPTH_TESTandusethedepthfunctionof GL_ALWAYS. Thereisonemoreissue.Weknowwhatthedepthvalueisinthedepthbufferafter afragmentiswrittentoit.Butwhatisitsvaluebeforeanyrenderingisdoneat all?Depthbuffersandcolorbuffersareverysimilar;colorbuffersgettheir initialcolorsfromcallingglClear.Soyoumightimaginea similarcallfordepthbuffers. Asitturnsout,theysharethesameclearingcall.Ifyourecall, glClearColorsetsthecolorforclearingcolorbuffers. Similarly,glClearDepthsetsthedepthvaluethatthedepth bufferwillbeclearedto. InordertoclearthedepthbufferwithglClear,youmustuse theGL_DEPTH_BUFFER_BIT.So,thedrawingfunction'sclearing,at thetopofthefunction,happensasfollows: Example 5.11. DepthBufferClearing glClearColor(0.0f,0.0f,0.0f,0.0f); glClearDepth(1.0f); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); Thiswillsetallofthedepthvaluesinthedepthbufferto1.0,whichisour rangezFar. Note Thisisallthatisnecessarytododepthbuffering,asfarasOpenGLproper isconcerned.However,inordertousedepthbuffering,theframebuffermust includeadepthbufferinadditiontoanimagebuffer.Thisinitializationcode isplatform-specific,butFreeGLUTtakescareofitforus.Ifyoudograduate fromFreeGLUT,makesurethatyouusetheappropriateinitializationmechanism foryourplatformtocreateadepthbufferifyouneedtododepth buffering. Ournewimagelookslikethis: Figure 5.3. DepthBuffering Whichmakesalotmoresense.Nomatterwhatorderwedrawtheobjectsin,weget areasonableresult. Let'stestourdepthbufferingabitmore.Let'screatealittleoverlapbetween thetwoobjects.Changethefirstoffsetuniformstatementin displaytobethis: glUniform3f(offsetUniform,0.0f,0.0f,-0.75f); Wenowgetsomeoverlap,buttheresultisstillreasonable: Figure 5.4. MildOverlap Wecanevenchangethelinetocausemajoroverlapwithoutincident: glUniform3f(offsetUniform,0.0f,0.0f,-1.0f); Whichgivesus: Figure 5.5. MajorOverlap Noamountofdepthsortingwillhelpwiththat. ForkmeonGitHubPrev Up NextOptimization:BaseVertex Home BoundariesandClipping
延伸文章資訊
- 1Depth Test - OpenGL Wiki
The Depth Test is a per-sample processing operation performed after the Fragment Shader (and some...
- 2Overlap and Depth Buffering
Like the color buffer, the depth buffer for the main window is created automatically by OpenGL wh...
- 3Force depth test against a specific depth value, instead of ...
Not the answer you're looking for? Browse other questions tagged opengl glsl opengl-3 depth-testi...
- 4Calculating Primitive Visibility Using Depth Testing - Apple Developer
- 5Depth testing - LearnOpenGL