HTML5 3D Canvas Tutorial - Web Code Geeks - 2022

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

The canvas element was one of the most expected novelties of HTML5. This element allows us to draw dynamically images in a webpage, usually done ... Home»HTML5»HTML53DCanvasTutorialAboutToni HTML53DCanvasTutorial Postedby:Toni inHTML5 April11th,2017 1Comment ViewsOneofthemostexpectedfeaturesofHTML5wastheintroductionofthecanvaselement,allowingtodrawgraphicsonit.Thistutorialwillshowhowtodraw3Dfiguresonit,butstartingfromtheverybeginning,inordertounderstandwhatweareactuallydoing.AsitisanHTMLexample,wewon’tneedanywebserverorback-endlanguageinstalledinourmachine,justawebbrowser.             Forthisexample,thefollowingbrowsershavebeenusedfortesting:Chromium 56.0.2924.76.Firefox52.0.1.Opera44.0.TableOfContents1.Thecanvaselement 2.IntroducingtheWebGL     2.1.UnderstandingWebGL     2.2.InitializingWebGL     2.3.2Ddrawing 3.Three.js   3.1. 3Drotatingcube   3.2.Thecode 4.Summary 5.Downloadthesourcecode1.ThecanvaselementBeforedivingintothe3Danimations,weneedtounderstandtheelementitrelieson:thecanvas.ThecanvaselementwasoneofthemostexpectednoveltiesofHTML5.Thiselementallowsustodrawdynamicallyimagesinawebpage,usuallydonewithJavaScriptincombinationwiththecanvasAPI.Assaid,theelementwehavetouseiscanvas.So,somethinglikethefollowingwouldbeenoughtostart:1_canvas.html

Canvasexample

Canvasexample

Thiswillrenderawhitecanvasinthebrowserof500×300(withtheblackbordersetwiththeCSS).Nothingveryexciting.But,nowthatwehaveourcanvas,wecan drawonit.Let’sseehowtodrawsomesimplerectangleswithJavaScripttoseethemostelementalcanvasfunctions.1_canvas.jsdocument.addEventListener('DOMContentLoaded',function(event){ varcanvas=document.getElementById('canvas'); varcontext=canvas.getContext('2d'); if(context){ context.fillRect(0,0,500,300); context.fillStyle='#a5d8d7'; context.fillRect(100,50,300,200); } });PD:donotforgettoincludethescriptintheHTMLpage: ThefirstthingwedoistobindthepieceofcodethatmanipulatesthecanvastotheDOMContentLoadedlistener,sincewehavetobesurethattheelementsareloadedbeforeweaccessthem.Then,wegetthecanvasobjectfromtheDOM.But,fordrawingonit,weneedtogettherendercontextofthecanvas,inthiscase,stillthe2Dcontext.Thiscontextoffersthemethodfordrawinginthecanvas.ThefillRectmethodfillsthecanvasfromthestartingX,Ycoordinates,totheendingX,Yones,withthegivencolor.So,forthisinstruction:context.fillRect(0,0,500,300); Wouldfillthecanvas,intheXaxis,fromthepoint0to500(firstandthirdparameters,respectively);andintheYaxis,fromthepoint0tothe300(secondandfourthparameters,respectively).Asanycolorwasset,itwillbefilledwiththedefaultone,black.Afterthatwedothesame,butsettingadifferentcolorforthefill,andforanothercoordinates.Theresultisshowninthefollowingimage:1.Renderingofthecanvasoftheabovecode.2.IntroducingtheWebGLAfterseeinghowworksthecanvaselementatitmostbasiclevel,it’stimetointroduceWebGL.Forthe3Danimationswiththecanvas,wedon’thavetogetthe3dcontext,asyoumayhavethought.Instead,wehavetogetthewebglcontext,whichissupported,atleastpartially,byeverymodernwebbrowser(seenextimage).2.WebGLsupportbybrowsers.Brightgreen:supported;green:partiallysupported;red:notsupported.Source:http://caniuse.com.2.1.UnderstandingWebGLWebGLisnotjustaboutdrawingsomespecificpixels onacanvas.Inorderto drawanimage,wehavetodefineaspatialvectorthatrepresentstheimage,whichwillbeconverted,usingtheOpenGLspecification,toitspixelrepresentation.Thismaysoundscary,andthat’swhywemustunderstandthewholeprocessinordertowriteWebGLapplications.2.1.1.CoordinatesystemBeingathree-dimensionalsystem,wehavethreeaxes:X,Y,andZ,beingthelastonethedepth.InWebGL,thecoordinatesarelimitedto(1,1,1)and(-1,-1,-1).Wehavetounderstandthat,whenwedefinefigures,wedon’thavetothinkinpixels,butinvector representationsinacoordinatesystemwithinacartesiansystem.3.Cartesiancoordinatesystem.CreativeCommons.Imaginethesystemlikeintheimageabove(that’sactuallywhatwearegoingtodealwith).Thedrawnpoint,(x,y,z),isrepresentedbythe coordinatesintheX,YandXaxes.Nowlet’ssupposethatwewanttobuildacube,andthatthecoordinatescommentedaboveareforoneoftheboundsoftheWebGLsystem.Thatcoordinatewouldbe(1,1,1).Thatmeansthatwehavejustoneofthe cornersofthecube,andacubehas8corners.Soweneedseveralmorecoordinates.Theothercoordinateswouldbe(1,1,-1),(1,-1,-1),(1,-1,1),(-1,-1,-1),(-1,1,-1),(-1,1,1)and(-1,-1,1).Tracingthevortexes betweenthesecoordinates,wewoulddefinethe volumeofthecube.Thismightbeeasiertounderstandintheseconddimension,justwiththeXandYaxes,wheretheunderlyingprincipleisthesame.Supposethreecoordinates,e.g.(0.8,0),(0,1)and(1,0.8).Withthisvortexes,wewoulddrawatrianglelikeinthefollowingimage.4.Threepointsformingatriangle.CreativeCommons.Assaid,theprincipleisthesameasforthethree-dimensionalfigureswithathirdaxis,buteasiertounderstandifthepreviousexamplewasconfusing.2.1.2.ShadersTheshadersarepiecesofcode thatareexecutedintheGPUforrepresentingeachpixelthatwillmakeupthefinalscene.Therearetwotypesofshaders:Vertexshader:thisone,asyouwillprobablyhavealreadyguessed,istheresponsibleformanipulatingandrepresentingthevertexes,calculatingthetextureandthepositionofeachvertex,amongotherthings.Fragment shader:thisonemanipulateseachpixelthatcomposetheareaboundedbythevertexes.Note:thesepiecesofcodearenotwritteninJavaScript,butinscripttypeknownas x-shader/x-vertex.Wewillseeitlater.2.2.InitializingWebGLKnowingthattherearesomebrowserswithjustpartialsupport,weshouldimplementafallbackforthebrowserthatdonotofferfullsupport.Thisisactuallyveryeasy.ThefollowingscriptwilltellusifourbrowseriscompatiblyornotwithWebGL:varwebgl=canvas.getContext('webgl') ||canvas.getContext('experimental-webgl'); if(!webgl||!(webglinstanceofWebGLRenderingContext)){ alert('FailedtogetWebGLcontext.'); }else{ alert('Great,yourbrowsersupportsWebGL.'); }Asyoucansee,it’salmostassameaswiththe2Dcontext.But,inthiscasewetrytogetthemainWebGL, or,theexperimentalone,ifthefirstonefails(i.e.returnsfalse).After,wecheckiftheexperimentalWebGLretrievalalsofailed,checkingalsothateffectivelythereturnedobjectisaninstanceoftheWebGLRenderingContext.2.3.2DdrawingYes,wehavealreadyseenhowtodrawin2dimensions,butthatwaswithadifferentcontext,withtheaimofunderstandingthebasicsofthecanvaselement.Thepreviousobvioussteptothe3rddimension,isthe2ndone.Startingdirectlydrawingin3D,mayresultinnotactuallyunderstandingthefunctioningoftheWebGL.So,let’sdrawatriangleasinthepreviouspicture.5.DrawingwithWebGLthetriangleshowninthepreviouspicture.Thefollowingcodewillshowourscriptatthehigherlevel,justshowingthefunctionswehavecreatedforrenderingthefigure.varvortexes=[ 0.8,0.0, 0.0,1, 1,0.8 ]; webgl=getWebGL(); if(webgl){ initWebGL(webgl,vortexes); varvertexShader=createVertexShader(); varfragmentShader=createFragmentShader(); varshaderProgram=createShaderProgram(webgl,vertexShader,fragmentShader); transformCoordinatesAndSet(webgl,shaderProgram); drawArrays(webgl); }Asyoucansee,wehavejust:definedthevortexesofthetriangle(thesamevaluesasusedforthepictureoftheprevioussection),inittheWebGL,createthevertexandfragmentshaders,createtheshader“program”fromtheshaders,setthespecifiedcoordinates,anddrawthearrays.So,thefullscriptwouldbe:2_webgl.jsdocument.addEventListener('DOMContentLoaded',function(event){ /** *InitstheWebGLorreturnsfalseifitcouldn'tbeloaded. */ functiongetWebGL(){ varcanvas=document.getElementById('canvas'); varwebgl=canvas.getContext('webgl') ||canvas.getContext('experimental-webgl'); if(!webgl||!(webglinstanceofWebGLRenderingContext)){ returnfalse; } returnwebgl; } /** *Createsthevertexbuffer,bindsit,passesthevortexdatatoit, *andsetsthecolor. */ functioninitWebGL(webgl,vortexes){ varvertexBuffer=webgl.createBuffer(); webgl.bindBuffer(webgl.ARRAY_BUFFER,vertexBuffer); webgl.bufferData( webgl.ARRAY_BUFFER, newFloat32Array(vortexes), webgl.STATIC_DRAW ); webgl.clearColor(0,0.5,0.5,0.9); webgl.clear(webgl.COLOR_BUFFER_BIT); } /** *Createsthevertexshaderobjectfromthesourcecodedefinedin *2_vertex_shader.js. */ functioncreateVertexShader(){ varvertexShader=webgl.createShader(webgl.VERTEX_SHADER); webgl.shaderSource(vertexShader,vertexCode); webgl.compileShader(vertexShader); returnvertexShader; } /** *Createsthefragmentshaderobjectfromthesourcecodedefinedin *2_vertex_shader.js. */ functioncreateFragmentShader(){ varfragmentShader=webgl.createShader(webgl.FRAGMENT_SHADER); webgl.shaderSource(fragmentShader,fragmentCode); webgl.compileShader(fragmentShader); returnfragmentShader; } /** *Createandattachtheshaderprogramsfromtheshadercompiledobjects. */ functioncreateShaderProgram(webgl,vertexShader,fragmentShader){ varshaderProgram=webgl.createProgram(); webgl.attachShader(shaderProgram,vertexShader); webgl.attachShader(shaderProgram,fragmentShader); webgl.linkProgram(shaderProgram); webgl.useProgram(shaderProgram); returnshaderProgram; } /** *Getsandsetsthecoordinatesassociatingthecompiledshaderprograms *tobufferobjects. */ functiontransformCoordinatesAndSet(webgl,shaderProgram){ varcoordinates=webgl.getAttribLocation( shaderProgram, 'coordinates' ); webgl.vertexAttribPointer( coordinates, 2, webgl.FLOAT, false, 0, 0 ); webgl.enableVertexAttribArray(coordinates); } /** *Drawsthearrays. */ functiondrawArrays(webgl){ webgl.drawArrays(webgl.TRIANGLES,0,3); } varvortexes=[ 0.8,0.0, 0.0,1, 1,0.8 ]; webgl=getWebGL(); if(webgl){ initWebGL(webgl,vortexes); varvertexShader=createVertexShader(); varfragmentShader=createFragmentShader(); varshaderProgram=createShaderProgram(webgl,vertexShader,fragmentShader); transformCoordinatesAndSet(webgl,shaderProgram); drawArrays(webgl); } });Rememberthatwetoldbeforethattheshaderswerepiecesthathavetobecompiled.Notethat,inthecodeabove,wehaven’tdefinedfragmentCode (line44)norvertexCode (line57).Thesearethepiecesofcodeforthefragment,whichwedefinedinseparatedfiles:fragment_shader.jsvarfragmentCode=` voidmain(void){ gl_FragColor=vec4( 0.0, 0.0, 0.0, 0.1 ); }` ;vertex_code.jsvarvertexCode=` attributevec2coordinates; voidmain(void){ gl_Position=vec4( coordinates, 0.0, 1.0 ); }` ;PD:don’tforgettoaddthecodetotheHTMLpage: Wow,thatwastomuchcodefordrawingasimpletriangle,wasn’tit?Imagineforananimated3Dfigure…Fortunately,fordoingthis,wewillusealibrarythatwillmakeourliveseasier.3.Three.jsWehaveseenhowtodealwithWebGLatthelowestlevel.Andperhaps,wegotdisappointed:toomuchwork,toomuchcode,forthesimplesttask.Asalreadycommented,fortunately,therearelibrariesavailablefordrawing3Dfiguresthatwillsavemuchtime,besidesbeingeasier.Probablythemostknownisthree.js,whichitssimplicityisfascinating,moreafterdealingwithnativeWebGL.Forusingit,wejusthavetodownloadthelatestminifiedbuild (morethan500kb!).Forthiscase,theversionr84hasbeenused.3.1. 3DrotatingcubeBeforeseeingthecode,let’sseewhatwearegoingtoachieve.Wewilldrawa3Dcube,whichwillrotateinbothXandYaxes.Thefollowingimageshowsit,statically,butitwillactuallyrotate!6.CuberotatinginXandYaxes(staticimage).3.2.ThecodeWewillworkinthesamecodebase.Justdon’tforgettoincludethethree.jslibrary.Thecodefordrawingthepreviousanimatedcubeisthefollowing:3_three.jsdocument.addEventListener('DOMContentLoaded',function(event){ window.requestAnimationFrame=(function(){ returnwindow.requestAnimationFrame; })(); functionanimateScene(){ requestAnimationFrame(animateScene); cube.rotation.y+=0.02; cube.rotation.x+=0.01; renderScene(); } functioncreateCube(){ varcubeMaterials=[ newTHREE.MeshBasicMaterial({color:0x2173fd}), newTHREE.MeshBasicMaterial({color:0xd5d918}), newTHREE.MeshBasicMaterial({color:0xd2dbeb}), newTHREE.MeshBasicMaterial({color:0xa3a3c6}), newTHREE.MeshBasicMaterial({color:0xfe6b9f}), newTHREE.MeshBasicMaterial({color:0x856af9}) ]; varcubeMaterial=newTHREE.MeshFaceMaterial(cubeMaterials); varcubeGeometry=newTHREE.BoxGeometry(2,2,2); cube=newTHREE.Mesh(cubeGeometry,cubeMaterial); returncube; } functionstartScene(cube){ varcanvas=document.getElementById('canvas'); render=newTHREE.WebGLRenderer(); render.setClearColor(0x000000,1); varcanvasWidth=canvas.getAttribute('width'); varcanvasHeight=canvas.getAttribute('height'); render.setSize(canvasWidth,canvasHeight); canvas.appendChild(render.domElement); scene=newTHREE.Scene(); varaspect=canvasWidth/canvasHeight; camera=newTHREE.PerspectiveCamera(45,aspect); camera.position.set(0,0,0); camera.lookAt(scene.position); scene.add(camera); cube.position.set(0,0,-7.0); scene.add(cube); } functionrenderScene(){ render.render(scene,camera); } varcube=createCube(); startScene(cube); animateScene(); renderScene(); });CreatingthecubeCreatingthecube(line15)issosimple.Wejustcreateanarraywherewedefineeachside(6intotal),specifyingthematerialofeachside,andthecolorofit.StartingthesceneThefunctioninline33.Forstartingthescene,wealsohavetosettherenderandthecamera.Fortherender,weinstantiatetheTHREE.WebGLRendererclass,setaclearcolor(black),defineitsdimensions(whicharealreadydefinedinthecanvaselementintheHTML),andappenditasachildtothecanvas.Forthecamera,inthiscase,weinstantiatethe THREE.PerspectiveCameraclass,passing2parameters:Thefirstparameterdefinesthevisualfieldofthecamera,indegrees.So,settingitto45,wouldbelikelookingtothecubebeinginfrontofit.Thesecondoneistheaspectratio.Forthis,generally,wewillwanttosetthewidthoftheelementdividedbytheheight.Otherwise,theimagewilllookdeformed.Then,wesetthecamerainacertainposition,wetellittolookatthepositionoftheinstantiatedscene,andweaddthecameratothescene.Finally,wecanaddthecubetothescene.AnimatingthesceneForanimatingthescene(line6),wehavetodoitrequestingtheanimationframetothebrowser.Toit,wepassthefunctiontobeexecutedascallback,whichistheoneofanimatingthescene.RenderingthesceneRenderingthesceneconsistsjustoncallingtherendermethodoftherenderobject,passingthesceneandthecamera.4.SummaryInthistutorialwehaveseenhowtodrawa3Dimage(thatalsorotates),usingtheHTML5canvaselementandthethree.jslibrary,but,alsoseeinghowtocreategraphicsfromthescratch,fundamentalforunderstandinghowdoestheWebGLandcanvaswork.5.DownloadthesourcecodeThiswasatutorialof HTML53Dcanvas.Download Youcandownloadthefullsourcecodeofthisexamplehere: HTML53DTutorial 2017-04-11Toni (0rating,0votes)Youneedtobearegisteredmembertoratethis.1Comment Views Tweetit!DoyouwanttoknowhowtodevelopyourskillsettobecomeaWebRockstar?SubscribetoournewslettertostartRockingrightnow!TogetyoustartedwegiveyouourbestsellingeBooksforFREE!1.BuildingwebappswithNode.js2.HTML5ProgrammingCookbook3.CSSProgrammingCookbook4.AngularJSProgrammingCookbook5.jQueryProgrammingCookbook6.BootstrapProgrammingCookbookandmanymore....IagreetotheTermsandPrivacyPolicySignupLikeThisArticle?ReadMoreFromWebCodeGeeks SubscribeNotifyof newfollow-upcommentsnewrepliestomycomments Label {} [+] Name* Email* Website IagreetotheTermsandPrivacyPolicy Thecommentformcollectsyourname,emailandcontenttoallowuskeeptrackofthecommentsplacedonthewebsite.PleasereadandacceptourwebsiteTermsandPrivacyPolicytopostacomment. Label {} [+] Name* Email* Website IagreetotheTermsandPrivacyPolicy Thecommentformcollectsyourname,emailandcontenttoallowuskeeptrackofthecommentsplacedonthewebsite.PleasereadandacceptourwebsiteTermsandPrivacyPolicytopostacomment. ThissiteusesAkismettoreducespam.Learnhowyourcommentdataisprocessed. 1Comment Oldest Newest MostVotedInlineFeedbacksViewallcomments DimitriosKalemis 4yearsago Neartheendof3_three.js,afteranimateScene()iscalled,renderScene()iscallednext.ButanimateScene()alreadycallsrenderScene()asitslastinstruction. 3 ReplyNewsletterInsidersarealreadyenjoyingweeklyupdatesandcomplimentarywhitepapers!JointhemnowtogainexclusiveaccesstothelatestnewsintheWebdevelopersworld,aswellasinsightsaboutHTML5,CSS,JavaScript,WordPressandotherrelatedtechnologies.IagreetotheTermsandPrivacyPolicySignupJoinUs With1,240,600monthlyuniquevisitorsandover500authorsweareplacedamongthetopWebresourcesanddevelopmentsitesaround.Constantlybeingonthelookoutforpartners;weencourageyoutojoinus.SoIfyouhaveablogwithuniqueandinterestingcontentthenyoushouldcheckoutourWCGpartnersprogram.YoucanalsobeaguestwriterforWebCodeGeeksandhoneyourwritingskills! WebCodeGeeksandallcontentcopyright©2010-2022,ExelixisMediaP.C.|TermsofUse|PrivacyPolicy|Contact wpDiscuzInsert


請為這篇文章評分?