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