Introduction to Computer Graphics, Section 7.4 -- Framebuffers
文章推薦指數: 80 %
In WebGL, a framebuffer is a data structure that organizes the memory resources that are needed to render an image. A WebGL graphics context has a default ... [PreviousSection| NextSection| ChapterIndex| MainIndex] Subsections FramebufferOperations RenderToTexture Renderbuffers DynamicCubemapTextures Section7.4 Framebuffers Theterm"framebuffer"traditionallyreferstotheregionofmemorythatholds thecolordatafortheimagedisplayedonacomputerscreen.InWebGL,a framebufferisadatastructurethatorganizesthe memoryresourcesthatareneededtorenderanimage.A WebGLgraphics contexthasadefaultframebuffer,whichisusedfortheimagethat appearsonthescreen.Thedefaultframebufferiscreatedbythecallto canvas.getContext()thatcreatesthegraphicscontext.Itsproperties dependontheoptionsthatarepassedtothatfunctionandcannotbechangedafteritiscreated. However,additionalframebufferscanbecreated,withpropertiescontrolled bytheWebGLprogram.Theycanbeusedforoff-screenrendering,andthey arerequiredforcertainadvancedrenderingalgorithms. Aframebuffercanuseacolorbuffertoholdthecolordata foranimage,adepthbuffertoholdadepthvalueforeach pixel,andsomethingcalledastencilbuffer(whichisnotcoveredinthis textbook).Thebuffersaresaidtobe"attached"totheframebuffer. Foranon-defaultframebuffer,bufferscanbeattachedanddetachedbythe WebGLprogramatanytime.Aframebufferdoesn'tneedafullsetofthreebuffers, butyouneedacolorbuffer,adepthbuffer,orbothtobeabletousetheframebufferforrendering. Ifthedepthtestisnotenabledwhenrenderingtotheframebuffer,thennodepthbufferisneeded. Andsomerenderingalgorithms,suchasshadowmapping(Subsection 5.3.3) useaframebufferwithadepthbufferbutnocolorbuffer.InWebGL 2.0,itisalso possibletoattachseveralcolorbufferstothesameframebuffer, whichcanbeusefulforcertainadvancedalgorithms andcomputationalapplications.(Also,seeSubsection 7.5.4.) Therenderingfunctionsgl.drawArrays()andgl.drawElements()affectthe currentframebuffer,whichisinitiallythedefaultframebuffer.Thecurrentframebuffer canbechangedbycalling gl.bindFramebuffer(gl.FRAMEBUFFER,frameBufferObject); Thefirstparametertothisfunctionisalwaysgl.FRAMEBUFFER.Thesecondparameter canbenulltoselectthedefaultframebufferfordrawing,oritcan beanon-defaultframebuffercreatedbythefunctiongl.createFramebuffer(), whichwillbediscussedbelow. 7.4.1 FramebufferOperations Beforewegettoexamplesofusingnon-defaultframebuffers,welookatsome WebGLsettingsthataffectrenderingintowhicheverframebufferiscurrent.Examplesthat wehavealreadyseenincludetheclearcolor,whichisusedtofillthecolorbuffer whengl.clear()iscalled,andtheenabledstateofthedepthtest. Anotherexamplethataffectstheuseofthedepthbufferisthedepthmask, abooleanvaluethatcontrolswhethervaluesarewrittentothedepthbufferduringrendering. (Theenabledstateofthedepthtestdetermineswhethervaluesfromthedepthbufferareused duringrendering;thedepthmaskdetermineswhethernewvaluesarewrittentothedepth buffer.)Writingtothedepthbuffercanbeturnedoffwiththecommand gl.depthMask(false); andcanbeturnedbackonbycallinggl.depthMask(true).Thedefault valueistrue. Oneexampleofusingthedepthmaskisforrenderingtranslucentgeometry.Whensomeofthe objectsinascenearetranslucent,thenalloftheopaqueobjectsshouldberenderedfirst, followedbythetranslucentobjects.Supposethatyourenderedatranslucentobject,and thenrenderedanopaqueobjectthatliesbehindthetranslucentobject.Thedepthtest wouldcausetheopaqueobjecttobehiddenbythetranslucentobject.But"translucent"means thattheopaqueobjectshouldbevisiblethroughthetranslucentobject.Soit'simportant torenderalltheopaqueobjectsfirst.Andit'simportanttoturnoffwriting tothedepthbuffer,bycallinggl.depthMask(false), whilerenderingthetranslucentobjects.Thereasonisthata translucentobjectthatisdrawnbehindanothertranslucentobjectshouldbevisible throughthefrontobject.Note,however,thatthedepthtestmuststillbeenabled whilethetranslucentobjectsarebeingrendered,sinceatranslucentobjectcanbehidden byanopaqueobject.Also,alphablendingmustbeonwhilerenderingthe translucentobjects. Forfullycorrectrenderingoftranslucentobjects,thetranslucent primitivesshouldbe sortedintoback-to-frontorderbeforerendering,asinthepainter'salgorithm (Subsection 3.1.4).However,thatcanbedifficulttoimplement,andacceptable resultscansometimesbeobtainedbyrenderingthetranslucentprimitivesinarbitrary order(butstillaftertheopaqueprimitives). Infactthatwasdoneinthedemosc3/rotation-axis.htmlfrom Subsection 3.2.2andc3/transform-equivalence-3d.htmlfrom Subsection 3.3.4. Itisalsopossibletocontrolwritingtothecolorbuffer,usingthecolormask. Thecolorbufferhasfour"channels"correspondingtothered,green,blue,andalphacomponents ofthecolor.Eachchannelcanbecontrolledseparately.Youcould,forexample,allowwriting totheredandalphacolorchannels,whileblockingwritingtothegreenandbluechannels. Thatwouldbedonewiththecommand gl.colorMask(true,false,false,true); ThecolorMaskfunctiontakesfourparameters,oneforeachcolorchannel.Atrue valueallowswritingtothechannel;afalsevalueblockswriting.Whenwritingisblocked forachannelduringrendering,thevalueofthecorrespondingcolorcomponentissimplyignored. Oneuseofthecolormaskisforanaglyphstereorendering(Subsection 5.3.1). Ananaglyphstereoimagecontainstwoimagesofthescene,oneintendedforthelefteyeandone fortherighteye.Oneimageisdrawnusingonlyshadesofred,whiletheotheruses onlycombinationsofgreenandblue.Thetwoimagesaredrawnfromslightlydifferent viewpoints,correspondingtotheviewsfromtheleftandtherighteye.Sothealgorithmfor anaglyphstereohastheform gl.clearColor(0,0,0,1); gl.clear(gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT); gl.colorMask(true,false,false,false);//writetoredchannelonly ...//setupviewfromlefteye ...//renderthescene gl.clear(gl.DEPTH_BUFFER_BIT);//clearonlythedepthbuffer gl.colorMask(false,true,true,false);//writetogreenandbluechannels ...//setupviewfromrighteye ...//renderthescene Onewaytosetuptheviewsfromtheleftandrighteyesissimplytorotatethe viewbyafewdegreesaboutthey-axis.Notethatthedepthbuffer,butnot thecolorbuffer,mustbeclearedbeforedrawingthesecondimage,sinceotherwise thedepthtestwouldpreventsomepartsofthesecondimagefrombeingwritten. Finally,Iwouldliketolookatblendinginmoredetail.Blendingrefersto howthefragmentcolorfromthefragmentshaderiscombinedwiththecurrentcolor ofthefragmentinthecolorbuffer.Thedefault,assumingthatthefragmentpasses thedepthtest,istoreplacethecurrentcolorwiththefragmentcolor.Whenblending isenabled,thecurrentcolorcanbereplacedwithsomecombinationofthecurrent colorandthefragmentcolor.Previously,Ihaveonly discussedturningonalphablendingfortransparencywiththecommands gl.enable(gl.BLEND); gl.blendFunc(gl.SRC_ALPHA,gl.ONE_MINUS_SRC_ALPHA); Thefunctiongl.blendFunc()determineshowthenewcoloriscomputed fromthecurrentcolorandthefragmentcolor.Withtheparametersshownhere, theformulaforthenewcolor,usingGLSLsyntax,is (src*src.a)+(dest*(1-src.a)) wheresrcisthe"source"color(thatis,thecolorthatisbeingwritten, thefragmentcolor)anddestisthe"destination"color(thatis,thecolor currentlyinthecolorbuffer,whichisthedestinationoftherenderingoperation). Andsrc.aisthealphacomponentofthesourcecolor.Theparametersto gl.blendFunc()determinethecoefficients—src.aand(1−src.a)—in theformula.Thedefaultcoefficientsfortheblendfunctionaregivenby gl.blendFunc(gl.ONE,gl.ZERO); whichspecifiestheformula (src*1)+(dest*0) Thatis,thenewcolorisequaltothesourcecolor;thereisnoblending. NotethatblendingappliestothealphacomponentaswellastheRGBcomponentsofthe color,whichisprobablynotwhatyouwant.Whendrawingwithatranslucentcolor,itmeans thatthecolorthatiswrittentothecolorbufferwillhaveanalphacomponentlessthan 1. Whenrenderingtoacanvasonawebpage,thiswillmakethecanvasitselftranslucent,allowing thebackgroundofthecanvastoshowthrough.(ThisassumesthattheWebGLcontextwas createdwithanalphachannel,whichisthedefault.)Toavoidthat,youcansettheblendfunction withthealternativecommand gl.blendFuncSeparate(gl.SRC_ALPHA,gl.ONE_MINUS_SRC_ALPHA, gl.ZERO,gl.ONE); Thetwoextraparametersspecifyseparatecoefficientstobeusedforthe alphacomponentintheformula,whilethefirsttwoparametersareusedonlyfortheRGBcomponents. Thatis,thenewcolorforthecolorbufferiscomputedusingtheformula vec4((src.rgb*src.a)+(dest.rgb*(1-src.a)),src.a*0+dest.a*1); Withthisformula,thealphacomponentinthedestination(thecolorbuffer)remains thesameasitsoriginalvalue. Theblendfunctionsetbygl.blendFunc(gl.ONE,gl.ONE)cansometimesbe usedinmulti-passalgorithms.Inamulti-passalgorithm,asceneis renderedseveraltimes,andtheresultsarecombinedsomehowtoproducethefinal image.(Anaglyphstereorenderingisanexample.)Ifyousimplywanttoaddupthe resultsofthevariouspasses,thenyoucanfillthecolorbufferwithzeros,enable blending,andsettheblendfunctionto(gl.ONE,gl.ONE)duringrendering. Asasimpleexample,thesampleprogramwebgl/image-blur.html usesamulti-passalgorithmtoimplementblurring.Thesceneintheexampleisjusta textureimageappliedtoarectangle,sotheeffectistoblurthetextureimage. Thetechniqueinvolvesdrawingthesceneninetimes.Inthefragmentshader, thecolorisdividedbynine.Blendingisusedtoaddthefragmentcolorsfromthe ninepasses,sothatthefinalcolorinthecolorbufferistheaverageofthecolors fromtheninepasses.Foreightoftheninepasses,thesceneisoffsetslightly fromitsoriginalposition,sothatthecolorofapixelinthefinalimageis theaverageofthecolorsofthatpixelandthesurroundingpixelsfromtheoriginal scene. 7.4.2 RenderToTexture Theprevioussubsectionappliestoanyframebuffer.Butwehaven't yetusedanon-defaultframebuffer.Weturntothattopicnow. Oneuseforanon-defaultframebufferistorenderdirectlyintoatexture. Thatis,thememoryoccupiedbyatextureimagecanbeattachedtotheframebuffer asitscolorbuffer,sothatrenderingoperationswillsendtheiroutputto thetextureimage.Thistechnique,whichiscalledrender-to-texture, isusedinthesampleprogramwebgl/render-to-texture.html. Texturememoryisnormallyallocatedwhenanimageisloadedintothetexture usingthefunctiongl.texImage2Dorgl.copyTexImage2D.(SeeSection 6.4.) However,thereisaversionofgl.texImage2Dthatcanbeusedtoallocatememory withoutloadinganimageintothatmemory.Hereisanexample,fromthesampleprogram: texture=gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D,texture); gl.texImage2D(gl.TEXTURE_2D,0,gl.RGBA,512,512, 0,gl.RGBA,gl.UNSIGNED_BYTE,null); Itisthenullparameterattheendofthelastlinethattells gl.texImage2Dtoallocatenewmemorywithoutloadingexistingimagedatatofillthatmemory. Instead,thenewmemoryisfilledwithzeros.Thefirstparametertogl.texImage2Dis thetexturetarget.Thetargetisgl.TEXTURE_2Dfornormaltextures, butothervaluesareusedforworkingwithcubemaptextures.Thefourthand fifthparametersspecifytheheightandwidthoftheimage;theyshouldbepowersoftwo. Theotherparameters usuallyhavethevaluesshownhere;theirmeaningsarethesameasforthe versionofgl.texImage2DdiscussedinSubsection 6.4.3. Notethatthetextureobjectmustfirstbecreatedandbound;gl.texImage2Dapplies tothetexturethatiscurrentlyboundtotheactivetextureunit. (InWebGL 2.0,thesamethingcanalsobeaccomplishedusingthe gl.texStorage2D()functiondiscussedinSubsection 6.4.6.) Toattachthetexturetoaframebuffer,youneedtocreateaframebufferobject andmakethatobjectthecurrentframebufferbybindingit.Forexample, framebuffer=gl.createFramebuffer(); gl.bindFramebuffer(gl.FRAMEBUFFER,framebuffer); Thenthefunctiongl.framebufferTexture2Dcanbeusedtoattachthe texturetotheframebuffer: gl.framebufferTexture2D(gl.FRAMEBUFFER,gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D,texture,0); Thefirstparameterisalwaysgl.FRAMEBUFFER.Thesecondparameter saysacolorbufferisbeingattached.Thelastcharacteringl.COLOR_ATTACHMENT0 isazero,whichallowsthepossibilityofhavingmorethanonecolor bufferattachedtoaframebuffer(althoughinstandardWebGL 1.0,onlyonecolorbuffer isallowed). Thethirdparameteristhesametexturetargetthatwasusedin gl.texImage2D,andthefourthisthetextureobject.Thelastparameter isthemipmaplevel;itwillusuallybezero,whichmeansrendering tothetextureimageitselfratherthantooneofitsmipmapimages. Withthissetup,youarereadytobindtheframebufferand drawtothetexture.Afterdrawingthetexture,call gl.bindFramebuffer(gl.FRAMEBUFFER,null); tostartdrawingagaintothedefaultframebuffer.Atthatpoint,thetextureisreadyforuse insubsequentrenderingoperations.Thetextureobject canbeboundtoatextureunit,andasampler2Dvariablecanbeused intheshaderprogramtoreadfromthetexture. Youareverylikelytouse differentshaderprogramsfordrawingtothetextureanddrawingtothescreen. Recallthatthefunctiongl.useProgram()isusedtospecifytheshaderprogram. Inthesampleprogram, thetexturecanbeanimated.Duringtheanimation,anewimageisdrawntothetexture foreachframeoftheanimation.Thetextureimageis2D,sothedepthtestisdisabled whilerenderingit.Thismeansthattheframebufferdoesn'tneedadepthbuffer. Inoutlineform,therenderingfunctioninthesampleprogramhastheform functiondraw(){ /*Drawthe2Dimageintoatextureattachedtoaframebuffer.*/ gl.bindFramebuffer(gl.FRAMEBUFFER,framebuffer); gl.useProgram(prog_texture);//shaderprogramforthetexture gl.clearColor(1,1,1,1); gl.clear(gl.COLOR_BUFFER_BIT);//clearthetexturetowhite gl.enable(gl.BLEND);//Usetransparencywhiledrawing2Dimage. gl.disable(gl.DEPTH_TEST);//framebufferdoesn'tevenhaveadepthbuffer! gl.viewport(0,0,512,512);//Viewportisnotsetautomatically! . .//drawthetextureimage,whichchangesineachframe . gl.disable(gl.BLEND); /*Nowdrawthemainscene,whichis3D,usingthetexture.*/ gl.bindFramebuffer(gl.FRAMEBUFFER,null);//Drawtodefaultframebuffer. gl.useProgram(prog);//shaderprogramfortheon-screenimage gl.clearColor(0,0,0,1); gl.clear(gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT); gl.enable(gl.DEPTH_TEST); gl.viewport(0,0,canvas.width,canvas.height);//Resettheviewport! . .//drawthescene . } Notethattheviewporthastobesetbyhandwhendrawing toanon-defaultframebuffer.Itthenhastoberesetwhendrawingthe on-screenimagetomatchthesizeofthecanvas wheretheon-screenimageisrendered.Ishouldalsonotethatonlyonetexture objectisusedinthisprogram,soitcanbeboundonceandforall duringinitialization.Inthiscase,itisnotnecessarytocall gl.bindTexture()inthedraw()function. Thisexamplecouldbeimplementedwithoutusingaframebuffer,aswasdone fortheexampleinSubsection 4.3.6.Inthatexample,the textureimagewasdrawntothedefaultframebuffer,thencopiedtothe textureobject.However, theversioninthissectionismoreefficientbecauseitdoesnotneedto copytheimageafterrenderingit. 7.4.3 Renderbuffers Itisoftenconvenienttousememoryfromatextureobjectasthecolorbuffer foraframebuffer.However,sometimesitsmoreappropriatetocreateseparatememory forthebuffer,notassociatedwithanytexture.Forthedepthbuffer,thatisthe typicalcase.Forsuchcases,thememorycanbecreatedasarenderbuffer. Arenderbufferrepresentsmemorythatcanbeattachedtoaframebufferforuseas acolorbuffer,depthbuffer,orstencilbuffer.Touseone,youneedtocreatethe renderbufferandallocatememoryforit.Memoryisallocatedusingthefunction gl.renderbufferStorage().Therenderbuffermustbeboundbycalling gl.bindRenderbuffer()beforeallocatingthememory.Hereisanexample thatcreatesarenderbufferforuseasadepthbuffer: letdepthBuffer=gl.createRenderbuffer(); gl.bindRenderbuffer(gl.RENDERBUFFER,depthBuffer); gl.renderbufferStorage(gl.RENDERBUFFER,gl.DEPTH_COMPONENT16,512,512); Thefirstparametertobothgl.bindRenderbufferandgl.renderbufferStorage mustbegl.RENDERBUFFER.Thesecondparametertogl.renderbufferStorage specifieshowtherenderbufferwillbeused.Thevaluegl.DEPTH_COMPONENT16 isforadepthbufferwith16bitsforeachpixel.(SixteenbitsistheonlyoptioninWebGL 1.0.) ForacolorbufferholdingRGBAcolorswithfoureight-bitvaluesperpixel,thesecondparameterwouldbegl.RGBA8. Othervaluesarepossible,suchasgl.RGB565,whichuses16bitsperpixelwith 5bitsfortheredcolorchannel,6bitsforgreen,and5bitsforblue.Fora stencilbuffer,thevaluewouldbegl.STENCIL_INDEX8. Thelasttwoparameterstogl.renderbufferStoragearethewidthandheight ofthebuffer. Thefunctiongl.framebufferRenderbuffer()isusedtoattacharenderbufffer tobeusedasoneofthebuffersinaframebuffer.Ittakestheform gl.framebufferRenderbuffer(gl.FRAMEBUFFER,gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER,renderbuffer); Theframebuffermustbeboundbycallinggl.bindFramebufferbefore thisfunctioniscalled.Thefirstandthirdparameterstogl.framebufferRenderbuffer mustbeasshown.Thelastparameteristherenderbuffer.Thesecondparamter specifieshowtherenderbufferwillbeused.Itcanbe,forexample, gl.COLOR_ATTACHMENT0,gl.DEPTH_ATTACHMENT,or gl.STENCIL_ATTACHMENT. 7.4.4 DynamicCubemapTextures Torendera3Dscenetoaframebuffer,weneedbothacolorbufferand adepthbuffer.Anexamplecanbefoundinthesample programwebgl/cube-camera.html.Thisexampleuses render-to-textureforacubemaptexture.Thecubemaptexture isthenusedasanenvironmentmap onareflectivesurface.Inadditiontotheenvironmentmap,theprogram usesanothercubemaptextureforaskybox.(See Subsection 6.3.5.)Here'sanimagefromtheprogram: Theenvironmentinthiscaseincludesthebackgroundskybox,butalsoincludes severalcoloredcubesthatarenotpartoftheskyboxtexture.Thereflective sphereinthecenteroftheimagereflectsthecubesaswellastheskybox,which meansthattheenvironmentmaptexturecan'tbethesameastheskyboxtexture—it hastoincludethecubes.Furthermore,thescenecanbeanimatedandthecubescanmove. Thereflectioninthespherehastochangeasthecubesmove.Thismeansthat theenvironmentmaptexturehastoberecreatedineachframe.Forthat,wecan useaframebuffertorendertothecubemaptexture. Acubemaptextureconsistsofsiximages,oneeachforthepositiveandnegative directionofthex,y,andzaxes.Eachimageisassociated withadifferenttexturetarget(similartogl.TEXTURE_2D).Torender acubemap,weneedtoallocatestorageforallsixsides.Here'sthecodefromthe sampleprogram: cubemapTargets=[ //storetexturetargetsinanarrayforconvenience gl.TEXTURE_CUBE_MAP_POSITIVE_X,gl.TEXTURE_CUBE_MAP_NEGATIVE_X, gl.TEXTURE_CUBE_MAP_POSITIVE_Y,gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, gl.TEXTURE_CUBE_MAP_POSITIVE_Z,gl.TEXTURE_CUBE_MAP_NEGATIVE_Z ]; dynamicCubemap=gl.createTexture();//Createthetextureobject. gl.bindTexture(gl.TEXTURE_CUBE_MAP,dynamicCubemap);//binditasacubemap for(i=0;i<6;i++){ gl.texImage2D(cubemapTargets[i],0,gl.RGBA,512,512, 0,gl.RGBA,gl.UNSIGNED_BYTE,null); } Wealsoneedtocreateaframebuffer,aswellasarenderbufferforuseasadepthbuffer, andweneedtoattachthedepthbuffertotheframebuffer.Thesameframebuffer canbeusedtorenderallsiximagesforthetexture,changingthecolorbuffer attachmentoftheframebufferasneeded.Toattachoneofthesixcubemapimages asthecolorbuffer,wejustspecifythecorrespondingcubemaptexturetarget inthecalltogl.framebufferTexture2D().Forexample,thecommand gl.framebufferTexture2D(gl.FRAMEBUFFER,gl.COLOR_ATTACHMENT0, gl.TEXTURE_CUBE_MAP_NEGATIVE_Z,dynamicCubemap,0); attachesthenegativezimagefromthetextureobjectdynamicCubemaptobeused asthecolorbufferinthecurrentlyboundframebuffer. Afterthesixtextureimageshavebeenrendered,thecubemaptextureis readytobeused.Asidefromthefactthatsix3Dimagesarerenderedinsteadof one2Dimage,thisisallverysimilartotherender-to-textureexamplefrom earlierinthissection. Thequestionremainsofhowtorenderthesiximagesofthescenethatareneededforthecubemaptexture. Tomakeanenvironmentmapforareflectiveobject,wewantimagesoftheenvironmentthat surroundsthatobject.Theimagescanbemadewithacameraplacedatthecenter oftheobject.Thebasicideaistopointthecamerainthesixdirectionsofthe positiveandnegativecoordinateaxesandsnapapictureineachdirection, butit'strickytogetthedetailscorrect.(Andnotethatwhenweapplytheresult toapointonthesurface,wewillonlyhaveanapproximationofthecorrect reflection.Forageometricallycorrectreflectionatthepoint,wewouldneedthe viewfromthatverypoint,nottheviewfromthecenterofthe object,butwecan'trealisticallymakeadifferentenvironmentmapforeach pointonthesurface.TheapproximationwilllookOKaslongasotherobjects inthescenearenottooclosetothereflectivesurface.) A"camera"reallymeansaprojectiontransformationanda viewingtransformation.Theprojectionneedsaninety-degree fieldofview,tocoveronesideofthecube,anditsaspectratio willbe 1,sincethesidesofthecubearesquares.Wecanmaketheprojection matrixwithaglMatrixcommandsuchas mat4.projection(projection,Math.PI/2,1,1,100); wherethelasttwoparameters,thenearandfarclippingdistances,shouldbechosento includealltheobjectsinthescene.Ifweapplynoviewingtransformation,thecamera willbeattheorigin,pointinginthedirectionofthenegativez-axis.Ifthe reflectiveobjectisattheorigin,asitisinthesampleprogram,wecanusethe camerawithnoviewingtransformationtotakethenegative-zimageforthecubemaptexture. But,becauseofthe detailsofhowtheimagesmustbestoredforcubemaptextures,itturnsoutthatwe needtoapplyonetransformation.Let'slookatthelayoutofimagesfor acubemaptexture: Thesixsidesofthecubeareshowninblack,asifthesidesofthecubehave beenopenedupandlaidoutflat.Eachsideismarkedwiththecorrespondingcoordinate axisdirection.Duplicatecopiesoftheplusandminusysidesareshowningray, toshowhowthosesidesattachtothenegativezside.Theimagesthatwemakefor thecubemapmustfittogetherinthesamewayasthesidesinthislayout.However, thesidesinthelayoutareviewedfromtheoutsideofthecube,while thecamerawillbetakingapicturefromtheinsideofthecube.Togetthe correctview,weneedtofilpthepicturefromthecamerahorizontally.Aftersome experimentation,IfoundthatIalsoneedtoflipitvertically,perhapsbecause webimagesarestoredupsidedownwithrespecttotheOpenGLconvention.Wecan dobothflipswithascalingtransformationby(−1,−1,1). Puttingthistogether,thecodeformakingthecubemap'snegativezimageis gl.bindFramebuffer(gl.FRAMEBUFFER,framebuffer);//Drawtooffscreenbuffer. gl.viewport(0,0,512,512);//Matchsizeofthetextureimages. /*Setupprojectionandmodelviewmatricesforthevirtualcamera mat4.perspective(projection,Math.PI/2,1,1,100); mat4.identity(modelview); mat4.scale(modelview,modelview,[-1,-1,1]); /*Attachthecubemapnegativezimageasthecolorbufferintheframebuffer, and"takethepicture"byrenderingtheimage.*/ gl.framebufferTexture2D(gl.FRAMEBUFFER,gl.COLOR_ATTACHMENT0, gl.TEXTURE_CUBE_MAP_NEGATIVE_Z,dynamicCubemap,0); renderSkyboxAndCubes(); Thefunctioninthelastlinerendersthescene,exceptforthecentralreflective objectitself,andisresponsibleforsendingtheprojectionandmodelviewmatrices totheshaderprograms. Fortheotherfiveimages,weneedtoaimthecamerainadifferentdirection beforetakingthepicture.Thatcanbedonebyaddinganappropriaterotation totheviewingtransformation.Forexample,forthepositiveximage,weneedto rotatethecameraby−90degreesaboutthey-axis.Asaviewingtransform, weneedthecommand mat4.rotateY(modelview,modelview,Math.PI/2); Itmightbeeasiertothinkofthisasamodelingtransformationthat rotatesthepositivexsideofthecubeintoviewinfrontofthecamera. Inthesampleprogram, thesixcubemapimagesarecreatedinthefunctioncreateDynamicCubemap(). Readthesourcecodeofthatfunctionforthefulldetails. Thisdynamiccubemap programisaniceexample,sinceitmakesuseofsomanyoftheconceptsand techniquesthatwehavecovered.Takeaminutetothinkabouteverythingthatis goingoninthisdemoversionofthesampleprogram,andhowitwasallimplemented. (Youmightalsonoticethattheteapotdoesnotreflectanypartofitself.) [PreviousSection| NextSection| ChapterIndex| MainIndex]
延伸文章資訊
- 1WebGL中图片多级处理(FrameBuffer) - 纸异兽- 博客园
FBO(Frame Buffer Object)是被推荐用于将数据渲染到纹理对象的扩展。 FrameBuffer就像是一个webgl显示容器一样,平时我们使用gl.drawArrays或者gl.
- 2How to work with framebuffers in webgl? - Stack Overflow
A fragment shader outputs to either the canvas or the attachments in a framebuffer. To be more te...
- 3JavaScript webgl framebuffer object | Develop Paper
By default, the final drawing result of webgl is stored in the color buffer, and the frame buffer...
- 4WebGLRenderingContext.bindFramebuffer() - Web APIs | MDN
Binding a frame buffer. var canvas = document.getElementById('canvas'); var gl = canvas.getContex...
- 5WebGL Framebuffers
This article is meant to try to give you a mental image of what a framebuffer is in WebGL. Frameb...