Buffers are arrays of binary data you upload to the GPU. ... This tells WebGL we want to get data out of a buffer. If we don't turn on the attribute then ...
English
Deutsch
日本語
한국어
PortuguêsBrasileiro
简体中文
TableofContents
WebGL2Fundamentals.org
Fix,Fork,Contribute
WebGL2Fundamentals
Firstthingsfirst,thesearticlesareaboutWebGL2.Ifyou'reinterestedinWebGL1.0
pleasegohere.NotethatWebGL2isnearly100%backward
compatiblewithWebGL1.Thatsaid,onceyouenable
WebGL2youmightaswelluseitasitwasmeanttobeused.Thesetutorialsfollow
thatpath.
WebGLisoftenthoughtofasa3DAPI.Peoplethink"I'lluseWebGLandmagicI'llgetcool3d".
InrealityWebGLisjustarasterizationengine.Itdrawspoints,lines,andtrianglesbased
oncodeyousupply.GettingWebGLtodoanythingelseisuptoyoutoprovidecodetousepoints,lines,
andtrianglestoaccomplishyourtask.
WebGLrunsontheGPUonyourcomputer.AssuchyouneedtoprovidethecodethatrunsonthatGPU.
Youprovidethatcodeintheformofpairsoffunctions.Those2functionsarecalledavertexshader
andafragmentshaderandtheyareeachwritteninaverystrictlytypedC/C++likelanguagecalled
GLSL.(GLShaderLanguage).Pairedtogethertheyarecalledaprogram.
Avertexshader'sjobistocomputevertexpositions.Basedonthepositionsthefunctionoutputs
WebGLcanthenrasterizevariouskindsofprimitivesincludingpoints,lines,ortriangles.
Whenrasterizingtheseprimitivesitcallsasecondusersuppliedfunctioncalledafragmentshader.
Afragmentshader'sjobistocomputeacolorforeachpixeloftheprimitivecurrentlybeingdrawn.
NearlyalloftheentireWebGLAPIisaboutsettingupstateforthesepairsoffunctionstorun.
Foreachthingyouwanttodrawyousetupabunchofstatethenexecuteapairoffunctionsbycalling
gl.drawArraysorgl.drawElementswhichexecutesyourshadersontheGPU.
AnydatayouwantthosefunctionstohaveaccesstomustbeprovidedtotheGPU.Thereare4ways
ashadercanreceivedata.
Attributes,Buffers,andVertexArrays
BuffersarearraysofbinarydatayouuploadtotheGPU.Usuallybufferscontain
thingslikepositions,normals,texturecoordinates,vertexcolors,etcalthough
you'refreetoputanythingyouwantinthem.
Attributesareusedtospecifyhowto
pulldataoutofyourbuffersandprovidethemtoyourvertexshader.
Forexampleyoumightputpositionsinabufferasthree32bitfloats
perposition.Youwouldtellaparticularattributewhichbuffertopullthepositionsoutof,whattype
ofdataitshouldpullout(3component32bitfloatingpointnumbers),whatoffset
inthebufferthepositionsstart,andhowmanybytestogetfromonepositiontothenext.
Buffersarenotrandomaccess.Insteadavertexshaderisexecutedaspecifiednumber
oftimes.Eachtimeit'sexecutedthenextvaluefromeachspecifiedbufferispulled
outandassignedtoanattribute.
Thestateofattributes,whichbufferstouseforeachone,andhowtopulloutdata
fromthosebuffersiscollectedintoavertexarrayobject(VAO).
Uniforms
Uniformsareeffectivelyglobalvariablesyousetbeforeyouexecuteyourshaderprogram.
Textures
Texturesarearraysofdatayoucanrandomlyaccessinyourshaderprogram.Themost
commonthingtoputinatextureisimagedatabuttexturesarejustdataandcanjust
aseasilycontainsomethingotherthancolors.
Varyings
Varyingsareawayforavertexshadertopassdatatoafragmentshader.Depending
onwhatisbeingrendered,points,lines,ortriangles,thevaluessetonavarying
byavertexshaderwillbeinterpolatedwhileexecutingthefragmentshader.
WebGLHelloWorld
WebGLonlycaresabout2things.Clipspacecoordinatesandcolors.
YourjobasaprogrammerusingWebGListoprovideWebGLwiththose2things.
Youprovideyour2"shaders"todothis.AVertexshaderwhichprovidesthe
clipspacecoordinates,andafragmentshaderthatprovidesthecolor.
Clipspacecoordinatesalwaysgofrom-1to+1nomatterwhatsizeyour
canvasis.HereisasimpleWebGLexamplethatshowsWebGLinitssimplestform.
Let'sstartwithavertexshader
#version300es
//anattributeisaninput(in)toavertexshader.
//Itwillreceivedatafromabuffer
invec4a_position;
//allshadershaveamainfunction
voidmain(){
//gl_Positionisaspecialvariableavertexshader
//isresponsibleforsetting
gl_Position=a_position;
}
Whenexecuted,iftheentirethingwaswritteninJavaScriptinsteadofGLSL
youcouldimagineitwouldbeusedlikethis
//***PSEUDOCODE!!***
varpositionBuffer=[
0,0,0,0,
0,0.5,0,0,
0.7,0,0,0,
];
varattributes={};
vargl_Position;
drawArrays(...,offset,count){
varstride=4;
varsize=4;
for(vari=0;i
TheninJavaScriptwecanlookthatup
varcanvas=document.querySelector("#c");
NowwecancreateaWebGL2RenderingContext
vargl=canvas.getContext("webgl2");
if(!gl){
//nowebgl2foryou!
...
NowweneedtocompilethoseshaderstoputthemontheGPUsofirstweneedtogetthemintostrings.
YoucancreateyourGLSLstringsanywayyounormallycreatestringsinJavaScript.Forexamplebyconcatenating,
byusingAJAXtodownloadthem,byputtingtheminnon-javascriptscripttags,orinthiscasein
multilinetemplatestrings.
varvertexShaderSource=`#version300es
//anattributeisaninput(in)toavertexshader.
//Itwillreceivedatafromabuffer
invec4a_position;
//allshadershaveamainfunction
voidmain(){
//gl_Positionisaspecialvariableavertexshader
//isresponsibleforsetting
gl_Position=a_position;
}
`;
varfragmentShaderSource=`#version300es
//fragmentshadersdon'thaveadefaultprecisionsoweneed
//topickone.highpisagooddefault.Itmeans"highprecision"
precisionhighpfloat;
//weneedtodeclareanoutputforthefragmentshader
outvec4outColor;
voidmain(){
//Justsettheoutputtoaconstantreddish-purple
outColor=vec4(1,0,0.5,1);
}
`;
Infact,most3DenginesgenerateGLSLshadersontheflyusingvarioustypesoftemplates,concatenation,etc.
ForthesamplesonthissitethoughnoneofthemarecomplexenoughtoneedtogenerateGLSLatruntime.
NOTE:#version300esMUSTBETHEVERYFIRSTLINEOFYOURSHADER.Nocommentsor
blanklinesareallowedbeforeit!#version300estellsWebGL2youwanttouseWebGL2's
shaderlanguagecalledGLSLES3.00.Ifyoudon'tputthatasthefirstlinetheshader
languagedefaultstoWebGL1.0'sGLSLES1.00whichhasmanydifferencesandfarlessfeatures.
Nextweneedafunctionthatwillcreateashader,uploadtheGLSLsource,andcompiletheshader.
NoteIhaven'twrittenanycommentsbecauseitshouldbeclearfromthenamesofthefunctions
whatishappening.
functioncreateShader(gl,type,source){
varshader=gl.createShader(type);
gl.shaderSource(shader,source);
gl.compileShader(shader);
varsuccess=gl.getShaderParameter(shader,gl.COMPILE_STATUS);
if(success){
returnshader;
}
console.log(gl.getShaderInfoLog(shader));
gl.deleteShader(shader);
}
Wecannowcallthatfunctiontocreatethe2shaders
varvertexShader=createShader(gl,gl.VERTEX_SHADER,vertexShaderSource);
varfragmentShader=createShader(gl,gl.FRAGMENT_SHADER,fragmentShaderSource);
Wethenneedtolinkthose2shadersintoaprogram
functioncreateProgram(gl,vertexShader,fragmentShader){
varprogram=gl.createProgram();
gl.attachShader(program,vertexShader);
gl.attachShader(program,fragmentShader);
gl.linkProgram(program);
varsuccess=gl.getProgramParameter(program,gl.LINK_STATUS);
if(success){
returnprogram;
}
console.log(gl.getProgramInfoLog(program));
gl.deleteProgram(program);
}
Andcallit
varprogram=createProgram(gl,vertexShader,fragmentShader);
Nowthatwe'vecreatedaGLSLprogramontheGPUweneedtosupplydatatoit.
ThemajorityoftheWebGLAPIisaboutsettingupstatetosupplydatatoourGLSLprograms.
InthiscaseouronlyinputtoourGLSLprogramisa_positionwhichisanattribute.
Thefirstthingweshoulddoislookupthelocationoftheattributefortheprogram
wejustcreated
varpositionAttributeLocation=gl.getAttribLocation(program,"a_position");
Lookingupattributelocations(anduniformlocations)issomethingyoushould
doduringinitialization,notinyourrenderloop.
Attributesgettheirdatafrombufferssoweneedtocreateabuffer
varpositionBuffer=gl.createBuffer();
WebGLletsusmanipulatemanyWebGLresourcesonglobalbindpoints.
YoucanthinkofbindpointsasinternalglobalvariablesinsideWebGL.
Firstyoubindaresourcetoabindpoint.Then,allotherfunctions
refertotheresourcethroughthebindpoint.So,let'sbindthepositionbuffer.
gl.bindBuffer(gl.ARRAY_BUFFER,positionBuffer);
Nowwecanputdatainthatbufferbyreferencingitthroughthebindpoint
//three2dpoints
varpositions=[
0,0,
0,0.5,
0.7,0,
];
gl.bufferData(gl.ARRAY_BUFFER,newFloat32Array(positions),gl.STATIC_DRAW);
There'salotgoingonhere.Thefirstthingiswehavepositionswhichisa
JavaScriptarray.WebGLonotherhandneedsstronglytypeddatasothepart
newFloat32Array(positions)createsanewarrayof32bitfloatingpointnumbers
andcopiesthevaluesfrompositions.gl.bufferDatathencopiesthatdatato
thepositionBufferontheGPU.It'susingthepositionbufferbecausewebound
ittotheARRAY_BUFFERbindpointabove.
Thelastargument,gl.STATIC_DRAWisahinttoWebGLabouthowwe'llusethedata.
WebGLcantrytousethathinttooptimizecertainthings.gl.STATIC_DRAWtellsWebGL
wearenotlikelytochangethisdatamuch.
Nowthatwe'veputdatainabufferweneedtotelltheattributehowtogetdata
outofit.FirstweneedtocreateacollectionofattributestatecalledaVertexArrayObject.
varvao=gl.createVertexArray();
Andweneedtomakethatthecurrentvertexarraysothatallofourattributesettings
willapplytothatsetofattributestate
gl.bindVertexArray(vao);
Nowwefinallysetuptheattributesinthevertexarray.Firstoffweneedtoturntheattributeon.
ThistellsWebGLwewanttogetdataoutofabuffer.Ifwedon'tturnontheattribute
thentheattributewillhaveaconstantvalue.
gl.enableVertexAttribArray(positionAttributeLocation);
Thenweneedtospecifyhowtopullthedataout
varsize=2;//2componentsperiteration
vartype=gl.FLOAT;//thedatais32bitfloats
varnormalize=false;//don'tnormalizethedata
varstride=0;//0=moveforwardsize*sizeof(type)eachiterationtogetthenextposition
varoffset=0;//startatthebeginningofthebuffer
gl.vertexAttribPointer(
positionAttributeLocation,size,type,normalize,stride,offset)
Ahiddenpartofgl.vertexAttribPointeristhatitbindsthecurrentARRAY_BUFFER
totheattribute.Inotherwordsnowthisattributeisboundto
positionBuffer.Thatmeanswe'refreetobindsomethingelsetotheARRAY_BUFFERbindpoint.
TheattributewillcontinuetousepositionBuffer.
NotethatfromthepointofviewofourGLSLvertexshaderthea_positionattributeisavec4
invec4a_position;
vec4isa4floatvalue.InJavaScriptyoucouldthinkofitsomethinglike
a_position={x:0,y:0,z:0,w:0}.Abovewesetsize=2.Attributes
defaultto0,0,0,1sothisattributewillgetitsfirst2values(xandy)
fromourbuffer.Thez,andwwillbethedefault0and1respectively.
Beforewedrawweshouldresizethecanvastomatchitsdisplaysize.CanvasesjustlikeImageshave2sizes.
Thenumberofpixelsactuallyinthemandseparatelythesizetheyaredisplayed.CSSdeterminesthesize
thecanvasisdisplayed.YoushouldalwayssetthesizeyouwantacanvaswithCSSsinceitisfarfar
moreflexiblethananyothermethod.
Tomakethenumberofpixelsinthecanvasmatchthesizeit'sdisplayed
I'musingahelperfunctionyoucanreadabouthere.
Innearlyallofthesesamplesthecanvassizeis400x300pixelsifthesampleisruninitsownwindow
butstretchestofilltheavailablespaceifit'sinsideaniframelikeitisonthispage.
BylettingCSSdeterminethesizeandthenadjustingtomatchweeasilyhandlebothofthesecases.
webglUtils.resizeCanvasToDisplaySize(gl.canvas);
WeneedtotellWebGLhowtoconvertfromtheclipspace
valueswe'llbesettinggl_Positiontobackintopixels,oftencalledscreenspace.
Todothiswecallgl.viewportandpassitthecurrentsizeofthecanvas.
gl.viewport(0,0,gl.canvas.width,gl.canvas.height);
ThistellsWebGLthe-1+1clipspacemapsto0gl.canvas.widthforxand0gl.canvas.height
fory.
Weclearthecanvas.0,0,0,0arered,green,blue,alpharespectivelysointhiscasewe'remakingthecanvastransparent.
//Clearthecanvas
gl.clearColor(0,0,0,0);
gl.clear(gl.COLOR_BUFFER_BIT);
NextweneedtotellWebGLwhichshaderprogramtoexecute.
//Tellittouseourprogram(pairofshaders)
gl.useProgram(program);
Thenweneedtotellitwhichsetofbuffersuseandhowtopulldataoutofthosebuffersto
supplytotheattributes
//Bindtheattribute/buffersetwewant.
gl.bindVertexArray(vao);
AfterallthatwecanfinallyaskWebGLtoexecuteourGLSLprogram.
varprimitiveType=gl.TRIANGLES;
varoffset=0;
varcount=3;
gl.drawArrays(primitiveType,offset,count);
Becausethecountis3thiswillexecuteourvertexshader3times.Thefirsttimea_position.xanda_position.y
inourvertexshaderattributewillbesettothefirst2valuesfromthepositionBuffer.
The2ndtimea_position.xywillbesettothe2ndtwovalues.Thelasttimeitwillbe
settothelast2values.
BecausewesetprimitiveTypetogl.TRIANGLES,eachtimeourvertexshaderisrun3times
WebGLwilldrawatrianglebasedonthe3valueswesetgl_Positionto.Nomatterwhatsize
ourcanvasisthosevaluesareinclipspacecoordinatesthatgofrom-1to1ineachdirection.
BecauseourvertexshaderissimplycopyingourpositionBuffervaluestogl_Positionthe
trianglewillbedrawnatclipspacecoordinates
0,0,
0,0.5,
0.7,0,
Convertingfromclipspacetoscreenspaceifthecanvassize
happenedtobe400x300we'dgetsomethinglikethis
clipspacescreenspace
0,0->200,150
0,0.5->200,225
0.7,0->340,150
WebGLwillnowrenderthattriangle.ForeverypixelitisabouttodrawWebGLwillcallourfragmentshader.
OurfragmentshaderjustsetsoutColorto1,0,0.5,1.SincetheCanvasisan8bit
perchannelcanvasthatmeansWebGLisgoingtowritethevalues[255,0,127,255]intothecanvas.
Here'saliveversion
clickheretoopeninaseparatewindow
Inthecaseaboveyoucanseeourvertexshaderisdoingnothing
butpassingonourpositiondatadirectly.Sincethepositiondatais
alreadyinclipspacethereisnoworktodo.Ifyouwant3Dit'suptoyou
tosupplyshadersthatconvertfrom3DtoclipspacebecauseWebGLisonly
arasterizationAPI.
Youmightbewonderingwhydoesthetrianglestartinthemiddleandgototowardthetopright.
Clipspaceinxgoesfrom-1to+1.Thatmeans0isinthecenterandpositivevalueswill
betotherightofthat.
Asforwhyit'sonthetop,inclipspace-1isatthebottomand+1isatthetop.Thatmeans
0isinthecenterandsopositivenumberswillbeabovethecenter.
For2Dstuffyouwouldprobablyratherworkinpixelsthanclipspaceso
let'schangetheshadersowecansupplythepositioninpixelsandhave
itconverttoclipspaceforus.Here'sthenewvertexshader
-invec4a_position;
+invec2a_position;
+uniformvec2u_resolution;
voidmain(){
+//convertthepositionfrompixelsto0.0to1.0
+vec2zeroToOne=a_position/u_resolution;
+
+//convertfrom0->1to0->2
+vec2zeroToTwo=zeroToOne*2.0;
+
+//convertfrom0->2to-1->+1(clipspace)
+vec2clipSpace=zeroToTwo-1.0;
+
*gl_Position=vec4(clipSpace,0,1);
}
Somethingstonoticeaboutthechanges.Wechangeda_positiontoavec2sincewe're
onlyusingxandyanyway.Avec2issimilartoavec4butonlyhasxandy.
Nextweaddedauniformcalledu_resolution.Tosetthatweneedtolookupitslocation.
varresolutionUniformLocation=gl.getUniformLocation(program,"u_resolution");
Therestshouldbeclearfromthecomments.Bysettingu_resolutiontotheresolution
ofourcanvastheshaderwillnowtakethepositionsweputinpositionBuffersupplied
inpixelscoordinatesandconvertthemtoclipspace.
Nowwecanchangeourpositionvaluesfromclipspacetopixels.Thistimewe'regoingtodrawarectangle
madefrom2triangles,3pointseach.
varpositions=[
*10,20,
*80,20,
*10,30,
*10,30,
*80,20,
*80,30,
];
gl.bufferData(gl.ARRAY_BUFFER,newFloat32Array(positions),gl.STATIC_DRAW);
Andafterwesetwhichprogramtousewecansetthevaluefortheuniformwecreated.
gl.useProgramislikegl.bindBufferaboveinthatitsetsthecurrentprogram.After
thatallthegl.uniformXXXfunctionssetuniformsonthecurrentprogram.
gl.useProgram(program);
//Passinthecanvasresolutionsowecanconvertfrom
//pixelstoclipspaceintheshader
gl.uniform2f(resolutionUniformLocation,gl.canvas.width,gl.canvas.height);
Andofcoursetodraw2trianglesweneedtohaveWebGLcallourvertexshader6times
soweneedtochangethecountto6.
//draw
varprimitiveType=gl.TRIANGLES;
varoffset=0;
*varcount=6;
gl.drawArrays(primitiveType,offset,count);
Andhereitis
Note:Thisexampleandallfollowingexamplesusewebgl-utils.js
whichcontainsfunctionstocompileandlinktheshaders.Noreasontocluttertheexamples
withthatboilerplatecode.
clickheretoopeninaseparatewindow
Againyoumightnoticetherectangleisnearthebottomofthatarea.WebGLconsiderspositiveYas
upandnegativeYasdown.Inclipspacethebottomleftcorner-1,-1.Wehaven'tchangedanysigns
sowithourcurrentmath0,0becomesthebottomleftcorner.
Togetittobethemoretraditionaltopleftcornerusedfor2dgraphicsAPIs
wecanjustfliptheclipspaceycoordinate.
*gl_Position=vec4(clipSpace*vec2(1,-1),0,1);
Andnowourrectangleiswhereweexpectit.
clickheretoopeninaseparatewindow
Let'smakethecodethatdefinesarectangleintoafunctionso
wecancallitfordifferentsizedrectangles.Whilewe'reatit
we'llmakethecolorsettable.
Firstwemakethefragmentshadertakeacoloruniforminput.
#version300es
precisionhighpfloat;
+uniformvec4u_color;
outvec4outColor;
voidmain(){
-outColor=vec4(1,0,0.5,1);
*outColor=u_color;
}
Andhere'sthenewcodethatdraws50rectanglesinrandomplacesandrandomcolors.
varcolorLocation=gl.getUniformLocation(program,"u_color");
...
//draw50randomrectanglesinrandomcolors
for(varii=0;ii<50;++ii){
//Setuparandomrectangle
setRectangle(
gl,randomInt(300),randomInt(300),randomInt(300),randomInt(300));
//Setarandomcolor.
gl.uniform4f(colorLocation,Math.random(),Math.random(),Math.random(),1);
//Drawtherectangle.
varprimitiveType=gl.TRIANGLES;
varoffset=0;
varcount=6;
gl.drawArrays(primitiveType,offset,count);
}
}
//Returnsarandomintegerfrom0torange-1.
functionrandomInt(range){
returnMath.floor(Math.random()*range);
}
//Fillsthebufferwiththevaluesthatdefinearectangle.
functionsetRectangle(gl,x,y,width,height){
varx1=x;
varx2=x+width;
vary1=y;
vary2=y+height;
//NOTE:gl.bufferData(gl.ARRAY_BUFFER,...)willaffect
//whateverbufferisboundtothe`ARRAY_BUFFER`bindpoint
//butsofarweonlyhaveonebuffer.Ifwehadmorethanone
//bufferwe'dwanttobindthatbufferto`ARRAY_BUFFER`first.
gl.bufferData(gl.ARRAY_BUFFER,newFloat32Array([
x1,y1,
x2,y1,
x1,y2,
x1,y2,
x2,y1,
x2,y2]),gl.STATIC_DRAW);
}
Andhere'stherectangles.
clickheretoopeninaseparatewindow
IhopeyoucanseethatWebGLisactuallyaprettysimpleAPI.
Okay,simplemightbethewrongword.Whatitdoesissimple.Itjust
executes2usersuppliedfunctions,avertexshaderandfragmentshaderand
drawstriangles,lines,orpoints.
Whileitcangetmorecomplicatedtodo3Dthatcomplicationis
addedbyyou,theprogrammer,intheformofmorecomplexshaders.
TheWebGLAPIitselfisjustarasterizerandconceptuallyfairlysimple.
Wecoveredasmallexamplethatshowedhowtosupplydatainanattributeand2uniforms.
It'scommontohavemultipleattributesandmanyuniforms.Nearthetopofthisarticle
wealsomentionedvaryingsandtextures.Thosewillshowupinsubsequentlessons.
BeforewemoveonIwanttomentionthatformostapplicationsupdating
thedatainabufferlikewedidinsetRectangleisnotcommon.Iusedthat
examplebecauseIthoughtitwaseasiesttoexplainsinceitshowspixelcoordinates
asinputanddemonstratesdoingasmallamountofmathinGLSL.It'snotwrong,there
areplentyofcaseswhereit'stherightthingtodo,butyoushouldkeepreadingtofindout
themorecommonwaytoposition,orientandscalethingsinWebGL.
Ifyou're100%newtoWebGLandhavenoideawhatGLSLisorshadersorwhattheGPUdoes
thencheckoutthebasicsofhowWebGLreallyworks.
Youmightalsowanttotakealookatthis
interactivestatediagram
foranotherwayofunderstandinghowWebGLworks.
Youshouldalso,atleastbrieflyreadabouttheboilerplatecodeusedhere
thatisusedinmostoftheexamples.Youshouldalsoatleastskim
howtodrawmultiplethingstogiveyousomeidea
ofhowmoretypicalWebGLappsarestructuredbecauseunfortunatelynearlyalltheexamples
onlydrawonethingandsodonotshowthatstructure.
Otherwisefromhereyoucangoin2directions.Ifyouareinterestedinimageprocessing
I'llshowyouhowtodosome2Dimageprocessing.
Ifyouareinterestinginlearningabouttranslation,
rotationandscalethenstarthere.
English
Deutsch
日本語
한국어
PortuguêsBrasileiro
简体中文
Fundamentals
HowtouseWebGL2
Fundamentals
HowItWorks
ShadersandGLSL
WebGL2StateDiagram
WebGL2vsWebGL1
What'snewinWebGL2
MovingfromWebGL1toWebGL2
DifferencesfromWebGLFundamentals.orgtoWebGL2Fundamentals.org
ImageProcessing
ImageProcessing
ImageProcessingContinued
2Dtranslation,rotation,scale,matrixmath
2DTranslation
2DRotation
2DScale
2DMatrices
3D
Orthographic3D
3DPerspective
3D-Cameras
3D-MatrixNaming
Lighting
DirectionalLighting
PointLighting
SpotLighting
StructureandOrganization
LessCode,MoreFun
DrawingMultipleThings
SceneGraphs
Geometry
3DGeometry-Lathe
Loading.objfiles
Loading.objw.mtlfiles
Textures
Textures
DataTextures
Using2orMoreTextures
CrossOriginImages
PerspectiveCorrectTextureMapping
PlanarandPerspectiveProjectionMapping
RenderingToATexture
RendertoTexture
Shadows
Shadows
Techniques
2D
2D-DrawImage
2D-MatrixStack
Sprites
3D
Cubemaps
Environmentmaps
Skyboxes
Skinning
Fog
Picking(clickingonstuff)
Text
Text-HTML
Text-Canvas2D
Text-UsingaTexture
Text-UsingaGlyphTexture
GPGPU
GPGPU
Tips
SmallestPrograms
DrawingWithoutData
Shadertoy
PullingVertices
Optimization
IndexedVertices(gl.drawElements)
InstancedDrawing
Misc
SetupAndInstallation
Boilerplate
ResizingtheCanvas
Animation
Points,Lines,andTriangles
MultipleViews,MultipleCanvases
VisualizingtheCamera
WebGL2andAlpha
2Dvs3Dlibraries
Anti-Patterns
WebGL2MatricesvsMathMatrices
PrecisionIssues
Takingascreenshot
PreventtheCanvasBeingCleared
GetKeyboardInputFromaCanvas
UseWebGL2asBackgroundinHTML
CrossPlatformIssues
QuestionsandAnswers
Reference
Attributes
TextureUnits
Framebuffers
readPixels
References
HelperAPIDocs
TWGL,AtinyWebGLhelperlibrary
github
Issue/Bug?Createanissueongithub.
Usecodegoeshere
forcodeblocks
commentspoweredbyDisqus