OpenGL 101: Drawing primitives - points, lines and triangles

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

OpenGL 101: Drawing primitives - points, lines and triangles. Posted on May 13, 2013 by Paul. The code for this post is on GitHub: ... OpenGL101:Drawingprimitives-points,linesandtrianglesPostedonMay13,2013byPaulThecodeforthispostisonGitHub:https://github.com/sol-prog/OpenGL-101.ThisisthesecondarticlefrommyOpenGL101series.Inthefirstarticlewe’veseenhowtoopenawindowforourOpenGLapplicationwiththeGLFWlibraryandhowtocompileandrunthecodeonWindows,OSXandLinux.ItistimetoactuallydrawsomethingusingOpenGL.First,letmementionthatOpenGLisalowlevelAPI,thismeansthatithasnosupportfordrawingcomplexgeometricalobjects.Itistheprogrammer’sjobtocombinethegeometricalprimitivesfromOpenGLincomplexshapesandbodies.ThebasicgeometricalprimitivesthatthecoreOpenGLprofileprovidetousarepoints,linesandtriangles.Forsimplicity,wearegoingtouseonlytwodimensionaldrawingsinthisarticle,butkeepinmindthatOpenGLallowsustorepresentthreedimensionalobjects,moreonthisinafuturearticle.Fornow,let’strytodrawthefourtrianglesfromthenextfigure:Fromageometricalpointofview,atriangleiscompletelydefinedbythepositioninspaceofhisthreecornersorvertices.InOpenGLterminology,avertexcanbeseenasacollectionofattributeslikeposition,color,texturecoordinatesetc…Intheabovefigurewehavefourtrianglesandtwelvevertices.Eachvertexfromourfigurehasapositionattribute,let’signoreforthemomentanyotherpossibleattributelikeacolor.WecanstoretheseverticesinaC++array:1 GLfloatvertices_position[24]={ 2 0.0,0.0, 3 0.5,0.0, 4 0.5,0.5, 5 6 0.0,0.0, 7 0.0,0.5, 8 -0.5,0.5, 9 10 0.0,0.0, 11 -0.5,0.0, 12 -0.5,-0.5, 13 14 0.0,0.0, 15 0.0,-0.5, 16 0.5,-0.5, 17 };Ifyoulookclosely,youmaynoticethatthepointsarewrittencounterclockwise,thisisimportanttokeepinmind.Bydefault,inOpenGL,atrianglewithhisverticesstoredincounterclockwiseorderissaidtobefrontfacing.Whyisthisdistinctionimportant?WecaninstructOpenGLtorenderonlyoneofthetwofacesofatrianglesurface(thefrontortheback);thedefaultistorenderbothfaces.Anotherobservationabouttheabovearrayisthatitstoresonlythex,ycoordinatesforourtriangles,thisisbecausethezcoordinateiszeroforalltwelvevertices.So,howdoesOpenGLdrawsourtriangles,nowthatwehavetheirverticesinanarray?ThefirststepistotransferthecontentoftheabovearrayinaVertexBufferObject.AVertexBufferObject,orVBO,isachunkofmemorymanagedbyOpenGL,basicallyitisapieceofthememoryofyourvideocard.AVBOneedstobecreated,allocatedandfilledwithdata.WecanalsofilltheVBOwithdataintheallocationstep:1 //CreateaVectorBufferObjectthatwillstoretheverticesonvideomemory 2 GLuintvbo; 3 glGenBuffers(1,&vbo); 4 5 //AllocatespaceanduploadthedatafromCPUtoGPU 6 glBindBuffer(GL_ARRAY_BUFFER,vbo); 7 glBufferData(GL_ARRAY_BUFFER,sizeof(vertices_position),vertices_position,GL_STATIC_DRAW);Line3fromtheabovepieceofcodewillcreateahandleforourVBO,usingtheglGenBuffersfunction.Keepinmindthatthisfunctioncancreateanarrayofhandlesifneeded;forourparticularcasewehaveasingleVBOsoonehandlewillsuffice.OnceaVBOiscreated,weneedtobinditinordertomodifyoruseit,thisiswhatline6doeswiththeglBindBufferfunction.ThelastlinewillallocatespacefortheVBOandfillitwiththecontentofourvertices_positionarray.OncewehaveourdatainaVBO,wecansenditthroughtheOpenGLpipeline-anumberofstepsandtransformationsthroughwhichourverticeswillpass;theresultiswritteninaframebuffer.TheglfwSwapBuffers()functionfromGLFWwillreplacethecurrent,visibleframebuffer(thesurfaceofourwindow),withtheresultoftherenderingprocess.AsimplifiedschemeoftheOpenGLpipelineispresentedinthenextfigure:TheabovefigureisasimplifiedmodeloftheentireOpenGLpipeline,itdoesn’tincludeanyoftheoptionalsteps.Fromthepointofviewofabeginner,whatisimportantintheaboveschemearethevertexshaderandthefragmentshader.Ashaderisa,typicallysmall,programthatisexecutedonthevideocard.AshaderiswritteninGLSL,theOpenGLShadingLanguage,alanguagesimilarwithC.AvertexshaderisexecutedforeveryvertexinaVBO,hisroleisto,potentially,applyvarioustransformationsontheverticespositionattributeandpassthroughotherattributeslikecolor,texturecoordinatesetc…Itistheprogrammer’sresponsibilitytowriteavertexshaderforeveryOpenGLbasedapplication.Thenextstep,inoursimplifiedmodeloftheOpenGLpipeline,isthePrimitiveSetupstagethatwillorganizetheverticesintogeometricprimitives(points,linesandtriangles)forthenexttwostages.Intheclippingstage,theprimitivesthatliesoutsideoftheviewingvolumearesplitinsmallerprimitives.ThedefaultviewingvolumeinOpenGLisacube,[-1,+1]x[-1,+1]x[-1,+1],withtheorigininthemiddleofthecurrentviewport(arectangularareaofourwindow,forourcasetheviewporthasthesamedimensionsasourwindow),thepositivexaxispointstotheright,thepositiveyaxispointsupandthepositivezaxispointstowardtheviewer.If,forexample,oneofourtrianglescornerswillbeoutsideoftheviewingvolume,sayat-2.0,0,theclippingstagewillsplitthistriangleinsmallertrianglesandremovethetrianglesthatareoutsideoftheviewingvolume.ThisstageisexecutedbyOpenGL.Intherasterizationstage,theprimitivesthatexittheclippingstagearetransformedintofragments.Whichofthesefragmentswillendasapixelvalueinthefinalframebufferisdecidedinthenextstageofthepipeline.Inthebookrecommendedattheendofthisarticle,itissuggestedtothinkatthesefragmentsaspotentialpixels.Thefragmentshader,alsotheprogrammer’sresponsibility,canpotentiallydeterminethefragmentfinalcolor,discardsomefragments,orusetexturemapping.Afterthefragmentshader,thecolorofafragmentcanpotentiallybefurthermodifiedifthedepthandstenciltestsareenabled,orifblendingwasenabled.Fromoursimplifiedapproachpointofview,weareinterestedinthetwomandatoryshadersofanyOpenGLcoreapplication,thevertexandthefragmentshaders.Inotherwords,weneedtoimplementthesetwoshadersifwewanttodrawsomething.Let’sstartwiththeimplementationofasimplevertexshader:1#version150 2 3invec4position; 4 5voidmain(){ 6 gl_Position=position; 7}Thefirstlineoftheaboveshaderspecifiestheshaderlanguageused,forOpenGL3.2thecorrespondingshaderlanguageversionis1.50.Next,wehaveaglobalvariableoftypevec4thatwillreceivethepositionofavertex,aGLSLvectorthatcanstore4values,bydefaultthisisinitializedwith(0,0,0,1).Asmallnotehere,OpenGLrepresentsinternallyanyvertexpositionasafourvaluevector,wearegoingtotalkmoreaboutthisinafuturearticleaboutMathinOpenGL:).Fromourpointofview,ifwesendatwovaluex,ypositiontotheshader,thelasttwonumberswillremainwiththedefaultvaluesof0and1.Anyshaderneedsamainfunction,liketheonedeclaredinline5.Line6setsthevalueofaninternalvariablefromGLSL,gl_position,tothevalueofourvertexposition.Next,wepresentasimplefragmentshader:1#version150 2 3outvec4out_color; 4 5voidmain(){ 6 out_color=vec4(1.0,1.0,1.0,1.0); 7}Line3ofthefragmentshaderdefinesaglobalvariablethatwillbeusedtosetthecolorofeveryfragmenttowhite,seeline6.Asmentionedinthefirstarticleofthisseries,OpenGLusesinternallyafourdimensionalcolorspace,RGBA,inthisspace1.0,1.0,1.0,1.0representswhiteopaque(notransparency).Formaximumflexibility,wearegoingtosavetheabovetwoshadersintwoseparatefilesvert.shaderandfrag.shader.SomeauthorskeeptheshadersinC-stylestringsintheircode,whilethisavoidstheneedtoreadtheshaderfilesfromthediskitwillalsorequiretherecompilationoftheentireapplicationforanysmallchangeintheshaders.TherealproblemwiththeshadercodestoredasstringintheC++codeisthatwhenyouhaveanerrorinyourshadercodeitcouldbeabitdifficulttofindthecorrespondingerrorline.Anotherdisadvantageisthatyoudon’thavesyntaxhighlightinginwhatyoureditorinterpretsasaconstantstring.First,wearegoingtoneedafunctiontoreadtheshaderfromthedisk,nothingspectacularhere,justopenafileandreadthecontent,alsocheckifthefileisopen,youcanseethecompletefunctionontheGithubrepository:1voidread_shader_src(constchar*fname,std::vector&buffer);Next,wearegoingtocompiletheshader,checktheresultofthecompilationandprintanyerrormessage:1//Compileashader 2GLuintload_and_compile_shader(constchar*fname,GLenumshaderType){ 3 //Loadashaderfromanexternalfile 4 std::vectorbuffer; 5 read_shader_src(fname,buffer); 6 constchar*src=&buffer[0]; 7 8 //Compiletheshader 9 GLuintshader=glCreateShader(shaderType); 10 glShaderSource(shader,1,&src,NULL); 11 glCompileShader(shader); 12 //Checktheresultofthecompilation 13 GLinttest; 14 glGetShaderiv(shader,GL_COMPILE_STATUS,&test); 15 if(!test){ 16 std::cerr<compilation_log(512); 18 glGetShaderInfoLog(shader,compilation_log.size(),NULL,&compilation_log[0]); 19 std::cerr<



請為這篇文章評分?