Introduction to WebGL CS 418: Interactive Computer Graphics UNIVERSITY OF ILLINOIS AT URBANA-CHAMPAIGN Eric Shaffer
You Need a Text Editor Brackets is a good choice…but whatever works for you is fine http://brackets.io/
Time to Write Some HTML A few notes We will keep everything in a single HTML file for this example • …for larger programs we will separate the HTML and JavaScript • Using WebGL entails writing a bunch of startup code Complexity comes from the flexibility of the API • Will enable you to do really sophisticated stuff later on…. • Eventually we’ll use a helper library for the startup code… • You can grab code from https://courses.engr.illinois.edu/cs418/Examples/HelloTriangle.html
The HTML <!DOCT YPEHT ML > We create an HTML page <html la ng ="e n"> <he a d> Notice: We create an HTML5 <canvas> That is 500 x 500 <title >He llo T ria ng le </ title > pixels which we will draw into. <me ta c ha rse t="utf-8"> </ he a d> We give it an id so we can refer to it in the javascript that <body onload="star tup();"> we will write. <c anvas id="myGL Canvas" width="500“ he ight="500"> onload specifies an entry point into the JavaScript we will write…a function named startup() will be called on a </ c a nva s> page load </ b o dy> </ html>
Adding JavaScript <script type="text/javascript"> var gl; var canvas; JavaScript is included inside <script> tags var shaderProgram; var vertexBuffer; We have some global variables… …and our initial function calls some other functions. function startup(){ Bolded functions are the ones we will write. canvas=document.getElementById("myGLCanvas"); gl= createGLContext(canvas); clearColor is a WebGL function that sets the initial color setupShaders(); of the pixels in the raster setupBuffers(); getElementByID is a Document Object Model (DOM) gl.clearColor(0.0, 0.0, 0.0, 1.0); function that gets us a reference to the canvas created in draw(); the HTML document } </script>
Getting a WebGL Context function createGLContext(canvas) { We need to make sure the browser supports var names = ["webgl", "experimental-webgl"]; var context = null; WebGL…so we try to get a reference to a WebGL for (var i=0; i < names.length; i++) { context using the two names under which it might try { exist context = canvas.getContext(names[i]); } catch(e) {} if (context) { break;} If we get a context, we set the viewport dimensions of the context to match the size of the canvas. } if (context) { context.viewportWidth = canvas.width; You can choose to use less than the full canvas. context.viewportHeight = canvas.height; } else { alert("Failed to create WebGL context!"); } return context; }
Creating Vertex Shader We’ll talk more about shaderslater but for now you shouldknow: var vertexShaderSource = We need to create a vertex shader "attribute vec3 aVertexPosition; \n"+ program written inGLSL "void main() { \n"+ We will use a JavaScript string to hold the source " gl_Position = vec4(aVertexPosition, 1.0); \n"+ code for thevertex shader. We’ll see a better way to do this later. "} \n" The shader must assign a valueto gl_Position Our shader basically just takes the position of an incoming vertexand assigns that position to gl_Position. It actually does one thing to the incoming position…do youknow what that is?
Creating Fragment Shader var fragmentShaderSource = Like the vertex shader program, the fragment shader code is "precision mediump float; \n"+ written in GLSL and held in a "void main() { string. \n"+ " gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); \n"+ "} You can think of fragments as \n"; being almost pixels…they are produced by the WebGL rasterizer and have a screen space position and some other data related to them. Our shader simply assigns each fragment the same color. Again, we’ll talk more about what the shaders do later…
Compiling the Shaders func tio n se tupShade rs() { We have a homemade helper function that compiles the shader and va r ve rte xSha de rSo urc e = … checks if there were compilation errors. va r fra g me ntSha de rSo urc e = … If there was an error, a JavaScript alert is issued and the shader object va r ve rte xSha de r = lo a dSha de r(g l.VE RT E X_SHADE R, ve rte xSha de rSo urc e ); deleted. va r fra g me ntSha de r = lo a dSha de r(g l.F RAGME NT _SHADE R, fra g me ntSha de rSo urc e ); Otherwise the compiled shader is returned. … } Important: You can create multiple shader programs func tio n lo adShade r(type , sha de rSo urc e ) { • va r sha de r = g l.c re ate Shade r(type ); g l.shade rSo urc e (shade r, sha de rSo urc e ); You can switch which one you use while drawing a single frame g l.c o mpile Shade r(shade r); • …just use the useProgram function in WebGL • if (!g l.g e tShade rParame te r(shade r, g l.COMPI L E _ST AT US)) { a le rt("E rro r c o mpiling sha de r"+ g l.g e tShade rI nfo L o g (shade r)); Each shader program needs a vertex shader and fragment shader g l.de le te Shade r(shade r); • re turn null; } re turn sha de r; }
Creating the Program Object Linking the Shaders func tio n se tupSha de rs() { We create a program object andattach the compiled shaders and link. At this point, we … have a complete shader program that WebGL sha de rPro g ra m = g l.c re a te Pro g ra m(); can use. g l.a tta c hSha de r(sha de rPro g ra m, ve rte xSha de r); g l.a tta c hSha de r(sha de rPro g ra m, fra g me ntSha de r); attr ttributes are user-defined variables that contain data specific to avertex. g l.linkPro g ra m(sha de rPro g ra m); The attr ttribute tes used in the vertex shader are bound to an index (basically a number given if (!g l.g e tPro g ra mPa ra me te r(sha de rPro g ra m, g l.L I NK _ST AT US)) { to a slot). Our code needs to know the index a le rt("F a ile d to se tup sha de rs"); associatedwith the attributes we use in the } shader so that our draw function can feed the g l.use Pro g ra m(sha de rPro g ra m); data correctly. vertexPositionAttribute is a user-defined sha de rPro g ra m.ve rte xPo sitio nAttrib ute = property in which we remember the index g l.g e tAttrib L o c a tio n(sha de rPro g ra m, "a Ve rte xPo sitio n"); value }
Setting up the Vertex Buffers We next need to create a buffer that will hold func tio n se tupBuffe rs() { the vertex data…this is the geometric data of ve rte xBuffe r = g l.c re a te Buffe r(); the shapes we wish to render. g l.b indBuffe r(g l.ARRAY_BUF F E R, ve rte xBuffe r); We create a WebGL buffer object and bind va r tria ng le Ve rtic e s = [ it so that WebGL knows it is the current 0.0, 0.5, 0.0, buffer to work with. -0.5, -0.5, 0.0, 0.5, -0.5, 0.0 triangleVertices is a user-defined JavaScript array containing the 3D ]; coordinates of a single triangle. g l.b uffe rDa ta (g l.ARRAY_BUF F E R, ne w F lo a t32Arra y(tria ng le Ve rtic e s), g l.ST AT I C_DRAW); We call a magic function to copy the vertex ve rte xBuffe r.ite mSize = 3; positions into the current WebGL buffer. ve rte xBuffe r.numb e rOfI te ms = 3; Two user-defined properties are used to } remember how many vertices we have and how many coordinates per vertex.
Drawing the Scene func tio n dra w() { The viewport rt method lets us tell WebGLhow to convert g l.vie wpo rt(0, 0, g l.vie wpo rtWidth, g l.vie wpo rtHe ig ht); from clipspace in which coordinates range from -1 to 1 into pixel coordinates. g l.c le a r(g l.COL OR_BUF F E R_BI T ); Here we use our two user-defined properties to set it to the g l.ve rte xAttrib Po inte r(sha de rPro g ra m.ve rte xPo sitio nAttrib ute , full size of the canvas. ve rte xBuffe r.ite mSize , g l.F L OAT , fa lse , 0, 0); Cl Clear initializes the color buffer to the color set with g l.e na b le Ve rte xAttrib Arra y(sha de rPro g ra m.ve rte xPo sitio nAttrib ute ); clearCol olor or . g l.dra wArra ys(g l.T RI ANGL E S, 0, ve rte xBuffe r.numb e rOfI te ms); We then tell WebGLto take values for aVertexPosition from } the buffer currently bound to gl.ARRAY_BUFFER….and then we draw.
…a little more about attributes • What is happening here? shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition"); gl.vertexAttribPointer( • What is happening here? shaderProgram.vertexPositionAttribute, vertexBuffer.itemSize, gl.FLOAT, false, 0, 0); • And here? gl.enableVertexAttribArray( shaderProgram.vertexPositionAttribute);
…a little more about attributes • Get an index for a variable from the shaderProgram.vertexPositionAttribute = shader program and remember it in a gl.getAttribLocation(shaderProgram, "aVertexPosition"); property tied to the shader program object • Set size, type, etc, of data for the gl.vertexAttribPointer( shaderProgram.vertexPositionAttribute, vertexBuffer.itemSize, gl.FLOAT, false, 0, attribute 0); • Start feeding the attribute from the gl.enableVertexAttribArray( data in the array shaderProgram.vertexPositionAttribute);
Result…
Can You? Change the triangle color? Change the background color? Change the triangle shape? Draw multiple triangles?
Recommend
More recommend