Lab 2: Points, Primitives and 2D Art
文章推薦指數: 80 %
This week's notes also provide links to the MDN WebGL/WebGL2 ... Choosing GLSL 3.00 ES: make this the first line of all shaders in the shader program. Lab2:Points,Primitivesand2DArt Highlightsofthislab: ThislabisanintroductiontoFundamentalOpenGLFunctions Lab1Follow-up BasicWebGLRenderingFunctions TheRenderingContextObject SettingUpaShaderProgram OpenGLPrimitives Vertices Points Lines Triangles SpecifyingColours SettingUp2DRendering Clearingthewindow TheCamera Assignment: Afterthelablecture,youhaveoneweekto: UseJavascript,GLSLshaders,andbasicWebGLcommandstocreateyourown2Dpicture fromOpenGLprimitives UploadyourresultstoURCoursesandoptionallytoHercules Don'tforgettoconsulttheWebGLspecandOpenGLES2.0manpagesforimportantdetailsonhowWebGLAPI functionsaresupposedtowork. Linkstobothareprovidedonthemainpageforyourconvenience. Thisweek'snotesalsoprovidelinkstotheMDNWebGL/WebGL2documentationforyourconvenience. CaveatEmptor:Ihavefounderrorsinsomesectionsofthemanpageinthepast.Icannotguaranteetheir correctness. SeminarNotes Beforeyoubeginthisseminar,createanewtemplateprojectlikeyoudidinthefirstlab-likethefirstone beforeyouaddedtrianglecode.Youwillcompletetheprojectbyfollowingtheinstructionsinthislab'snotes instead. A.Lab1Follow-up OpenGLisanoperatingsystemandhardwareplatformindependentgraphics librarydesignedtobeeasilyportableyetrapidlyexecutable.Unlike Direct3D,whichisonlyavailableonPC,XboxandWindowsMobileOS,OpenGL isavailableonawidevarietyofhardwareplatformsandoperatingsystems includingUnix/X11(Linux,BSD),MacOSX,andMicrosoftWindows 98toWindows10. Onthedesktop,OpenGLstayedrelevantthrougharobustextension mechanismandwithmajorreleasesthroughoutthe2000s.InFebruary2016, OpenGLreceivedamassiveupdatecalledVulkan,whichhasfeaturescomparableto Direct3D12.ThefirstgamesforVulkanappearedsoonafter.Afewnotable recentgameswithVulkansupportincludeDoomEternal,HalfLife: Alyx,CrisisRemastered(1,2,and3)andtheupcomingBaldur'sGate 3.VulkanwillrunonhardwarethatcansupportOpenGLES3.1or OpenGL4,includingSwitch,Androidsincev9.0andallrecentWindows3D desktop.AppledoesnotsupportVulkandirectly,preferringtheirownMetal API,butKhronosprovidesacompatibilitylayercalledMoltenVK. Anembeddedversion,OpenGLES,isavailableonmanyhand helddevicesincludingiPhoneOSandAndroidOSdevices.Javascriptversions ofOpenGLES2.0and3.0areanofficialpartoftheHTML5 specificationandareavailableasWebGL1.0(Feb.2011)andWebGL2.0(Apr.2017).AsofJanuary2021,WebGL2supportisavailableonnearly85%ofthebrowsermarket,andWebGL1isat96.18%. ThebasicstepstouseOpenGLinaprogramare: GetaRenderingContext. Fromtheprogrammer'sperspective,thisisasimpleonesteptaskinWebGL(thewebbrowser,oragent,hasmanysteps),but historicallyitinvolved: GettingaDeviceContext(DC)fortherenderinglocation Selectingandsettingapixelformat(featureset)fortheDC CreatingaRenderingContext(RC)associatedwiththeDC Optional:ifanupdatedDC/RCrequestmechanismisincludedwiththedriver,requestitwiththeactive RCandrepeattheprocesstogetafullycapableOpenGL. Repeattheseasneededtodrawwhatisdesired Load,compileandbindshaders Loadgeometryintobuffers Connectbufferstotheshaders Setshaderuniformstate SetOpenGLinternalstate Drawthegeometryasneeded Releasetherenderingcontext Releasethedevicecontext WhatareDCsandRCs? ADCissimplyadatastructurethatkeepsthestateofthe currentsettingsofandroutescallstotheappropriatedevice(graphicscard+window+monitor;remote computer;etc.). AnRCisadatastructurethatkeepsthestatevariablesfor OpenGL.ItisalsoaportalthroughwhichOpenGLcallsaresenttothe DC. YoucanthinkofbothDCandRCasadatastructurethatkeeps thestateofcurrentOpenGLsettingsandroutescallstotheproper device. Whatisapixelformat? PixelformatsdefinethetranslationbetweenOpenGLcalls(such asanOpenGLcalltodrawapixelwithanRGBtriadvalueof [128,120,135])andtheoperationthattherenderingsystemactually performs(thepixelmightbedrawnwithatranslatedRGBvalueof [128,128,128]).Theyarealsoadescriptionofallthehardware featuresyouwantOpenGLtoprovidetoyourprogram.Theselectedpixel formatdescribessuchthingsashowcoloursaredisplayed,thedepthof fieldresolution,andwhatadditionalcapabilitiesaresupportedbythe renderingcontextyouhavecreated. Click hereforamoreinvolveddiscussionofpixelformatsinWindows. Click herefordetailsonDCs(Renderers)andpixelformats(Buffer Attributes)inMacOSX AlthoughWebGLdoesn'tletyouchangeallofthethingsafullpixel formatwould,youcanrequestsomepixelformatfeatureswhenyouissuethe getContext()commandbyprovidinganoptionalContext Attributesargument.TheWebGLSpecification providesafulllistof contextattributes,theirdefaults,theirpurpose,andanexampleofuse. B.WebGLRenderingFunctions TheRenderingContextObject AllthefunctionsintheWebGLAPIareaccessedthroughtheRenderingContextobject.ThatiswhyalltheWebGL2 Javascriptprogramsyouhaveseensofarhaveaglobalvariablecalledglatthetop: vargl;//Genericvariable,intendedtoholdWebGL2RCobject TheRenderingContextobjectisacquiredwiththegetContext()functionbuilt intoHTML5canvases.Thisfunctionmayalsoprovideaccesstoothertypesofrenderers. //findcanvasbyidname varcanvas=document.getElementById(/*yourcanvaselement'sidgoeshere*/); //getwebglRCanddosomeminimalerrorchecking gl=canvas.getContext("webgl2");//basicwebGL2context //gl=canvas.getContext("webgl2",{antialias:false});//WebGL2contextwithanoption if(!gl) { //Thisisfriendlierthananalertdialoglikeweuseinthetemplate canvas.parentNode.replaceChild( document.createTextNode("CannotgetWebGL2RenderingContext"), canvas ); } Onceyouhavearenderingcontext,allyourinteractionswithWebGLwillbe throughtheobject.Thismeansthatifyourrenderingcontextobjectiscalled glallWebGL2callswillbegingl..ManyWebGL2 constantsare alsodefinedasmembersoftherenderingcontextobject.Forexample,inthis labyouwillsee: FunctionsRelatedConstants ===================================== DataManagementgl.createBuffer() gl.bindBuffer() gl.bufferData()gl.STATIC_DRAW gl.DYNAMIC_DRAW gl.STREAM_DRAW gl.ARRAY_BUFFER ShaderConnectionManagement gl.createVertexArray() gl.bindVertexArray() gl.getAttribLocation() gl.enableVertexAttribArray() gl.vertexAttribPointer() gl.getUniformLocation() gl.uniform*() Built-inSettings gl.clearColor() gl.clearDepth() gl.cullFace()gl.FRONT gl.BACK gl.FRONT_AND_BACK gl.frontFace()gl.CW gl.CCW gl.enable()gl.CULL_FACE gl.DEPTH_TEST gl.POINT_SMOOTH Drawgl.clear()gl.COLOR_BUFFER_BIT gl.DEPTH_BUFFER_BIT gl.drawArrays()gl.LINES gl.LINE_LOOP gl.LINE_STRIP gl.TRIANGLES gl.TRIANGLE_STRIP gl.TRIANGLE_FAN gl.POINTS General gl.FLOAT gl.UNSIGNED_BYTE gl.TRUE gl.FALSE ForafulllistseethesectiononWebGL2 ContextintheWebGL2Specifications,orchecktheMozillaDeveloper'sPageonWebGLRenderingContext. SettingUpaShaderProgram BeforeyoucandoanydrawingyouneedtotellWebGLwhattodowith thethingsyoutellittodraw.YoudothiswithshaderprogramswrittenalanguagecalledGLSL.Shaderprograms consistofaminimumoftwoparts:avertexshaderandafragmentshader. Youmayalsohaveheardoftwoothershadertypes:geometryshaders,tesselationshaders,and computeshaders.GeometryshaderswereintroducedinOpenGL3.2withGLSL1.50,tesselationshaderswere introducedinOpenGL4.0withGLSL4.00andcomputeshaderswereintroducedinOpenGL4.3withGLSL4.30.These extrashadertypesareoptionalinallversionsofOpenGL. WebGL1supportedGLSL1.0ES,whichisbasedonGLSL1.20andhadonlythetwobasicshadertypes.WebGL2allowsus touseOpenGLShadingLanguage3.00ES(GLSL3.00ES)asitsshaderprogramminglanguage,butcanstillusetheold WebGLversionifnecessary.GLSL3.00ESisamodifiedversionofGLSL3.30,soWebGL2supportsgeometryshadersif youwantthem. ChoosingyourGLSLversion AWebGLshaderwithnoversioncodewilldefaulttoGLSL1.00ESwhichisverydifferentandfarlesspowerfulthan GLSL3.00ES.Toexplicitlyselectashaderlanguage,theveryfirstcharactersmuststatetheversion.Nospacesor newlinesshouldcomefirst.Asaconvenience,thetextbook'sinitShaders() functionsstripleading whitespacefromshaderprogramssoyoucanusetidyformattinginHTMLandstillcompileyourshader.Allpartsofa shaderprogrammustusethesameversion. ChoosingGLSL3.00ES:makethisthefirstlineofallshadersintheshaderprogram #version300es VertexShader Youwillsendlistsofvertexinformationintoavertexshader.This informationcomesinthroughvariableslabelledwiththein modifier.Thisinformationrepresentsattributesthatcanchange fromonevertextothenextsuchascolourandposition.InolderGLSL programs,vertexshaderinputsaremarkedattribute.Thistermisstillusedinotherplaces. Youcanalsosetvaluesbeforeyoudrawwithashaderthatwillstayconstantwhiletheshaderisrunning.Thisis donebysettingvariableslabelledwiththeuniformmodifier.Youwillseemore aboutthislater. Whenwearedoneusingattributesanduniformstocalculatepropertiesforavertex,wepassthe resultsalongtothefragmentshaderthroughoutputslabelledwiththe outmodifier.Thevertexshaderoutputsforthe verticesinthesameprimitivewillbeinterpolatedacrosstheprimitive -iftheyaren'tallthesame,theirvalueswillvaryfromfragmenttofragment.InolderGLSLprograms,vertex shaderoutputsarearemarked varying. Belowisourfirstvertexshader.Replacethevertex-shaderinyourtemplatewiththisvertexshadercode: BasicVertexShader #version300es invec2vPosition;//receivesincomingvertexpositions outvec4color;//passesthecolourofthisvertextothefragmentshader voidmain() { //Addzandwcoordinatestotheincomingpositionandpassiton. gl_Position=vec4(vPosition,0.0,1.0); //Coloureveryvertexred color=vec4(1.0,0.0,0.0,1.0);//colourchannelsarered,green,blueandalpha } Thisvertexshaderonlyhasoneattributeandnouniforms.Theattributerepresentsa2Dcoordinatefor thevertexandhasdatatypevec2-a2componentvectorwhichhasabasetypeof float.Verticescanbemovedaroundinspace,coloured,andlitby thevertexshader.Youwillexploremanyofthesethingslater.Fornow,our vertexprogramwillonlyprovideacolourforthevertex.Thiscolourishard codedandwillbethesameforallvertices.Youwilllearnhowtochangethis colourwithauniformoranattributelaterinthislab. Ourfirstvertexshaderusestwooutputsaswell.Youcanseethe declarationfora4componentvector,vec4,forcolour,andweuse thebuilt-inoutputgl_Position,whichisalsoavec4.GLSLdoesnotperformanytype coercion, whichiswhytheshaderaddstwomorecomponentstovPositionwhen itisassignedtogl_Position. Allvertexshadershaveasecondbuilt-inoutput,gl_PointSizewhichcontrols thesizeofpoints.Its valuecontrolsthepoint'swidthinpixels. FragmentShader Thefragmentshadergetsdatathatisblendedfromeachvertexthatmakesup theprimitivebeingdrawn.Thiscouldbeapositionsomewherebetweeneach vertex,atexturelookupcoordinate,orablendedcolour.Fornow,ourshader willignorethebuilt-ininputsandsimplycopytheincomingcolourtothescreen. Replacethefragmentshaderinyourtemplatewiththisfragmentshadercode: BasicFragmentShader #version300es precisionmediumpfloat; invec4color;//Theblendedfragmentcolourfromthevertexshader. //Namesofinputstoafragmentshadermustmatch //anoutputfromthevertexshader. outvec4fragColor; voidmain() { fragColor=color; } Thisfragmenthasoneinputfortheinterpolatedcolour.Itisimportantthatnamesanddatatypesfortheinputs youcreateinafragmentshadermatchthenameanddatatypeofanoutputyoucreateinthevertexshader. Thisshaderalsodeclaresanoutput.Thereisnobuiltincoloroutputfromfragmentshaders.Instead,thefragment shadermustdeclareatleastoneoutput.Typicallythereisonlyoneoutputfromafragmentshader,anditgoesdraw buffer0-whichwillusuallybeyourcanvas.Iftherearemoreoutputs,theywillgotootherdrawbufferswhich mustbespecifiedwithlocationnumbers.Theseoutputsmaybegrayscale,declaredwithfloator uint. Fragmentshadershavethreebuilt-ininputs: highpvec4gl_FragCoordthefragment'spositionintheframebuffer(often thecanvas) boolgl_FrontFacing-indicatesifthefront(true)orback (false)isfacingtheviewer mediumpvec2gl_PointCoord-usedtocreate shaped,varicolored,ortexturedpoints.[0.0,1.0]foreachcomponent. andonebuiltinoutput: gl_FragDepth-allowsthefragmentshadertooverridethedefaultdepthofa fragment-thezvalue ofgl_FragCoord. Loading,CompilingandUsingtheShaderProgram Compilingshadersisaninvolvedprocess.Youhavetogettheshadercodeas text,compiletheindividualpiecescorrectly,thenlinkthem.Youarealso responsibleforcheckingforcompileandlinkerrorsandreportingthem.The textbookprovidesthreedifferentinitShaders()functionsthatcandoallthisfor you.Istronglysuggest thatyouuseone.Ifyouarelucky,yourlabinstructorwillexplainhowtouseallthree. YoushouldcallinitShaders()fromwithinyourinit()function,andusetheresultastheactive shadersomethinglikethis: //Loadandcompileshaders,thenusetheresultingshaderprogram varprogram=initShaders(gl,"vertex-shader","fragment-shader"); gl.useProgram(program); OpenGLPrimitives Yourgraphicshardwarehaslimitedabilitytorepresentgeometry.Most hardwareonlyknowshowtorendertriangleprimitives.Everythingelse isbuiltupusingtriangles.OlderversionsofOpenGLincludedsomeother shapesthatmighthavebeensupportedbysomespecializedhardware,suchas convexpolygonsandquadrilaterals,butthatsupporthasbeenremovedfrommost newerversions.Belowisadiagramshowingthedifferentprimitivetypesor modes: Here'sacoolinteractivePrimitivesDemo DrawingwithoneofthesetypesiscontrolledbyadrawArrays() ordrawElements() function.ThedrawArrays()functiontellsyourrenderingcontextto begindrawingacertainnumberofelementsfromalistofvertexdatathathas alreadybeenloadedintoanarraybufferobjectandconnectedtoappropriate shaderinputs.ThedrawElements()issimilar,butrequiresan additionalelementindexbufferthatallowsyoutoaccessthedatainthe vertexarraysoutoforder-thisisthelastyou'llhearof drawElements()inthelabs.Regardlessofwhichyouuse,tobeableto drawyouwillneedtoknowhowtoloadvertexdataintoabuffer,andhowto attachittoashaderattribute. Vertices DefiningVertexData BasicWebGLrenderingprimitivesaremadeupof listsofvertices. Vertexdatacanbetwo,threeoffourdimensional.Anextradimension issometimesnecessarytoproperlymoveverticesaroundinspace. Vertexdataismostoftenrepresentedwiththevec2,vec3,andvec4datatypesin theshader.Theseare2,3and4componentfloatingpointstructures. Thisdatashouldbeuploadedfromjavascriptarraysof32-bitfloatingpointtype.Forexample,thefollowingtwo dimensionalarraygivesthe2Dcoordinates forthethreeverticesinatriangle: //Trianglepositions varpoints=newFloat32Array ([ 0.9,0.9, 0.9,0.0, 0.0,0.9 ]); Thenumberofcoordinatesprovidedpervertexshouldmatchthevectype specifiedonthepositioninputoftheshaderyouareusing.Ifitdoesn't,itmaybepaddedtofit. Thetextbook'sMVnew.jsfiledefinesJavascriptclassesforthe vec2,vec3andvec4datatypes.Thefollowingcodeisidenticaltotothearray above,butusesthevec2class: //Trianglepositions varpoints= [ vec2(0.9,0.9), vec2(0.9,0.0), vec2(0.0,0.9) ]; Youcanuseeitherform,butIprefertousearraysof vec*classesbecausetheyarecompatiblewiththemathfunctions providedbyDr.Angel,andprovideaneasywaytoaddandremovepointswith .push()and.pop()functions.Thiswouldallowyou toeasilywritefunctionstocreate arbitrarilylargearrays,likethisoneformakingcircleswithradiusof1: functioncircle(sides) { varvertices=[];//createemptyarray if(sides<3) { console.log("functioncircle:Notenoughsidestomakeapolygon."); } else { if(sides>10000) { sides=10000; console.log("functioncircle:Sideslimitedto10,000."); } for(vari=sides;i>=0;i--) { vertices.push(vec2(Math.cos(i/sides*2*Math.PI),Math.sin(i/sides*2*Math.PI))); } } returnvertices; } Theyarealsoeasilyconcatenatedwiththeconcat()method,whichcomesinhandyforpacking multipledrawableobjectsintoonebuffer. Pros Cons Float32Array ExacttyperequiredformostcommonWebGLbuffers OnedimensionalHardtomanipulate Arraysofvec2,vec3,vec4 ElementshavemathsupportinMVnew.js Easytoextendandconcatenate Mustbeflattenedbeforesendingtoabuffer. FlatteningtranslatesintoaFloat32Arrayandtakes alotoftimeifyouupdatebufferdatafrequently LoadingVertexDataintoBuffers Onceyouhavesomevertexdata,youneedtoload itintobuffers. Eacharraycanbeloadedintoaseparatebuffer,orallthearrayscan bepackedintothesamebuffer.Youwillfindexamplesofbothin variouscodesamplesinyourtextbook.Fornow,wewillusetwoseparate buffers:oneforvertexpositionsandoneforvertexcolours. Tocreateabuffer,youusethecreateBuffer() (similartothe OpenGLESglGenBuffers() command).createBuffer()createsavalidbuffernamewhichyou mustbindtoloadwithbufferdataorattachtoashaderattribute. createBuffer() WebGLBuffercreateBuffer() Returnsabuffermanagementobject/name.Onebuffermaybeboundtoloadorconfigureatatime. Onceyouhaveabuffername,youbinditwithbindBuffer(). Abufferisnotallocateduntilyoubinditthefirsttime. bindBuffer() voidbindBuffer(GLenumtarget, WebGLBufferbuffer); Where: targetindicateswhattypeofdatathebufferholds-eitherARRAY_BUFFERor ELEMENT_ARRAY_BUFFER bufferisavalidbuffernamegeneratedwithcreateBuffer(). YouwillusethetargettypeARRAY_BUFFERfor storingallvertexdataintheselabs. Withthebufferbound,youarereadytoloaddataintoitwithbufferData().This functioncomesin fourforms.ThefirstthreealsoexistinWebGL1:form1specifiesa buffersizeandinitializeswith0s,forms2and3 initializefromadatasource–likeaflatarray.Form4isnewtoWebGL2andpermitsinitializingfromonly aportionofadatasource. bufferData() Form1: voidbufferData(GLenumtarget,GLsizeiptrsize,GLenumusage); Form2: voidbufferData(GLenumtarget,ArrayBuffer?data,GLenumusage); Form3: voidbufferData(GLenumtarget,ArrayBufferViewdata,GLenumusage); Form4: voidbufferData(GLenumtarget,ArrayBufferViewdata,GLenumusage, GLuintsrcOffset,GLuintlength); Where: targetindicateswhattypeofdatayouaresending (youwillalwaysuseARRAY_BUFFER), sizeisthesizeofbuffertoallocateinbytes, dataisareferencetoaflat(contiguous,non-pointer)array,liketheFloat32Arrayabove, usageindicateshowthedatawillbeused. srcOffsetisthestartofdatatobecopiedfromthesource.IfthesourceisaDataView,thisvalueis inbytes,otherwiseitistheelementofthearray. length:(optional)lengthtocopyfromthebuffer.Thedefaultvalue,0,meanscopytherestofthe array.OthervaluesaretreatedasbytesorelementsasforsrcOffset. Sinceyouwilllikelyuseyourbuffersfordrawingsimplegeometric objects,youwillgenerallyspecifytheSTATIC_DRAWusagetype.If youplantoupdatethebufferfrequently,youmightwanttospecify DYNAMIC_DRAW.Ifyouplantousethebufferinfrequentlyyou shouldspecifySTREAM_DRAW.Abuffer'sdatamaybeupdatedwith anothercalltobufferData()orwithacalltobufferSubData(). Ifyouplantoupdateonlyaportionofabuffer'sdata,considerusing bufferSubData(). Hereishowwewouldloadoursampletrianglepositiondata.Sincewe willonlyloadthedataonce,placethiscodeininitaftertheshader loadingcode: Placethiscodeininitaftertheshaderloadingcode.Makesureyouhavealsoaddedoneofthetwopoints definitionsfromearlier,orsetpointsequaltotheresultofacirclefunctioncall: //***Positionbuffer********************** //Createabufferforvertexpositions,makeitactive,andcopydatatoit varpositionBuffer=gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER,positionBuffer); //UsethisformforFloat32Arraydata //gl.bufferData(gl.ARRAY_BUFFER,points,gl.STATIC_DRAW); //Usethisformforarraysofarraysorofvecs gl.bufferData(gl.ARRAY_BUFFER,flatten(points),gl.STATIC_DRAW); ManagingBufferAttachments Asyouwillsoonsee,attachingbufferstoashaderiscomplicatedandexpensive.WebGL1.0hadnoeasywayto managetheprocess,but WebGL2.0hasvertexarrayobjects(VAOs)thatcanmanagetheseattachements.VAOscanbeusedtoquicklyswitch fromdrawingonethingtoanother.Youdon'tneedVAOsforthis,sinceabuffercanbepackedwithmultipleitems, butitcanbeveryhandyespeciallyifyouarealsoswitchingshaders. TouseVAOs,youfirstcreatethemwithcreateVertexArray(), thenbindtheoneyouwishtoconfigurewithbindVertexArray(). Theprocesslookslikethis: ConfiguringaVertexArrayObject: varmyFirstVao;//declaregloballysoyoucanconfigureininit()anduseinrender() myFirstVao=gl.createVertexArray(); gl.bindVertexArray(myFirstVao);//startconnectingbufferstoashader //alsobindconfiguredVAOsbeforedrawingwiththem AttachingBufferstoShaderPrograms Onceabufferisloadedwithdata,itmustbeattachedtothecorrect inputinyourshaderprogram.Todothis,youaskfortheinputby name,enableit,thenattachyourdatainthecurrentlyboundbufferto theinputwithadescriptionofhowthedataisformatted. TogetareferencetoashaderinputyouusegetAttribLocation(). getAttribLocation() GLintgetAttribLocation(WebGLProgramprogram,DOMStringname); Where: programisavalid,compiledshaderprogram nameisacharacterstringcontainingthe nameofthedesiredshaderinput. Ifnamedoesnotrefertoavalidinputinthespecifiedshaderprogram,thereturnedresultwillbe-1. WebGLrestrictsshaderattributenamestoamaximumlengthandtryingtorequestonewithalongernamewillalso resultin-1. ToenabletheshaderinputyouuseenableVertexAttribArray(). enableVertexAttribArray() voidenableVertexAttribArray(GLuintindex); WhereindexisavalidvaluereturnedfromgetAttribLocation(). ToattachthecurrentlyboundbuffertoashaderinputyouusevertexAttribPointer(). vertexAttribPointer() voidvertexAttribPointer(GLuintindex,GLintsize, GLenumtype,GLbooleannormalized, GLsizeistride,GLintptroffset); Where: indexisavalidvaluereturnedfromgetAttribLocation(). sizeisthenumberofcomponentsbeingsentpervertex.Mustbe1,2,3,or4. typeisthedatatypeofthecomponents.YouwillusuallyuseFLOAT, butforcolours UNSIGNED_BYTEishelpfulbecauseitallowsyoutospecifyvaluesfrom0to255 insteadof0to1. normalizedisforintegerdataanddoesn'tapplytothetypeFLOAT,so useFALSE withFLOATtype.Itwillcauseintegertypedatatobemappedtoafloatwith valuesbetween0and1, whichishowshadersexpectcolourstobeformatted. strideindicatesthenumberofbytesbetweenvaluesthat applytothisshaderinput.Thisallowsustosendinterleaveddata.If yourvaluesaretightlypacked,use0asyourargument. offsetistheoffsetinbytesofthefirstrelevantcomponentin yourbuffer.Ifyouareusingseparatebuffersforeachvertex attribute(color,position,texturecoordinate,etc),thisshouldbe0. Thepurposeofthesizeandtypeargumentsis to describethedatabeingsenttotheshader.Iftheoriginaldatadoesn'tmatch what'saskedforintheshader,itwillbeconvertedforyou.Infact,all vertexattributesareconvertedtosize4.Ifyorzaremissing,theybecome 0,andifwismissingitbecomes1.Youcanthendefinean attributeintheshaderofadifferentsizedependingonyour need. Hereishowwewillattachthesampletrianglepositionbuffertothe"vPosition"inputoftheshader: Placethiscodeininitafterthebuffercreationcode //Enabletheshader'svertexpositioninputandattachtheactivebuffer varvPosition=gl.getAttribLocation(program,"vPosition"); gl.enableVertexAttribArray(vPosition); gl.vertexAttribPointer(vPosition,2,gl.FLOAT,gl.FALSE,0,0); Finally,todrawthings,usedrawArrays(). drawArrays() voiddrawArrays(GLenummode,GLintfirst,GLsizeicount); Where: modeiswhatprimitivetodrawwith firstiswhatvertextostartatinthearrayyouloaded countishowmanyverticestodraw. Todrawthesampletriangleplacethiscodeinthedrawfunction: PlacethiscodeinthedrawfunctionbeforetheglutSwapBufferscommand: gl.clear(gl.COLOR_BUFFER_BIT); gl.drawArrays(gl.TRIANGLES,0,3); Ifyouhavedoneeverythingtothispointyoushouldseeared triangleintheupperrightcornerofanotherwisewhiterendering canvas.Nowit'stimetoexperimentwithdifferentdrawingmodes. Points Onlyonetypeofpointcanbedrawn: POINTS—drawsapointforeachvertex Youcancontrolthesizeofthepointsbysettingthevalueofthevertexshader'sbuilt-ingl_PointSize output.Ifyoudonotsetgl_PointSize,thepointsizeisundefinedandyoumay notseeanypointsat all.AlthoughtheWebGLspecificationonlyrequirespointsofsize1,nearlyallWebGLimplementationsallowamuch widerrangebecausetexturedpointsformthebasisofmanyinterestingeffects.Trysettingvariouspointsizes inyourvertexshader. Bydefault,largepointsaresquare.Youcanchangethisusingclevercodinginaspecializedfragmentshaderfor points,likethisone: SimpleRoundPointFragmentShader #version300es precisionmediumpfloat; invec4color;//Theblendedfragmentcolourfromthevertexshader. //Namesofinputstoafragmentshadermustmatch //anoutputfromthevertexshader. outvec4fragColor; voidmain() { fragColor=color; //Tomakesimpleroundpoints,throwawayfragmentsoutsideacertainradius vec2pc=gl_PointCoord-vec2(0.5);//puts(0,0)atcenterinsteadoflowerleft floatd=length(pc);//calculatedistancefromthisfragmenttopointcenter if(d>0.5)discard;//Antialiasingnotpossiblethisway.Thereisanother... } Lines Threedifferentlineprimitivescanbecreated: LINES—drawsalinesegmentforeachpairofvertices. LINE_STRIP—drawsaconnectedgroupoflinesegmentsfromvertexv0to vnconnecting alinebetweeneachvertexandthenextintheordergiven. LINE_LOOP—similartoLINE_STRIP,exceptitclosesthelinefromvnto v0,defininga loop. SomeWebGLimplementationsletyoucontrolthewidthoflineswithlineWidth().MostMacsimplement theminimumrangeoflinewidths-,1.0to1.0.YoumayfindthatyourPCallowsmore. Triangles Frontfaces,backfacesandrenderingmodes cullFace()—if CULL_FACEisenabled,thisspecifieswhichsidesofatriangletodiscard, FRONT, BACKorFRONT_AND_BACK. frontFace()—specify whetherclockwise,CWorcounter-clockwise,CCWpointdrawingordermeansatriangleis facingfront. TriangleTypes TRIANGLES—drawsaseriesofseparate three-sidedpolygons TRIANGLE_STRIP—drawsastripofconnected triangles.Thefirstthreeverticesdefineacompletetriangle.Each subsequentvertexcompletesatrianglewiththeprevioustwo.Thedraw orderofthefirsttwopointsreversedeverytriangletohelpmaintain clockwiseorcounter-clockwisedraworder.ie:vertices0-1-2-3-4-5-6are drawnlikethis:0-1-2,2-1-3,2-3-4,4-3-5,4-5-6 TRIANGLE_FAN—drawsastripoftriangles connectedaboutacommonorigin.Thefirstthreeverticesdefinea completetriangle.Eachsubsequentvertexcompletesatrianglewiththe previousandthefirstvertex. Trythispointsarraywitheachoftheabovetriangletypes: //Triangle varpoints= [ vec2(0.0,0.0), vec2(0.5,0.0), vec2(0.5,0.5), vec2(-0.5,0.5), vec2(-1.0,0.0), vec2(-0.5,-0.5) ]; Itmaybehardtoseewhyyougettheresultsyouobserve.Considerthe orderthepointsaredefinedandhowtrianglesaredefinedforeach triangletype. SpecifyingColours Sofarourshaderhasusedahardcodedcolour.Youcanchangethis colourinarunningprograminoneoftwoways:uniformsand attributes.Theseareexplainedbelow. AllourcolourswillbeinRGBAformat-Red,Green, Blue,Alpha.Alphaisanextratermusedinblendingoperations.Youcanthinkofitas"transparency",butitcan domorethanthat.Thealphachannelwillbeignoredinourprogramsthisweek. UniformColours Auniformisashadervaluethathasaconstantvalueduringadraw operation,butcanbechangedbetweendrawoperations withWebGLcommands.Uniformscanbedeclaredinvertexandfragementshaderprograms. Inyourshadercode,auniformisdeclarednexttoinputvaryingsorattributeslikethis: uniformtypeuniformName; //eg:a4componentcolouruniform uniformvec4uColor;//copythistoyourcolouroutput Yougetaccesstoauniforminmuchthesamewayasavertexarrayinput,butyouusegetUniformLocation: WebGLUniformLocationuniformLocation=rco.getUniformLocation(shaderProgram,"uniformName"); //eg:getthecolourfromtheexampleaboveforuseinlabsamplecode varuColor;//Gettinguniformscanbeslow,somakethisglobal uColor=gl.getUniformLocation(program,"uColor");//Andputthisininit. YouchangethevalueofauniformwithglUniform*()type functions.The* representstheformatoftheuniformyouarechangingandhastwoorthreeparts: thenumberofcomponents(1,23,or4) thedatatype(fforfloat,iforinteger) (optional)avtoindicatethatyouarepassinginanarrayofvalues. Here'salittlemappingforyou: InShader Matchinguniform*()function float uniform1f int uniform1i vec2 uniform2f oruniform2fv vec3 uniform3f oruniform3fv vec4 uniform4f oruniform4fv Tochangethe4componentuColoraboveyoumightwriteeitheroftheseglUniform* calls: gl.uniform4f(uColor,1.0,1.0,0.0,1.0);//Yellow varyellow=vec4(1.0,1.0,0.0,1.0);//Yellow gl.uniform4fv(uColor,flatten(yellow)); VertexColourArrays Theseworkjustlikevertexpositionarrays.Youwillneedtosetup asecondarrayinputtoyourvertexshader,createacolourarray,load itintoabufferandattachittoyourshader.Herearesamplesofall threer.: ThefollowingcodedefinesanattributeinputcalledvColor.It issimilartothecodeusedforvPosition.Youshouldassignthe valueinvColortothecoloroutput: Addthislinetoyourvertexshader,nearthevPositioninput, andmodifyyourcolouroutputvaluetomatch: invec4vColor;//Pervertexcolourinput Addtheappropriatetrianglecolourstoinitneartothepointsarray //forinitialtriangle varcolors= [ vec4(1.0,0.0,0.0,1.0),//Red vec4(0.0,1.0,0.0,1.0),//Green vec4(0.0,0.0,1.0,1.0),//Blue ]; //forlatertriangletypesexample varcolors= [ vec4(1.0,0.0,0.0,1.0),//Red vec4(0.0,1.0,0.0,1.0),//Green vec4(0.0,0.0,1.0,1.0),//Blue vec4(1.0,1.0,0.0,1.0),//Yellow vec4(0.0,1.0,1.0,1.0),//Cyan vec4(1.0,0.0,1.0,1.0),//Magenta ]; Thencopythecolourdatatoabuffer,likethis: Placethisbelowyourpositionbuffercodeininit //***Colourbuffer********************** //Createabufferforcolourpositions,makeitactive,andcopydatatoit varcolorBuffer=gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER,colorBuffer); gl.bufferData(gl.ARRAY_BUFFER,flatten(colors),gl.STATIC_DRAW); //Enabletheshader'svertexcolourinputandattachtheactivebuffer varvColor=gl.getAttribLocation(program,"vColor"); gl.enableVertexAttribArray(vColor); gl.vertexAttribPointer(vColor,4,gl.FLOAT,gl.FALSE,0,0); Theprocessisverysimilartothepositionbuffersetup.Ihavehighlightedthedifferencesinred. SettingUp2DRendering Clearingtherenderingwindow Thecolourbufferanddepthbufferareusuallyclearedeachtimeyou begindrawingtotheOpenGLwindow.Thevaluesyouusetoclearwith rarelychange,sotheyareoftensetintheinitialisationstepwith theclearColor() andclearDepth() functions: gl.clearColor(0.0,0.0,0.0,1.0);//clearcolourisblack gl.clearDepth(1.0);//Cleartomaximumdistance Theactualclearinghappensjustbeforeyoudraw.Inyourmaindraw routine,youspecifywhichbufferstoclearwiththeclear() function: gl.clear(gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT); TheCamera Inthislabyouwillbedrawing2Dobjects.Whenyoudrawin 2D(oryouaredoing3DCADwork)youshoulduseaspecialgeometry transformationthatdoesnotcauseshapeorsizedistortion.This transformationiscalledorthographicprojection.Inthefirst labwewanteda3Deffectwithforeshorteningsoweusedperspective projection.Thetransformationmadebyperspectiveprojectionmakesithardtoplace thingspreciselyonthescreen.Shapesaredistortedtowardtheedges andcorners,andtheirapparentsizevarieswiththeirdistancefrom thecamera.Withorthographicprojectionyoucanpreciselycontrolhow coordinatesmaptothedrawingarea,andobjectsrenderthesameway regardlessofdistance. Thisweek,wewilluseonlysimplenormalizeddevicecoordinates-our drawingspacewillliebetween(-1,-1)inthelowerleftcornerand(1,1)in theupperright.Ifyouareusing3Dcoordinates,then-1isthenearest possibleZcoordinate,and1isthefarthest.Thingsdonotappearsmallerwith distance.Nextweek,whenyoulearntodoperspective()projection andothertransformations,youwillalsoseethetextbook'sortho() functionswhichcangiveyoucontroloverhowcoordinatesaremappedtothe windowwhenyoudon'tdoperspective. Defaultdrawingcoordinates.TheseareknownasNDCorNormalizedDeviceCoordinates. IfyouarehavingdifficultydrawinginNDCthisweek,youcanmapfromcanvascoordinatestoNDCbychangingthe gl_PointCoordlineinyourvertexshader. floatwidth=500.0,height=500.0;//setthesetomatchyourcanvas vec4temp...;//incomplete-setthiswithvec4versionofvPosition //exactcodedepentsonhowyousetupvPosition. //ifyaxisisflipped,usethisline //temp.y=height-temp.y; gl_Position=temp/vec4(width,height,1.,1.)*2.0-1.0; Thiswillput(0,0)inthelowerleftcornerofthecanvas. Depthtesting Inthelasttwosectionswe'vediscussedhowtoclearthedepthbuffer,and thedefaultrangeofdepthvalues.Perhapsyou'dalsoliketoknowhow tospecify3Dverticesanddodepthtesting. Withoutdepthtesting,objectsappearonthescreenintheorderyoudraw them.Ifyouwanttodrawsomethingbehindanotherthingyouhavealready drawn,youneedtoturnondepthtesting,supplydepthvalueswithyourvertex coordinates,andclearthedepthbuffereachtimeyoustartdrawing. Inmoredetail: Clearthedepthbufferalongwiththecolourbufferasdescribedabove. Turnondepthtestingwithenable()likethis: Placethiscodeanywhereinyourinit: gl.enable(gl.DEPTH_TEST); Supplyanon-zerodepthtothevertexshaderbymakingsurethatthe vPositionattributeisavec3orvec4.Then makesureyouadjusthowitiscopiedtothegl_Positionbuilt-in output. Changeyourcoordinatedataarraystobasetypevec3,thensupplyadepth,or z,valuetoeachvertex inyourdataarrays.Forexampleyoucouldspecifytwooverlappingtriangleslikethis: //TRIANGLES varpoints= [ vec3(0.0,0.0,-0.5), vec3(0.5,0.0,-0.5), vec3(0.5,0.5,-0.5), vec3(0.0,1.0,0.0), vec3(0.0,-1.0,0.0), vec3(1.0,0.0,0.0) ]; varcolors= [ vec4(1.0,0.0,0.0,1.0),//3redvertices vec4(1.0,0.0,0.0,1.0), vec4(1.0,0.0,0.0,1.0), vec4(0.0,1.0,1.0,1.0),//3cyanvertices vec4(0.0,1.0,1.0,1.0), vec4(0.0,1.0,1.0,1.0) ]; Makesureyouaresetuptouseacolourinputattributeasdiscussedearlier. Makesureyouaredrawingthesixpointsspecified. ChangethesizecomponentofthevertexAttribPointer()callforyour positionbuffertomatch thepointsarray.Itwas2,itshouldbe3now. Ifeverythingworks,thecyantriangleinthisexampleappearsbehindthe red,eventhoughitisdrawnsecond.Inthedefaultcoordinatesystem,larger zvaluesarefartheraway.Withdepthtestingoff,thecyantrianglewouldbe infrontoftheredone. Assignment Goalsofthisassignment: Getcomfortabledrawingwithvertexbuffers,uniformsandshadersby: drawingseveralthingswithseparatedrawcommands usingdifferentprimitives changingdefaultlineandpointsizes changingcoloursonthefly Forstarters: Itisgoodtogetafeelingforwhereyoucanputpointsonthe scene. Thefollowinginstructionsaremeanttogetyoustartedfromoneof thetemplateprojectsprovidedonthelabschedule.Yourlabinstructor willprobablydoa.throughc.duringthelabdemo: GettheHTML andJavascripttemplatecodefromlab1andputitinaLab2folderinyourLabdirectory structure.NamethefilesLab2.htmlandLab2.js ModifytheshaderintheprojectasdescribedintheSettingUpaShader Programsectionofthelab2notes. Addcodetoinit()asindicatedbythefollowingcomments: //Explicitlysetclearcolortoblackoracolouryoulike //Load,compileanduseashader //Loadthesimpletrianglepositiondatanearthetopofthenotesintoabuffer //Bindthebuffertoyourshader'svPositioninput Confirmthatyoucandrawthetrianglewiththeoriginalshader code.UsethefirstdrawArrays()commandfoundinthenotes,andplaceitinthe render() functionasdescribedthere. Addeitherauniformoranarrayinputtoyourvertexshadertoallowyoutochangecolours. Addtheseverticestotheendofyourpointsarray: vec2(0.99,0.99), vec2(-0.99,0.99), vec2(-0.99,-0.99), vec2(0.99,-0.99), AddthisdrawArrays()commandtodrawthefournewpoints: gl.drawArrays(gl.LINE_LOOP,3,4);//Startatthefourthvertex,drawfourvertices Colourthetriangleandrectanglewiththecoloursofyourchoice.AddglUniform*()commands,orset upandloadacoloursarrayasappropriatetoaccomplishthistask. YoumayremovethedrawArrays()commandthatdrawsthetriangle.Pleaseleave therectangleborderin place. Consultthemarkingschemetoseewhatelsetodo. Markingschemeanddetailsofassignment: /6-Drawapicturethatcontainsatleastthree ofthevariousOpenGLprimitives.Itshouldlookverydifferentfrom anyin-labdemonstrations. mustusePOINTS mustuseatleastonelinetype:eitherLINES, LINE_STRIP,orLINE_LOOP(notincludingthe lineloopinthe instructionsabove) mustuseatleastonepolygontype:eitherTRIANGLES,TRIANGLE_STRIP,or TRIANGLE_FAN(notincludinganygeometryusedasanin-labdemo) /3-Useatleast3differentcolours.Dothiswithauniformshadervariableoravertexcolourarray input. /2-Useatleasttwopointsizes.Auniformmustbesetuptoallowyoutosetthepointsizefrom Javascript. /2-Writecodethatwoulddrawatleasttwodifferentlinesizes.Tellmeinacommentwhetherornotit worked,andonwhatOS+graphicscardcombination. /5-Artisticimpression-yourdrawingshouldresemble somethingandreflectsomeeffort. Protip:thecirclefunctionshowninthelabnotescaneasilybemodifiedcreatepointsforarbitrarily sizedandcenteredcircles.Usingdifferentsidesargumentsyoucandraw triangles,squares,pentagons, hexagons,etc.Youcanlearnthesizeofthearrayyougetbackwithits.length member.Youcancreate asamesizecolourarraywithaloop.Youcanconcatenateitwithotherarraystoaddittoyourarraybuffers. ItspointsshouldworkwellwithbothLINE_LOOPandTRIANGLE_FAN.TRIANGLESmightproduceaneateffecttoo... (18markstotal) Samplesofpreviouswork.Yourworkwill endupinthegallery,sopayattentiontoartisticimpression. Deliverables WhatIwantinzippedformat: Yourcode+anysupportingfiles(forinstance,ifyouputcustomfunctionsorpointsarraysinseparate.js files) Animageofyourfinalproduct BONUS:Addatleastoneextrausefuluniformtoyourprogram.Youcouldusesuchuniformstoadjustthe position,sizeorrotationofobjectsyoudrawwithdrawcommands.Trysomething.Ilikebeingsurprised.
延伸文章資訊
- 1Drawing A Line Using gl.LINES - WebGL Programming
- 2WebGL2 Points, Lines, and Triangles
WebGL2 Points, Lines, and Triangles · POINTS. For each clip space vertex output by the vertex sha...
- 3How 2 draw lines in
How to draw line in WebGL. ○ drawArrays , LINE_STRIP ... For framebuffers - only in WebGL2 ... 20...
- 4WebGL - Modes of Drawing - Tutorialspoint
In addition to triangles, WebGL supports various other drawing modes. Thi. ... To draw a series o...
- 5WebGL2 Drawing Without Data
In GLSL ES 3.0 there is a special variable, gl_VertexID available in vertex shaders. Effectively ...