Intro to WebGL Using Angular- How to Set Up a Scene (Part 1)

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

In this article, we're going to setup WebGL within a typical Angular app by utilising the HTML5 canvas ... The source code for this tutorial is available at ... Skiptothecontent CloseMenu Whatwedo Ourwork Whoweare Blog GetinTouch Overview WebGL hastobeoneofthemostunder-usedJavaScriptAPIswithinmodernwebbrowsers. Itoffersrenderinginteractive2Dand3Dgraphicsandisfullyintegratedwithotherwebstandards,allowingGPU-acceleratedusageofphysicsandimageprocessingeffectsaspartofthewebpagecanvas (Wikipedia,2020). Inthisarticle,we’regoingtosetupWebGLwithinatypical Angular appbyutilisingthe HTML5canvaselement. Prerequisites Beforestarting,itsworthwhiletoensureyoursystemissetupwiththefollowing: Nodejs isinstalledYouhave setup aneworexistingAngularappYouareusingamodernwebbrowser(Chrome56+,Firefox51+,Opera43+,Edge10240+) WebGLFundamentals There’shonestlyalottotakeinregardstothefundamentalsofWebGL(andmorespecificallyOpenGL).Itdoesmeanthatyou’llneedtohavesomebasicunderstandingoflinearalgebraand2d/3drenderingingeneral. WebGLFundamentals doesagreatjobatprovidinganintroductiontoWebGLfundamentalsandI’llbereferencingtheirdocumentationaswestepthroughsettingupourAngularapptouseWebGL. Beforegoinganyfurther,itsimportantthatyouunderstandthefollowingataminimum. WebGLis not a3DAPI.Youcan’tjustuseittoinstantlyrenderobjectsandmodelsandgetthemtodosomeawesomemagic. WebGLisjusta rasterizationengine.Itdrawspoints,linesandtrianglesbasedonthecodeyousupply. IfyouwantWebGLtodoanythingelse,itsuptoyoutowritecodethatusespoints,linesandtrianglestoaccomplishthetaskyouwant. WebGLrunsontheGPUandrequiresthatyouprovidecodethatrunsontheGPU.Thecodethatweneedtoprovideisintheformofpairsoffunctions. Theyareknownas: avertexshaderresponsibleforcomputingvertexpositions–basedonthepositions,WebGLcanthenrasterizeprimitivesincludingpoints,lines,ortriangles.afragmentshaderwhenprimitivesarebeingrasterized,WebGLcallsthefragmentshadertocomputeacolourforeachpixeloftheprimitivethat’scurrentlybeingdrawn. EachshaderiswritteninGLSLwhichisastrictlytypedC/C++likelanguage.Whenavertexandfragmentshaderarecombined,they’recollectivelyknownasa program. NearlyalloftheentireWebGLAPIisaboutsettingupstateforthesepairsoffunctionstorun.Foreachthingyouwanttodraw,yousetupabunchofstatethenexecuteapairoffunctionsbycalling gl.drawArrays or gl.drawElements whichexecutesyourshadersontheGPU. Anydatayouwantthosefunctionstohaveaccessto,mustbeprovidedtotheGPU.Thereare4waysashadercanreceivedata. AttributesandbuffersBuffersarearraysofbinarydatayouuploadtotheGPU.Usuallybufferscontainthingslikepositions,normals,texturecoordinates,vertexcolours,etcalthoughyou’refreetoputanythingyouwantinthem.Attributesareusedtospecifyhowtopulldataoutofyourbuffersandprovidethemtoyourvertexshader.Forexampleyoumightputpositionsinabufferasthree32bitfloatsperposition.Youwouldtellaparticularattributewhichbuffertopullthepositionsoutof,whattypeofdataitshouldpullout(3component32bitfloatingpointnumbers),whatoffsetinthebufferthepositionsstart,andhowmanybytestogetfromonepositiontothenext.Buffersarenotrandomaccess.Insteadavertexshaderisexecutedaspecifiednumberoftimes.Eachtimeit’sexecutedthenextvaluefromeachspecifiedbufferispulledoutandassignedtoanattribute.UniformsUniformsareeffectivelyglobalvariablesyousetbeforeyouexecuteyourshaderprogram.TexturesTexturesarearraysofdatayoucanrandomlyaccessinyourshaderprogram.Themostcommonthingtoputinatextureisimagedatabuttexturesarejustdataandcanjustaseasilycontainsomethingotherthancolours.VaryingsVaryingsareawayforavertexshadertopassdatatoafragmentshader.Dependingonwhatisbeingrendered,points,lines,ortriangles,thevaluessetonavaryingbyavertexshaderwillbeinterpolatedwhileexecutingthefragmentshader. (WebGLFundamentals,2015). I’mglossingoveralotoftechnicaldetailhere,butifyoureallywanttoknowmore,headoverto WebGLFundamentalslessons formoreinfo. Settingupaplayground Let’ssetupaplaygroundsowehavesomethingthatwecanuseinordertocontinuesettingupWebGL. First,createa component.YoucancreateonebyexecutingthefollowingcommandwithinyourAngularroot(src)directory.I’vegoneaheadandnamedmine scene. E.g. nggeneratecomponentscene PSX:\...\toucan-webgl>nggeneratecomponentscene CREATEsrc/app/scene/scene.component.html(20bytes) CREATEsrc/app/scene/scene.component.spec.ts(619bytes) CREATEsrc/app/scene/scene.component.ts(272bytes) CREATEsrc/app/scene/scene.component.scss(0bytes) PSX:\...\toucan-webgl> Let’s also create a service with the component and call it WebGL too. E.g. nggenerateservicescene/services/webGL PSX:\...\toucan-webgl>nggenerateservicescene/services/webGL CREATEsrc/app/scene/services/web-gl.service.spec.ts(352bytes) CREATEsrc/app/scene/services/web-gl.service.ts(134bytes) PSX:\...\toucan-webgl> Ifyou’reusinganewAngularapp,hopefullyyou’vealreadyconfiguredittouse AppRouting.Ifyouhaven’t,followthenextcoupleofsteps. nggeneratemoduleapp-routing--flat--module=app You’llnowhavean app-routing.module.ts file,ifyouhaven’tgotonealready. Updatethecontentsofthefilewiththefollowing: import{Routes,RouterModule}from"@angular/router"; import{SceneComponent}from"./scene/scene.component"; constroutes:Routes=[{path:"",component:SceneComponent}]; @NgModule({ imports:[RouterModule.forRoot(routes)], exports:[RouterModule], }) exportclassAppRoutingModule{} Thiswillensurethatonappload,it’lldisplaythe SceneComponent first. Next,addthe WebGLService tothe SceneComponent‘sconstructorlikeso: import{Component,OnInit}from"@angular/core"; import{WebGLService}from"./services/web-gl.service"; @Component({ selector:"app-scene", templateUrl:"./scene.component.html", styleUrls:["./scene.component.scss"], }) exportclassSceneComponentimplementsOnInit{ //***Updateconstructorhere*** constructor(privatewebglService:WebGLService){} ngOnInit():void{} } Finally,run ngserve andchecktoseeiftheAngularappisrunninganddisplayingthe SceneComponent.Itshouldlooklikethis: Now,letsmoveontoaddingaWebGLcontext. SettinguptheWebGLcontext SettinguptheWebGLcontextisalittlebitinvolvedbutoncewegetthefoundationgoingwecanthenproceedtostartgettingsomethingonthescreen. Let’sstartbyopeningup scene.component.html andaddaHTML5canvaselement. Yourbrowserdoesn'tappeartosupportthe element. Openup scene.component.scss (orequivalent)andaddinthefollowingstyles: .scene{ height:100%; width:100%; } .scenecanvas{ height:100%; width:100%; border-style:solid; border-width:1px; border-color:black; } Thefollowingcssshouldjustmakesurethecanvaselementextendstothesizeofthebrowserwindow.Ijustaddedsomeborderstylingsoyoucanexplicitlyseeitforyourself. TIP:Ifyouwant,youcanalsoupdatetheglobal styles.scss soallcontentexpandstotheheightofthewindowrespectively. styles.scss /*Youcanaddglobalstylestothisfile,andalsoimportotherstylefiles*/ html, body{ height:99%; } We’llnowembarkondoingthefollowing: Resolvingthecanvaselementintypescriptviathe #canvas idBindingthecanvaselementtoaWebGLrenderingcontextInitializetheWebGLrenderingcanvas Resolvingthecanvaselement Open scene.component.ts andaddthefollowingproperty: @ViewChild('sceneCanvas')privatecanvas:HTMLCanvasElement; Updateyourthe SceneComponent classtoimplement AfterViewInit,we’llneedtohookintothislifecyclehooktocontinuesettinguptheWebGLcanvas. Addinthefollowingguardtothe ngAfterViewInit methodtoensurethatweactuallyhavethecanvaselementbeforeattemptingtobindit: if(!this.canvas){ alert("canvasnotsupplied!cannotbindWebGLcontext!"); return; } NOTE:Ifthealertishit,it’sduetothefactthatthe ElementRef IDyou’reusingdoesmatchtheonedefinedinHTMLandtheTSclass.Youneedtoensuretheymatch. Yourcomponentimplementationshouldnowlooklikethis: import{AfterViewInit,Component,OnInit,ViewChild}from"@angular/core"; import{WebGLService}from"./services/web-gl.service"; @Component({ selector:"app-scene", templateUrl:"./scene.component.html", styleUrls:["./scene.component.scss"], }) exportclassSceneComponentimplementsOnInit,AfterViewInit{ @ViewChild("sceneCanvas")privatecanvas:HTMLCanvasElement; constructor(privatewebglService:WebGLService){} ngAfterViewInit():void{ if(!this.canvas){ alert("canvasnotsupplied!cannotbindWebGLcontext!"); return; } } ngOnInit():void{} } BindingthecanvaselementtoaWebGLrenderingcontext Openupthe web-gl.service.ts file. Createamethodcalled initialiseWebGLContext withaparameter canvas:HTMLCanvasElement. initialiseWebGLContext(canvas:HTMLCanvasElement){ } Gobackto scene.component.ts andaddinthefollowinglineaftertheguardcheckin ngAfterViewInit. ngAfterViewInit():void{ if(!this.canvas){ alert('canvasnotsupplied!cannotbindWebGLcontext!'); return; } this.webglService.initialiseWebGLContext(this.canvas.nativeElement); } Now,backin web-gl.service.ts,letsretrieveaWebGLcontextfromthecanvas’snativeelementandreferenceittoapropertythatwe’llcall gl. private_renderingContext:RenderingContext; privategetgl():WebGLRenderingContext{ returnthis._renderingContextasWebGLRenderingContext; } constructor(){} initialiseWebGLContext(canvas:HTMLCanvasElement){ //Trytograbthestandardcontext.Ifitfails,fallbacktoexperimental. this._renderingContext=canvas.getContext('webgl')||canvas.getContext('experimental-webgl'); //Ifwedon'thaveaGLcontext,giveupnow...onlycontinueifWebGLisavailableandworking... if(!this.gl){ alert('UnabletoinitializeWebGL.Yourbrowsermaynotsupportit.'); return; } } Oncewe’veretrievedthe WebGLRenderingContext,wecanthensettheWebGLcanvas’sheightandwidth,andthenfinallyproceedtoinitialisetheWebGLcanvas. Letsadd two methodswhichdothatIdescribedabove: setWebGLCanvasDimensions(canvas:HTMLCanvasElement){ //setwidthandheightbasedoncanvaswidthandheight-goodpracticetouseclientWidthandclientHeight this.gl.canvas.width=canvas.clientWidth; this.gl.canvas.height=canvas.clientHeight; } initialiseWebGLCanvas(){ //Setclearcolourtoblack,fullyopaque this.gl.clearColor(0.0,0.0,0.0,1.0); //Enabledepthtesting this.gl.enable(this.gl.DEPTH_TEST); //Nearthingsobscurefarthings this.gl.depthFunc(this.gl.LEQUAL); //Clearthecolouraswellasthedepthbuffer. this.gl.clear(this.gl.COLOR_BUFFER_BIT|this.gl.DEPTH_BUFFER_BIT); } Nowfinallycallthemattheendofthe initialiseWebGLContext method. initialiseWebGLContext(canvas:HTMLCanvasElement){ //Trytograbthestandardcontext.Ifitfails,fallbacktoexperimental. this._renderingContext= canvas.getContext('webgl')||canvas.getContext('experimental-webgl'); //Ifwedon'thaveaGLcontext,giveupnow...onlycontinueifWebGLisavailableandworking... if(!this.gl){ alert('UnabletoinitializeWebGL.Yourbrowsermaynotsupportit.'); return; } //***setwidth,heightandinitialisethewebglcanvas*** this.setWebGLCanvasDimensions(canvas); this.initialiseWebGLCanvas(); } Runtheappagain,youshouldnowseethatthecanvasisentirelyblack. Thisshowsthatwe’vesuccessfullyinitialisedtheWebGLcontext. Thatsitforpart1! Next:IntroductiontoWebGLusingAngular–Part2–Settingupshadersandatriangle Inpart2,we’llproceedtoaddinshadersandstartsettingupcontenttorenderonscreen! Staytuned! Thesourcecodeforthistutorialisavailableathttps://gitlab.com/MikeHewett/intro-webgl-part-1.git References https://en.wikipedia.org/wiki/WebGLhttps://webglfundamentals.org/https://angular.io/docshttp://www.codinglabs.net/article_world_view_projection_matrix.aspx Tags Angular8,API,JavaScript,WebGL 5 4 votes ArticleRating Subscribe Login Notifyof newfollow-upcomments newrepliestomycomments Pleaselogintocomment 0Comments InlineFeedbacks Viewallcomments Youmightalsolike... Blog IntrotoWebGLusingAngular–HowtoBuildin3D(Part3) Blog IntrotoWebGLusingAngular-HowtoSetupandCompileShaders(Part2) Blog SwiftStack:BeaFullStackSwiftDeveloper(PartOne) AboutDigizoo We’reateamofbankingproductstrategists,designers,developers,andengineers. ReadmoreaboutWhoweare LinkedIn Findus Level2 63YorkStreet Sydney,NSW,2000Australia ViewonGoogleMaps wpDiscuzInsert



請為這篇文章評分?