Learn OpenGL. Lesson 4.8 - Advanced GLSL
文章推薦指數: 80 %
A simple example of resizing a point is setting the size of the ... Another interesting variable in the fragment shader is gl_FrontFacing . LearnOpenGL.Lesson4.8-AdvancedGLSLFromthesandboxAdvancedGLSL Thislessonwillnotshowyounewadvancedtoolsthatsignificantlyimprovethevisualqualityofthescene.Inthistutorial,wewillgooverthemoreorlessinterestingaspectsofGLSLandtouchonsomegoodtricksthatcanhelpyouwithyouraspirations.Basically,theknowledgeandtoolsthatmakeyourlifeeasierwhencreatingOpenGLapplicationsinconjunctionwithGLSL. Wewilldiscusssomeinterestingbuilt-invariables,newapproachestotheorganizationofinput-outputshadersandaveryusefultool-theobjectoftheuniformbuffer.ContentPart1.GettingStartedOpenglWindowcreationHellowindowHellotriangleShadersTexturesTransformationsCoordinatesystemsCamera Part2.BasiclightingColorsLightingbasicsMaterialsTexturemapsSourcesoflightMultipleLightingSources Part3.Download3DmodelsAssimpLibraryMeshPolygonClassModelClassModel Part4.AdvancedOpenGLFeaturesDepthtestStenciltestColormixingClippingfacesFramebufferCubiccardsAdvanceddatahandlingGLSLbuilt-invariables Shadersareself-sufficient,ifweneeddatafromsomeothersource,wewillhavetotransferthemtotheshader.Welearnedhowtodothiswithvertexattributes,uniforms,andsamplers.However,thereareseveralmorevariablesdefinedinGLSLwiththegl_prefix,whichgivesusadditionalopportunitiestoreadand/orwritedata.Wehavealreadyseentworepresentativesresultingvectors:gl_Positionofthevertexshaderandgl_FragCoordfragmentshader. WewilldiscusssomeinterestingGLSLbuilt-invariablesforbothinputandoutput,andexplainwhatarethebenefitsofthem.Inotethatwewillnotdiscussallthebuilt-invariablesinGLSL,soifyouwanttoseeallthebuilt-invariables,youcandothisonthecorrespondingOpenGLpage.Vertexshadervariables Wehavealreadyworkedwiththegl_Positionvariable,whichistheoutputvectorofthevertexshaderthatdefinesthepositionvectorintheclippingspace.Settingthegl_Positionvalueisaprerequisitefordisplayingsomethingonthescreen.Nothingnewforus.gl_PointSize OneoftheprocessedprimitivesthatwecanchooseisGL_POINTS.Inthiscase,eachvertexisaprimitiveandistreatedasapoint.YoucanalsosetthesizeoftheprocessedpointsusingtheglPointSizefunction.Butwecanalsochangethisvaluethroughtheshader. Intheoutputfloatofthegl_PointSizevariabledeclaredinGLSL,youcansettheheightandwidthofthepixelsinpixels.Bydescribingthesizeofapointinavertexshader,youcaninfluencethisvalueforeachvertex. Bydefault,resizingapointinthevertexshaderisdisabled,butifyouwant,youcancocktheOpenGLflagGL_PROGRAM_POINT_SIZE:glEnable(GL_PROGRAM_POINT_SIZE); Asimpleexampleofresizingapointissettingthesizeofthepointtothevalueofthecomponentzoftheclippingspace,which,inturn,isequaltothedistancefromthevertextotheobserver.Thesizeofthepointwillincrease,thefurtherwearefromthetop.voidmain() { gl_Position=projection*view*model*vec4(aPos,1.0); gl_PointSize=gl_Position.z; } Asaresult,thefartherwearefromthepoints,thelargertheyaredisplayed. Resizingapointforeachvertexwillbeusefulfortechniquessuchasparticlegeneration.gl_VertexID Thevariablesgl_Positionandgl_PointSizeareoutputvariables,becausetheirvaluesarereadastheoutputofthefragmentshaderstage,andbywritingwecaninfluencethem.Thevertexshaderalsoprovidestheinputvariablegl_VertexID,fromwhichonlyreadingispossible. Theintegervariablegl_VertexIDcontainstheidentifierofthevertextobedrawn.Duringindexrendering(usingglDrawElements),thisvariablecontainsthecurrentindexofthevertexbeingdrawn.Duringrenderingwithoutindexes(viaglDrawArrays)thevariablecontainsthenumberofverticesprocessedatthemomentsincetherenderwascalled. Althoughthisisnotreallynecessarynow,itisusefultoknowaboutthepresenceofsuchavariable.FragmentShaderVariables Insidethefragmentshader,wealsohaveaccesstosomeinterestingvariables.GLSLprovidesuswithtwoinputvariablesgl_FragCoordandgl_FrontFacing.gl_FragCoord Wehavealreadyseengl_FragCoordacoupleoftimeswhilediscussingdepthtesting,asThezcomponentofthegl_FragCoordvectorisequaltothedepthofaparticularfragment.However,wecanalsousethexandycomponentsforsomeeffects. Thexandycomponentsofthegl_FragCoordvariablearethecoordinatesofthefragmentinthecoordinatesystemofthewindow,originatingfromthelowerleftcornerofthewindow.Wespecifiedawindowsizeof800x600usingglViewport,sothefragmentcoordinatesinthewindowcoordinatesystemwillbebetween0-800inxandarangeof0-600iny. Usingthefragmentshader,wecancalculatevariouscolorvaluesbasedonthescreencoordinatesofthefragment.Commonuseofthegl_FragCoordvariable-Comparethevisibleresultofthecalculationsofvariousfragments,asisusuallydoneintechnicaldemos.Forexample,wecandividethescreenintotwoparts,therenderingpartonthelefthalfofthescreen,andtheotherpartontherighthalfofthescreen.Thefollowingisanexampleofafragmentshaderthatdisplaysvariouscolorsbasedonscreencoordinates.voidmain() { if(gl_FragCoord.x<400) FragColor=vec4(1.0,0.0,0.0,1.0); else FragColor=vec4(0.0,1.0,0.0,1.0); } Becausethewidthofthewindowis800,inthecaseofsettingthecoordinatesofthepixellessthan400,itshouldbeontheleftsideofthescreen,andthisgivesusanobjectofadifferentcolor. Nowwecancalculatetwocompletelydifferentresultsinafragmentshaderanddisplayeachonitsownpartofthescreen.Thisisgreatfortestingvariouslightmechanics.gl_FrontFacing Anotherinterestingvariableinthefragmentshaderisgl_FrontFacing.Inthelesson,faceclipping-wementionedthatOpenGLcandetermineifafaceisfaceintheorderoftraversalofvertices.Ifwedonotuseedgeclipping(byactivatingtheGL_FACE_CULLflag),thenthegl_FrontFacingvariabletellsuswhetherthecurrentfragmentisthefrontornon-frontpart.Wecancalculatedifferentcolorsforthefrontpartforexample. Thebooleanvariablegl_FrontFacingissettotrueifthefragmentisontheface,otherwisefalse.Forexample,wecancreateacubewithdifferenttexturesinsideandout.#version330core outvec4FragColor; invec2TexCoords; uniformsampler2DfrontTexture; uniformsampler2DbackTexture; voidmain() { if(gl_FrontFacing) FragColor=texture(frontTexture,TexCoords); else FragColor=texture(backTexture,TexCoords); } Ifwelookinsidethecontainer,wewillseethatadifferenttextureisusedthere. Inotethatifyouactivateclippingoffaces,thenyouwillnotseeanyfacesinsidethecontainer,sousinggl_FronFacingwillbeuseless.gl_FragDepthgl_FragCoordisaninputvariablethatallowsustoreadthecoordinatesinthewindowcoordinatesystemandgetthedepthvalueofthecurrentfragment,butthisvariableisread-only.Wecannotchangethecoordinatesofthefragmentinthecoordinatesystemofthewindow,butwecansetthevalueofthedepthofthefragment.GLSLprovidesuswithanoutputvariable-gl_FragDepth,usingwhichwecansetthefragmentdepthvalueinsidetheshader. Settingthedepthvalueissimple-youjustneedtowriteafloatvaluefrom0.0to1.0inthegl_FragDepthvariable.gl_FragDepth=0.0;//теперьзначениеглубиныэтогофрагментаравнонулю Iftheshaderdoesnotwritethevalueingl_FragDepth,thenthevalueforthisvariablewillbeautomaticallytakenfromgl_FragCoord.z. However,settingthedepthvalueyourselfhasasignificantdrawback,asOpenGLdisablesallearlydepthchecks(asdiscussedinthedepthtest)assoonasanentryingl_FragDepthappearsinthefragmentshader.ThisisduetothefactthatOpenGLcannotknowwhatdepthvaluethefragmentwillhavebeforestartingthefragmentshader,becausethefragmentshadercouldcompletelychangethisvalue. Writingingl_FragDepth,стоитподуматьовозможномпадениипроизводительности.Однако,начинаясверсииOpenGL4.2мыможемнайтикомпромисс,переобъявляяпеременнуюgl_FragDepthвначалефрагментногошейдерасусловиемглубины.layout(depth_)outfloatgl_FragDepth; Параметрconditionможетприниматьследующиезначения:УсловиеОписаниеanyЗначениепоумолчанию.Ранняяпроверкаглубиныотключена–выпотеряетевпроизводительностиgreaterВыможетеустановитьзначениеглубинытолькобольшечемgl_FragCoord.zlessВыможетеустановитьзначениеглубинытолькоменьшечемgl_FragCoord.zunchangedВgl_FragDepthвызаписываетезначениеравноеgl_FragCoord.zByspecifyinggreaterorlessasaconditionfordepth,OpenGLmaymaketheassumptionthatyouwillonlywritevaluesmoreorlessthanthedepthvaluesofthefragment.Inthisscenario,OpenGLcanstillperformanearlytestofthedepthvalueifthevalueislessthanthefragmentdepthvalue. Intheexamplebelow,weincreasethedepthvalueinthefragmentshader,butalsowanttokeeptheearlydepthcheckinthefragmentshader.#version420core//обратитевниманиенаверсиюOpenGL outvec4FragColor; layout(depth_greater)outfloatgl_FragDepth; voidmain() { FragColor=vec4(1.0); gl_FragDepth=gl_FragCoord.z+0.1; } ThispropertyisonlyavailableinOpenGL4.2andhigher.Interfaceblocks Untilnow,wheneverwewantedtotransferdatafromavertexshadertoafragmentshader,wedeclaredseveralcorrespondinginput/outputvariables.Thismethodistheeasiesttotransferdatafromoneshadertoanother.Asapplicationsbecomemorecomplex,youmaywanttopassmorethanafewvariables,whichmayincludearraysand/orstructures. Tohelpusorganizevariables,GLSLprovidessuchathingasinterfaceblocks,whichallowsyoutogroupvariablestogether.Declaringsuchinterfaceblocksisverysimilartodeclaringastructure,withtheexceptionofusingtheinandoutkeywordsbasedontheuseoftheblock(inputoroutput).#version330core layout(location=0)invec3aPos; layout(location=1)invec2aTexCoords; uniformmat4model; uniformmat4view; uniformmat4projection; outVS_OUT { vec2TexCoords; }vs_out; voidmain() { gl_Position=projection*view*model*vec4(aPos,1.0); vs_out.TexCoords=aTexCoords; } Hereweannouncedthevs_outinterfaceunit,groupingalloutputvariablestogether,whichwillbesenttothenextshader.Thisisatrivialexample,butjustimaginehowthiscanhelpyouorganizeyourI/Oinshaders.Thiswillalsobeusefulinthenextlessonongeometricshaders,whenyouneedtocombinetheinput/outputofshadersintoarrays. Thenweneedtodeclaretheinputinterfaceblockinthenextshader-fragment.Theblockname(VS_OUT)shouldbethesame,buttheinstancename(vs_outusedinthevertexshader)canbeanything,themainthingistoavoidnameconfusion(forexample,naminganinstancecontainingvs_outinput)#version330core outvec4FragColor; inVS_OUT { vec2TexCoords; }fs_in; uniformsampler2Dtexture; voidmain() { FragColor=texture(texture,fs_in.TexCoords); } Sincethenamesoftheinterfaceunitsarethesame,theircorrespondinginput-outputiscombinedtogether.Thisisanotherusefulfeaturethathelpsorganizeyourcodeandprovesusefulwhenmovingbetweenspecificstepsasageometricshader.Uniformbuffer WehavebeenusingOpenGLforquitesometimeandlearnedsomegoodtricks,butalsogotafewinconveniences.Forexample,whenweconstantlyusemorethanoneshader,wehavetosetuniformvariables,whilemostofthemarethesameineachshader-whydowehavetodothisagain? OpenGLprovidesuswithatoolcalledauniformbufferthatallowsustodeclareasetofglobaluniformvariablesthatremainthesameineveryshader.Whenusingtheuniformbuffer,weneedtosetthenecessaryuniformvariablesonlyonce.Butwestillhavetotakecareofuniquevariablesforaparticularshader.However,toconfiguretheuniformbufferobject,wewillhavetosweatabit. Sincetheuniformbufferisabuffer,likeanyotherbuffer,wecancreateitthroughtheglGenBuffersfunction,bindit,bindittotheGL_UNIFORMS_BUFFERtarget,andputallthenecessaryuniformvariabledatathere.Therearecertainrulesforplacingdatainauniformbuffer-wewillreturntothislater.First,weputourprojectionandviewmatricesintheso-calleduniformblockinthevertexshader.#version330core layout(location=0)invec3aPos; layout(std140)uniformMatrices { mat4projection; mat4view; }; uniformmat4model; voidmain() { gl_Position=projection*view*model*vec4(aPos,1.0); } Inmostofourexamples,wespecifiedprojectionandviewmatricesineachrenderingiterationforeachshaderused.Thisisanidealexampletodemonstratetheusefulnessofauniformbuffer,asnowweneedtoaskthemonlyonce.Weannouncedandnamedtheuniformblock-Matrices,whichstorestwo4x4matrices.Variablesinablockcanbeaccesseddirectlywithoutspecifyingablockprefix.Thenweputthevaluesofthesematricesinabuffersomewhereinthecode,andeachshaderthatdeclaresthisuniformblockhasaccesstothematrices. Nowyouprobablythinkwhattheexpressionstd140means.Itsaysthattheuniformblockusesaspecialmethodofplacingitscontentsinmemory;thisexpressiondefinesthelayout(layout)oftheuniformblock.Uniformblocklayout Thecontentsoftheuniformblockarestoredinabufferobject,whichisessentiallynothingmorethanareservedportionofmemory.Sincethispieceofmemorydoesnotcontaininformationwhattypeofdataitstores,weneedtotellOpenGLwhichpieceofmemorycorrespondstoeachoftheuniformvariablesintheshader. Imaginethefollowinguniformblockinashader:layout(std140)uniformExampleBlock { floatvalue; vec3vector; mat4matrix; floatvalues[3]; boolboolean; intinteger; }; Wewanttoknowthesize(inbytes)andtheoffset(fromthestartoftheblock)foreachofthesevariablessothatwecanplacetheminthebufferintheappropriateorder.ThesizeofeachelementisexplicitlydefinedinOpenGLandisdirectlyrelatedtoC++types;vectorsandmatricesarelargearraysoffloatingpointnumbers.WhatOpenGLdoesnotexplicitlydefineisthespacebetweenthevariables.Thisallowsthehardwaretoplacethevariablesasitseesfit.Forexample,someinstanceshostvec3nexttoafloat.Noteveryonecanhandlethisandthereforealignvec3toanarrayoffourfloatsbeforeaddingafloat.Wonderfulproperty,butinconvenientforus. GLSLbydefaultusestheso-calledsharedmarkup(layout)foruniformbuffermemory.Sharedmarkupiscalledbecausetheoffsetsdefinedbythehardwarearesharedbyseveralprograms.Usingsharedmarkup,GLSLhastherighttomoveuniformvariablesforoptimization,providedthattheorderofthevariablesdoesnotchange.Becausewedon’tknowatwhatoffseteachuniformvariableis,andwedon’tknowhowtopreciselyfillouruniformbuffer.WecanrequestthisinformationwithfunctionslikeglGetUniformIndices,butthisisbeyondthescopeofourlesson. Whilethesharedmarkupprovidesuswithsomeoptimizationofthememoryusedup,weneedtorequestanoffsetfromeachuniformvariable,whichturnsintoalotofwork.However,itiscommonpracticenottousesharedmarkup,buttousestd140markup.Std140explicitlysetsthememorylayoutforeachtypeofvariable,settingtheappropriateoffsetaccordingtospecialrules.Becausemixingisexplicitlyindicated,wecanmanuallyfigureoutthebiasforeachvariable. Eachvariablecorrespondstoabasicalignmentequaltothesizeoftheoccupiedvariablememory(includingpaddingbytes)insidetheuniformblock-thevalueofthisbasicalignmentiscalculatedaccordingtomarkuprulesstd140.Thenforeachvariable,wecalculatethealignedoffsetinbytesfromthestartoftheblock.Thealignedbyteoffsetofthevariablemustbeamultipleofthebasealignment. YoucanfindtheexactlayoutrulesintheOpenGLUniformBufferspecificationhere.Butwewilllistthegeneralrulesbelow.EachtypeofvariableinGLSL,suchasint,float,andbool,isdefinedasfour-byte,eachfour-byteobjectisdenotedasN.AtypePlacement(markup)ruleScalar(int,bool)EachscalartypehasabasicalignmentNVector2Nor4N.Thismeansthatvec3hasabasicalignmentof4NArrayofvectorsorscalarsEachelementhasabasicalignmentequaltovec4alignmentMatricesTheyarestoredaslargearraysofcolumnsofvectors,whereeachvectorhasabasicalignmentvec4StructureItisequaltothecalculatedsizeofallelements,inaccordancewiththepreviousrule,butsupplementedbyafactorofsizevec4LikemostOpenGLspecifications,it’seasiertounderstandwithanexample.Wewilllookatthepreviouslypresenteduniformblock-ExampleBlockandcalculatethealignedoffsetofeachmemberusingthestd140markup.layout(std140)uniformExampleBlock { //базовоевыравнивание//выровненноесмещение floatvalue;//4//0 vec3vector;//16//16(должнобытькратно16,потомузаменяем4на16) mat4matrix;//16//32(column0) //16//48(column1) //16//64(column2) //16//80(column3) floatvalues[3];//16//96(values[0]) //16//112(values[1]) //16//128(values[2]) boolboolean;//4//144 intinteger;//4//148 }; Asanexercise,trytocalculatetheoffsetvalueyourselfandcomparewiththistable.Withcalculatedoffsetvalues,basedonstd140markuprules,wecanfillthebufferwithdataateachoffsetusingfunctionslikeglBufferSubData.Std140isnotthemostefficient,butitguaranteesusthatthemarkupmemorywillremainthesameforeveryprogramthatdeclaresthisuniformblock. Addingthelayoutexpression(std140)beforedefiningtheuniformblock,wetellOpenGLthatthisblockusesthestd140markup.Therearetwomorelayoutsthatwecanusethatrequireustorequesteachoffsetbeforefillingthebuffer.Wehavealreadyseensharedmarkupinthecase,andtheremainingmarkupiscompacted.Whenusingcompactedmarkup,thereisnoguaranteethatthemarkupwillremainthesamebetweenprograms(notshared),asthisallowsthecompilertooptimizeuniformvariablesbythrowingoutindividualuniformvariables,whichcanleadtodifferencesindifferentshaders.UsingUniformBuffers Wediscusseddefininguniformblocksinshadersandspecifyingamemorylayout,butwehavenotyetdiscussedhowtousethem. Thefirstthingweneedisauniformbuffer,whichhasalreadybeendonewithglGenBuffers.Havingcreatedthebufferobject,webindittoGL_UNIFORM_BUFFERandallocatetherequiredamountofmemorybycallingglBufferData.unsignedintuboExampleBlock; glGenBuffers(1,&uboExampleBlock); glBindBuffer(GL_UNIFORM_BUFFER,uboExampleBlock); glBufferData(GL_UNIFORM_BUFFER,152,NULL,GL_STATIC_DRAW);//выделяем150байтпамяти glBindBuffer(GL_UNIFORM_BUFFER,0); Inthecasewhenwewanttoupdateorpastedataintothebuffer,webindtouboExampleBlockanduseglBufferSubDatatoupdatethememory.Itisenoughforustoupdatethisbufferonce,andallshadersthatusethisbufferwillusetheupdateddata.ButhowdoesOpenGLknowwhichuniformbufferscorrespondtowhichuniformblocks? InthecontextofOpenGL,thereareanumberofanchorpointsthatdeterminewherewecansnaptheuniformbuffer.Havingcreatedtheuniformbuffer,weconnectittooneoftheanchorpoints,aswellasconnecttheuniformblocktothesamepoint,essentiallylinkingthemtogether.Thediagrambelowillustratesthis: Asyoucansee,wecanbindseveraluniformbufferstodifferentanchorpoints.SinceshaderAandshaderBhaveauniformblockconnectedtothesameanchorpoint0,theuboMatricesinformationintheuniformblocksbecomescommontothem;requirethattheseshadersaredefinedthesameUniformblockMatricesare. Tobindtheuniformblocktotheanchorpoint,weneedtocallglUnifomBlockBinding,whichtakestheidentifieroftheshaderprogramobjectasthefirstargument,thesecondastheindexoftheuniformblock,andthethirdastheanchorpoint(towhichweattach).Uniformblockindex-theindexofthelocationofaspecificblockintheshader.ThisinformationcanbeobtainedbycallingglGetUnifromBlocIndex,принимающей,вкачествеаргументовидентификаторобъекташейдернойпрограммыиимяюниформ-блока.Мыможемпривязатьюниформ-блокLightsкакнарис.3кточкепривязки2следующимобразом.unsignedintlights_index=glGetUniformBlockIndex(shaderA.ID,"Lights"); glUniformBlockBinding(shaderA.ID,lights_index,2); Замечу,чтонампридетсяэтоповторитьдлякаждогошейдера.НачинаясOpenGL4.2сталовозможнымхранитьточкипривязкиюниформ-блокавшейдереявно,добавляядополнительныйспецификаторсхемыразмещения,чтоизбавляетнасотнеобходимостивызыватьglGetUniformBlockIndexиglUniformBlockBinding.Впримеренижемысоединяемточкупривязкииюниформ-блокLightsявно.layout(std140,binding=2)uniformLights{...}; Затеммыдолжныпривязатьюниформ-буферкэтойжеточкепривязкиспомощьюglBindBufferBaseилиglBindBufferRange.glBindBufferBase(GL_UNIFORM_BUFFER,2,uboExampleBlock); //или glBindBufferRange(GL_UNIFORM_BUFFER,2,uboExampleBlock,0,152); TheglBindBufferBasefunctionexpectsasanargumenttheidentifierofthebufferbindingtarget-theindexofthebindingpointandtheuniformbuffer.ThisfunctionconnectsuboExampleBlockandanchorpoint2,andfromnowonpoint2connectsbothobjects.YoucanalsouseglBindBufferRange,whichacceptsadditionaloffsetandsizeparameters-withthisapproach,youcanonlybindthespecifiedrangeoftheuniformbuffertotheanchorpoint.UsingglBindBufferRange,youcanbindmultipleuniformblockstoasingleuniformbuffer. Noweverythingisconfigured,wecanstartaddingdatatotheuniformbuffer.WecouldaddallthedataasasinglearrayorupdatepartsofthebufferwhenweneeditusingglBufferSubData.Toupdatethebooleanuniformvariable,wecouldupdatetheuniformbufferlikethis:glBindBuffer(GL_UNIFORM_BUFFER,uboExampleBlock); intb=true;//булевыпеременныевGLSLпредставленыкакчетырёхбайтовые,поэтомухранимихвкачествецелочисленнойпеременной glBufferSubData(GL_UNIFORM_BUFFER,144,4,&b); glBindBuffer(GL_UNIFORM_BUFFER,0); Thesameoperationisperformedwithalluniformvariablesinsidetheuniformblock,butwithdifferentarguments.Simpleexample Let'sdemonstratethetruebenefitsofauniformbuffer.Ifyoulookattheprevioussectionsofthecode-allthetimeweused3matrices:projection,viewandmodel.Ofallthesematrices,onlythemodelmatrixoftenchanges.Ifwehaveseveralshadersusingasetofthesamematrices,itwillprobablybemoreprofitableforustousetheuniformbufferobject. Wewillstoretheprojectionandviewmatricesintheuniformblock-Matrices.Wewillnotstorethemodelmatrixhere,asitchangesquiteofteninshaders,wewouldnotgetmuchbenefitfromsuchactions.#version330core layout(location=0)invec3aPos; layout(std140)uniformMatrices { mat4projection; mat4view; }; uniformmat4model; voidmain() { gl_Position=projection*view*model*vec4(aPos,1.0); } Nothingspecialhappenshereexceptforusingthestd140layout.Inourexample,wewilldraw4cubesusingapersonalshaderforeachcube.Allfourwillusethesamevertexshader,butdifferentfragmentshadersthatdisplaytheirowncolor. First,placethevertexshaderuniformblockattheanchorpoint0.Notethatwemustdothisforeachshader.unsignedintuniformBlockIndexRed=glGetUniformBlockIndex(shaderRed.ID,"Matrices"); unsignedintuniformBlockIndexGreen=glGetUniformBlockIndex(shaderGreen.ID,"Matrices"); unsignedintuniformBlockIndexBlue=glGetUniformBlockIndex(shaderBlue.ID,"Matrices"); unsignedintuniformBlockIndexYellow=glGetUniformBlockIndex(shaderYellow.ID,"Matrices"); glUniformBlockBinding(shaderRed.ID,uniformBlockIndexRed,0); glUniformBlockBinding(shaderGreen.ID,uniformBlockIndexGreen,0); glUniformBlockBinding(shaderBlue.ID,uniformBlockIndexBlue,0); glUniformBlockBinding(shaderYellow.ID,uniformBlockIndexYellow,0); Next,wecreateauniformbufferandalsobindthebuffertopoint0.unsignedintuboMatrices glGenBuffers(1,&uboMatrices); glBindBuffer(GL_UNIFORM_BUFFER,uboMatrices); glBufferData(GL_UNIFORM_BUFFER,2*sizeof(glm::mat4),NULL,GL_STATIC_DRAW); glBindBuffer(GL_UNIFORM_BUFFER,0); glBindBufferRange(GL_UNIFORM_BUFFER,0,uboMatrices,0,2*sizeof(glm::mat4)); First,allocateenoughmemoryforourbuffer,whichisequaltothedoublesizeofglm::mat4.ThesizeoftheGLMmatrixisexactlythesizeofthemat4GLSLmatrix.Thenweconnectacertainrangeofthebuffer,inourcaseitisawholebuffer,withareferencepointof0. Nowallthatremainsistofillthebuffer.Iftheparameteroftheviewingangleoftheprojectionmatrixismadeunchanged(saygoodbyetothepossibilityofzoom),thenthematrixcanbedeterminedonlyonce-andthereforeitisenoughtocopyittothebufferonlyonce.Sincewehavealreadyallocatedenoughmemoryforthebufferobject,wecanuseglBufferSubDatatostoretheprojectionmatricesbeforeweenterthegameloop:glm::mat4projection=glm::perspective(glm::radians(45.0f),(float)width/(float)height,0.1f,100.0f); glBindBuffer(GL_UNIFORM_BUFFER,uboMatrices); glBufferSubData(GL_UNIFORM_BUFFER,0,sizeof(glm::mat4),glm::value_ptr(projection)); glBindBuffer(GL_UNIFORM_BUFFER,0); Hereweputthefirstpartoftheuniformbuffer-theprojectionmatrix.Beforedrawingobjects,ateachiterationofrendering,weupdatethesecondpartofthebuffer-theviewmatrix.glm::mat4view=camera.GetViewMatrix(); glBindBuffer(GL_UNIFORM_BUFFER,uboMatrices); glBufferSubData(GL_UNIFORM_BUFFER,sizeof(glm::mat4),sizeof(glm::mat4),glm::value_ptr(view)); glBindBuffer(GL_UNIFORM_BUFFER,0); That'sallfortheuniformbuffer.EachvertexshadercontainingtheMatricesuniformblockwillnowcontaindatastoredinuboMatrices.Now,ifweweretodraw4cubesusing4differentshaders,theirprojectionandviewmatriceswouldremainthesame.glBindVertexArray(cubeVAO); shaderRed.use(); glm::mat4model; model=glm::translate(model,glm::vec3(-0.75f,0.75f,0.0f)); //переместимвлевуюверхнюючасть shaderRed.setMat4("model",model); glDrawArrays(GL_TRIANGLES,0,36); //...рисуемзелёныйкуб //...рисуемсинийкуб //...рисуемжелтыйкуб Theonlyuniformvariableweneedtosetismodel.Usingtheuniformbufferinthisconfigurationsavesusfrominvokingthesettingofthevalueofuniformvariablesforeachshader.Theresultlookssomethinglikethis: Thankstodifferentshadersandachangeinthemodelmatrix,4cubeshavemovedtotheirpartsofthescreenandhaveadifferentcolor.Thisisarelativelysimplescenariowherewecanuseuniformbuffers,butanyotherlargeprojectwithrenderingcouldhaveoverahundredactiveshaders;thisisexactlythecasewhenuniformbuffersshowthemselvesinalltheirglory. Youcanfindthesourcecodefortheexampleapplicationuniformshere. Uniformbuffershaveseveraladvantagesoversettingindividualuniformvariables.Firstly,settingmultipleuniformvariablesatatimeisfasterthansettingmultipleuniformvariablesmultipletimes.Secondly,ifyouwanttochangethesameuniformvariableinseveralshaders,itismucheasiertochangetheuniformvariableonceintheuniformbuffer.Andthelastadvantageisnotsoobvious,butyoucanusemuchmoreuniformvariablesinshadersusingauniformbuffer.OpenGLhasalimitonthenumberofprocesseddatauniforms.YoucangetthisinformationusingGL_MAX_VETEX_UNIFORM_COMPONENTS.Whenusingtheuniformbuffer,thislimitationissignificantlyhigher.Whenyoureachthelimitofusinguniformvariables(forexample,whendoingskeletalanimation),youcanalwaysuseuniformbuffers.Tags:transferlearnopengl.comopenglopengl3glsl Alsopopularnow: HowtoincorporateanewGoogledesign iBarfromMACG4 AmazonKindleFire-partialRussification Wefinishfullcalendar AbugwithvarioussavesintheMODXRevolutionadminadminareainOpera(Eternaldownload) ExtremetestingofstreamingreplicationPostgreSQL9.1 QtComponentsforthedesktop CAPTCHA2.0-workonbugs ImprovingnotificationsfromHPOpenViewServiceDesk SettingupQtCreatortoworkwithNokiaN9
延伸文章資訊
- 1GLSL-to-HLSL 參考- UWP applications | Microsoft Docs
Sample [datatype.Function]. sampler2D [datatype], Texture2D [datatype] ... gl_FrontFacing. 此變數為bo...
- 2gl_PointSize - OpenGL ES 3.1 Reference Pages - Khronos Group
- 3高级GLSL
片段着色器另一个有意思的输入变量是 gl_FrontFacing 变量。在面剔除教程中,我们提到过OpenGL可以根据顶点绘制顺序弄清楚一个面是正面还是背面。
- 4WebGL/gl-frontfacing.html at main - GitHub
WebGL/sdk/tests/conformance/glsl/variables/gl-frontfacing.html ... <canvas id="example" width="32...
- 5gl_FrontFacing - The Book of Shaders
by Patricio Gonzalez Vivo. Gl_FrontFacing. Declaration / Example. Parameters. Description. See Al...