Getting Started with WebGL

WebGL is an open web standard that allows you to create highly efficient graphical applications to run in web browsers through hardware acceleration.
This article will walk you through how to create a WebGL context and render a simple triangle (as shown in the picture below) using WebGL 2.0.
 
WebGL triangle
Setting up WebGL: To develop and run a WebGL application all you need is a web browser and a code editor. That’s it! You don’t need to install anything extra on your system. WebGL is currently supported by the major browsers Apple (Safari), Google (Chrome), Microsoft (Edge), Opera (Opera web browser), and Mozilla (Firefox). So, make sure to update your browser to the latest version.
Creating a WebGL context: To begin we create an HTML file with an <canvas> element to draw and display animations in the browser.
index.html
| <!DOCTYPE html> <html>  <head>     <title></title> </head>  <body>     <canvasid="canvas"width="400"height="300">         Your browser does not support HTML5     </canvas>     <scriptsrc="app.js"></script> </body>  </html>  | 
Now, to start rendering content, we must first create a WebGL context using JavaScript.
app.js
| // Request html canvas element varcanvas = document.getElementById("canvas");  // Create a WebGL rendering context   vargl = canvas.getContext("webgl2");  // Tell user if their browser does not support WebGL if(!gl) {     alert("Your browser does not support WebGL"); }  // Set the color of the canvas. // Parameters are RGB colors (red, green, blue, alpha) gl.clearColor(0, 0.6, 0.0, 1.0); // Clear the color buffer with specified color gl.clear(gl.COLOR_BUFFER_BIT); | 
If the browser supports WebGL, you see an empty box with a green background waiting to receive content.
 
Output WebGL context
Defining the Shaders: So far, we have our canvas and WebGL prepared and ready to render some content. Now, let’s define our shaders.
Shaders are programs that are executed in the GPU written in OpenGL Shading Language (GLSL) and allow us to perform mathematical operations to transform vertices and/or colors. In WebGL, we just need to provide two shades: vertex shader, and fragment shader. The vertex shader is used to specify the final position of the vertices, and the fragment shader is used to define to the color surface of our model. GLSL is semantically similar to the C language. We have a main function to perform all the operations and we have input and output parameters denoted as in, out, and data-types as vec2, vec3, vec4.
Let’s take a look at these two shaders for our simple triangle.
Javascript
| // Define shaders: vertex shader and fragment shader const shaders = {     vs: `#version 300 es         invec2 vertPosition;         invec3 vertColor;         out vec3 fragColor;              void main() {             fragColor = vertColor;             gl_Position = vec4(vertPosition, 0, 1);         }`,      fs: `#version 300 es         precision mediump float;         invec3 fragColor;         out vec4 outColor;              void main() {             outColor = vec4(fragColor, 1);         }` }; | 
Once defined the shaders in GLSL, we are now ready to create the shader objects and compile them so that WebGLProgram can use them. We use gl.createShader(), gl.shaderSource(), and gl.compileShader() methods for our vertexShader and fragmentShader.
Javascript
| // Create WebGl Shader objects varvertexShader = gl.createShader(gl.VERTEX_SHADER); varfragmentShader = gl.createShader(gl.FRAGMENT_SHADER);  // sets the source code of the WebGL shader gl.shaderSource(vertexShader, shaders.vs); gl.shaderSource(fragmentShader, shaders.fs);  // Compile GLSL Shaders to a binary data  // so WebGLProgram can use them gl.compileShader(vertexShader); gl.compileShader(fragmentShader); | 
Creating the WebGLProgram: The next step is to create the WebGLProgram to host our vertex shader and fragment shader in the GPU.
Javascript
| // Create a WebGLProgram varprogram = gl.createProgram();  // Attach pre-existing shaders gl.attachShader(program, vertexShader); gl.attachShader(program, fragmentShader);  gl.linkProgram(program); | 
Creating the Triangle Object: In this step, we create the vertex attributes and the input data to the shaders (the triangle). We define two attributes for this triangle “position” and “color”. We create a “data” array for each attribute using 32 bits as this is required in the vertex buffers. The “data” arrays contain the coordinates of the triangle in the XY plane and the RGB colors for each vertex of the triangle.
Javascript
| const vertexAttributes = {     position: {         numberOfComponents: 2, // X and Y ordered pair coordinates         data: newFloat32Array([0.0, 0.5, -0.5, -0.5, 0.5, -0.5])     },     color: {          numberOfComponents: 3, // RGB triple         data: newFloat32Array([1, 0, 0, 0, 1, 0, 0, 0, 1])     } }; | 
Creating Vertex Buffers, and Rendering: Now, we need to create buffers to store the vertex attributes. In OpenGL/WebGL applications, buffers are memory spaces in the graphics card (VRAM) that are used by the shaders to perform mathematical operations. Remember, shaders are executed in the GPU and we need the memory from the graphics card for fast data access. Here, we create two buffers one for the position attribute and the other one for the color attribute.
We then use gl.getAttribLocation() and gl.vertexAttribPointer() to tell the shaders how we are sending the data in the vertex attributes.
Finally, we execute the shaders using gl.drawArrays()
Javascript
| // Create an initialize vertex buffers varvertexBufferObjectPosition = gl.createBuffer(); varvertexBufferObjectColor = gl.createBuffer();  // Bind existing attribute data gl.bindBuffer(gl.ARRAY_BUFFER, vertexBufferObjectPosition); gl.bufferData(gl.ARRAY_BUFFER, vertexAttributes.position.data,          gl.STATIC_DRAW);  varpositionAttribLocation = gl.getAttribLocation(program,          'vertPosition');  gl.vertexAttribPointer(positionAttribLocation,     vertexAttributes.position.numberOfComponents,          gl.FLOAT, gl.FALSE, 0, 0); gl.enableVertexAttribArray(positionAttribLocation);  // Bind existing attribute data gl.bindBuffer(gl.ARRAY_BUFFER, vertexBufferObjectColor); gl.bufferData(gl.ARRAY_BUFFER, vertexAttributes.color.data,          gl.STATIC_DRAW);  varcolorAttribLocation = gl.getAttribLocation(program,          'vertColor');  gl.vertexAttribPointer(colorAttribLocation,     vertexAttributes.color.numberOfComponents, gl.FLOAT,              gl.FALSE, 0, 0); gl.enableVertexAttribArray(colorAttribLocation);  // Set program as part of the current rendering state gl.useProgram(program); // Draw the triangle gl.drawArrays(gl.TRIANGLES, 0, 3); | 
Putting All Together: Here we have all pieces together in the app.js file. To test this code, please, download both the html.index and the app.js files and put them in the same directory, and then open the index.html on your web browser.
index.html
| <!DOCTYPE html> <html>  <head>     <title></title> </head>  <body>     <canvasid="canvas"width="400"height="300">         Your browser does not support HTML5     </canvas>     <scriptsrc="app.js"></script> </body>  </html>  | 
app.js
| // Request html canvas element varcanvas = document.getElementById("canvas");  // Create a WebGL rendering context   vargl = canvas.getContext("webgl2");  // Tell user if their browser does not support WebGL if(!gl) {     alert("Your browser does not support WebGL"); }  // Set the color of the canvas.  // Parameters are RGB colors (red, green, blue, alpha) gl.clearColor(0, 0.6, 0.0, 1.0); // Clear the color buffer with specified color gl.clear(gl.COLOR_BUFFER_BIT);  // Define shaders: vertex shader and fragment shader const shaders = {     vs: `#version 300 es         invec2 vertPosition;         invec3 vertColor;         out vec3 fragColor;              void main() {             fragColor = vertColor;             gl_Position = vec4(vertPosition, 0, 1);         }`,      fs: `#version 300 es         precision mediump float;         invec3 fragColor;         out vec4 outColor;              void main() {             outColor = vec4(fragColor, 1);         }` };  // Create WebGl Shader objects varvertexShader = gl.createShader(gl.VERTEX_SHADER); varfragmentShader = gl.createShader(gl.FRAGMENT_SHADER);  // sets the source code of the WebGL shader gl.shaderSource(vertexShader, shaders.vs); gl.shaderSource(fragmentShader, shaders.fs);  // Compile GLSL Shaders to a binary data so // WebGLProgram can use them gl.compileShader(vertexShader); gl.compileShader(fragmentShader);  // Create a WebGLProgram varprogram = gl.createProgram();  // Attach pre-existing shaders gl.attachShader(program, vertexShader); gl.attachShader(program, fragmentShader);  gl.linkProgram(program);  const vertexAttributes = {     position: {            // X and Y ordered pair coordinates         numberOfComponents: 2,          data: newFloat32Array([0.0,             0.5, -0.5, -0.5, 0.5, -0.5])     },     color: {          numberOfComponents: 3, // RGB triple         data: newFloat32Array([1.0, 0.0,              0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0])     } };  // Create an initialize vertex buffers varvertexBufferObjectPosition = gl.createBuffer(); varvertexBufferObjectColor = gl.createBuffer();  // Bind existing attribute data gl.bindBuffer(gl.ARRAY_BUFFER, vertexBufferObjectPosition); gl.bufferData(gl.ARRAY_BUFFER,      vertexAttributes.position.data, gl.STATIC_DRAW);  varpositionAttribLocation =      gl.getAttribLocation(program, 'vertPosition');  gl.vertexAttribPointer(positionAttribLocation,     vertexAttributes.position.numberOfComponents,      gl.FLOAT, gl.FALSE, 0, 0); gl.enableVertexAttribArray(positionAttribLocation);  // Bind existing attribute data gl.bindBuffer(gl.ARRAY_BUFFER, vertexBufferObjectColor); gl.bufferData(gl.ARRAY_BUFFER,      vertexAttributes.color.data, gl.STATIC_DRAW);  varcolorAttribLocation =      gl.getAttribLocation(program, 'vertColor');  gl.vertexAttribPointer(colorAttribLocation,     vertexAttributes.color.numberOfComponents,      gl.FLOAT, gl.FALSE, 0, 0); gl.enableVertexAttribArray(colorAttribLocation);  // Set program as part of the current rendering state gl.useProgram(program); // Draw the triangle gl.drawArrays(gl.TRIANGLES, 0, 3); | 
Output:
 
Output: WebGL triangle
 
				 
					


