Getting started with WebGL – Part 2

Introduction

 

Having introduced the drawing pipeline in a preceding article, we will now code a first example. We will initialize a HTML canvas to draw on, and then write the shaders that constitute our program

 

 

Initialize a canvas

All the code is available at https://github.com/Edouard360/getting-started-with-webgl. To get it, you may run those commands:

 

We first need to create an html canvas in the DOM. In our index.html, we have created the tag:

 

Then got it in the javascript webgl-demo.js:

 

This JS element has a method to retrieve the WebGL context:

 

A context gives us different functions to draw in a particular way on the canvas. The webgl context for instance, exposes ways to draw on the canvas using the GPU.

We can start using the context to initialize the canvas:

 

To obtain a black canvas. This code is boilerplate and can be used as is in most of our projects.

Open index.html to see the result.

photo2-article2

Create a GLSL program

Vertex shader

Description

A vertex shader is a piece of GLSL code written by the developer that deals with each vertex and gives it a position. It has a main function, in which the user defines the final position of each vertex, by assigning the desired position into the predefined global variable gl_Position.

The main function of the vertex shader is the same for each vertex, but with different input values, so that their final position is different. These vertex-specific input values are called “vertex attributes”.

In our square example, the 3D-coordinates (x, y, z) of each vertex are the input values for the vertex shader. They will be stored in a variable declared before the main function, with the “attribute” keyword. Let’s call this attribute “position”. Unlike in JavaScript, we also need to specify the data-type for this variable.

In GLSL, the most common predefined data-types are: a single floating number (float), a vector of 2, 3, 4 floats (vec2, vec3, vec4), or a matrix of 2×2, 3×3, 4×4 floats (mat2, mat3, mat4). For our 3D-coordinates, we will use the vec3 type.

Let’s write this vertex shader !

The simplest Vertex Shader

The reason why we use GLSL code instead of using only Javascript is that the GLSL language runs on a GPU/graphics card. The main function of the vertex shader can be executed in parallel for each vertex.

In our square example, to keep it simple, the main function of our vertex shader makes no computations.

In our index.html, we can add the script of our vertex shader, written in the GLSL language.

 

gl_Position is a vector of 4 floats (vec4). The 3 first elements are the positions (x,y,z) and the last element (w) is called the clip coordinate.

The clip coordinate

When drawing things in WebGL, we often use the concept of camera, from which we observe our world. Some objects are in the field of view of this camera, others aren’t. As long as the coordinates of an object are “out of bounds”, the object will not be rendered.

By default, in WebGL, if the screen space position of an object has its coordinates out of [-1,1], it will not be rendered. That’s why we use a “camera” to modify these bounds. We can similarly modify these bounds with the clip coordinate. The w coordinate plays a role in adjusting the coordinates, so that it fits in the picture or not.

photo3-article2

In computing, this is called clipping. It refers to the process of removing the “out of the bounds” objects. It usually amounts to dividing all the coordinates by w. The default value is, as in our current shader, 1.0.

Fragment shader

Description

The fragment shader is a GLSL code written by the developer that deals with each fragment – or potential pixel – and gives it a color. It has a main function, in which the user defines the final color of each fragment, by assigning the desired color into the predefined global variable gl_FragColor.

The main function of the fragment shader is the same for each fragment. In our square example, we won’t provide any input value to it, because we want a uniform orange square.

Let’s write this fragment shader !

The simplest Fragment Shader

The main function of the fragment shader can be executed in parallel for each pixel. In our square example, to keep it simple, our fragment shader makes no computations. In our index.html, we can add the script of our fragment shader, written in the GLSL language.

 

gl_FragColor is a vector of 4 floats (vec4) – (red, green, blue, alpha). The values for the colors are between 0, and 1, (0,0,0) being black and (1,1,1) being white. The alpha coordinate stands for the opacity, 0 being totally transparent, and 1 totally opaque.

Initialize the GLSL Program

These shaders will be part of a program that link them together. A program needs at least one vertex shader and one fragment shader to be valid.

We compile the shaders and link them to a program.

var vertexShaderSource = document.getElementById(shader-vs).firstChild.textContent;

 

Our program is now ready to receive JS data, but we will explain that it the next article. For now, we checkout:

 

Open index.html to see the desired square.

photo4-article2

Conclusion

We have written our first vertex shader and fragment shader, compiled them, and linked them in a newly created program. In the next article, we will see how to send our coordinates as attributes to the shader.