Open In App

Getting Started with WebGL

Last Updated : 05 Apr, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

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.

Output WebGL triangle

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>
    <canvas id="canvas" width="400" height="300">
        Your browser does not support HTML5
    </canvas>
    <script src="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
var canvas = document.getElementById("canvas");
  
// Create a WebGL rendering context  
var gl = 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

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
        in vec2 vertPosition;
        in vec3 vertColor;
        out vec3 fragColor;
      
        void main() {
            fragColor = vertColor;
            gl_Position = vec4(vertPosition, 0, 1);
        }`,
  
    fs: `#version 300 es
        precision mediump float;
        in vec3 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
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
var fragmentShader = 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
var program = 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: new Float32Array([0.0, 0.5, -0.5, -0.5, 0.5, -0.5])
    },
    color: { 
        numberOfComponents: 3, // RGB triple
        data: new Float32Array([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
var vertexBufferObjectPosition = gl.createBuffer();
var vertexBufferObjectColor = gl.createBuffer();
  
// Bind existing attribute data
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBufferObjectPosition);
gl.bufferData(gl.ARRAY_BUFFER, vertexAttributes.position.data, 
        gl.STATIC_DRAW);
  
var positionAttribLocation = 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);
  
var colorAttribLocation = 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>
    <canvas id="canvas" width="400" height="300">
        Your browser does not support HTML5
    </canvas>
    <script src="app.js"></script>
</body>
  
</html>


app.js




// Request html canvas element
var canvas = document.getElementById("canvas");
  
// Create a WebGL rendering context  
var gl = 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
        in vec2 vertPosition;
        in vec3 vertColor;
        out vec3 fragColor;
      
        void main() {
            fragColor = vertColor;
            gl_Position = vec4(vertPosition, 0, 1);
        }`,
  
    fs: `#version 300 es
        precision mediump float;
        in vec3 fragColor;
        out vec4 outColor;
      
        void main() {
            outColor = vec4(fragColor, 1);
        }`
};
  
// Create WebGl Shader objects
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
var fragmentShader = 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
var program = 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: new Float32Array([0.0,
            0.5, -0.5, -0.5, 0.5, -0.5])
    },
    color: { 
        numberOfComponents: 3, // RGB triple
        data: new Float32Array([1.0, 0.0, 
            0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0])
    }
};
  
// Create an initialize vertex buffers
var vertexBufferObjectPosition = gl.createBuffer();
var vertexBufferObjectColor = gl.createBuffer();
  
// Bind existing attribute data
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBufferObjectPosition);
gl.bufferData(gl.ARRAY_BUFFER, 
    vertexAttributes.position.data, gl.STATIC_DRAW);
  
var positionAttribLocation = 
    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);
  
var colorAttribLocation = 
    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

Output: WebGL triangle



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads