News

2D and 3D graphics with WebGL

Master graphics in your browser by learning to write WebGL programs to display 2D and 3D objects with JavaScript

A WebGL cube

OpenGL is a well-known standard for generating 3D as well as 2D graphics; it’s extremely powerful and has many capabilities. OpenGL is defined and released by the OpenGL Architecture Review Board (ARB) and is a big state machine. Most calls to OpenGL functions modify a global state that you cannot directly access. WebGL is a JavaScript implementation of OpenGL ES 2.0 that runs on the latest browsers. The OpenGL ES (Embedded Subsystem) is the mobile version of the OpenGL standard and is targeted towards embedded devices. OpenGL ES is a C-based, Platform-Neutral API. The OS must provide a rendering context that accepts commands as well as a framebuffer that keeps the results of the drawing commands.

All modern web browsers support the WebGL API by default so you do not need to do any extra work to use WebGL. If you want your WebGL programs to be available to the world, you will need to put them in a web server. Finally, all the code referred to in the steps can be downloaded from FileSilo.co.uk.

A Google experiment using WebGL graphics
A Google experiment using WebGL graphics

Resources

OpenGL
OpenGL ES
WebGL
Reference Cards

Step-by-step

Step 01 How to use WebGL

Before starting to write small WebGL programs, you will need to write some HTML code to use it as a template. The HTML code itself does not really matter in this instance as long as it fits your needs (see ‘init.html’).

The code does nothing but initialise some basic stuff that you should use later. The most important stuff is the definition of canvas; everything will be drawn inside the canvas element. You will also need to use a context name: some supported context names are ‘webgl’, ‘experimental-webgl’ and ‘webkit-3d’. You can paint the canvas any colour you want.

Step 02 Draw a simple shape

Drawing 2D or 3D shapes used to require expensive hardware and specialised software but nowadays, even a smartphone can run WebGL.

The presented HTML code (see ‘rectangle. html’) draws a 2D rectangle on-screen using WebGL. In order to separate the two triangles that compose the rectangle, the coordinates for the second triangle are slightly changed in order for you to distinguish the two triangles.

If you don’t want a line to separate the two triangles, you should define the vertices array using the following code:

var vertices = [-0.75, -0.75, 0.75, -0.75, 0.75, 0.75, -0.75, -0.75, 0.75, 0.75, -0.75, 0.75 ];

Step 03 The code explained

The JavaScript code is pretty straightforward. Nevertheless, it contains some mathematics that is needed for defining the coordinates of the rectangle’s vertices.

The following line defines a buffer which will hold the vertex data:

var myVertexBuffer = gl.createBuffer();

The following line of code defines the number of triangles you want to draw:

gl.drawArrays(gl.TRIANGLES, 0, 6);

The ‘createShader(str, type)’ and the ‘createProgram(vstr, fstr)’ functions are pretty much standard code that you are going to use in your programs in some form or another.

Please also note that it would be a good idea to specify the size of the canvas that you are drawing onto using pixels.

Step 04 About drawing

In WebGL there are three types of drawing primitives: points, lines and triangles. The most widely used primitive is the triangle, as every 3D object in WebGL is composed of triangles. The programmer should give the coordinates of the triangles that compose the desired shape. For drawing a rectangle you will need to draw two triangles. Therefore, you will need an array with six points in 2D dimensions because each triangle needs three points in order to be defined.

Step 05 The aspect ratio

The programmer has to deal with the proportions of the WebGL native coordinate system. So, in order to make a square look like a square on-screen, you will have to calculate the aspect ratio. Then, you multiply the y values of each vertex by the aspect ratio and you are done.

Be careful of confusing the WebGL native coordinate system with the Cartesian coordinate system that is used for specifying the points in the programs you are using.

Drawing the rectangle using the correct aspect ratio requires the following changes to the code:

var AR = myCanvas.width / myCanvas.height;
var vertices = [-0.75, -0.75 * AR , 0.75, -0.75 * AR , 0.75, 0.75 * AR , -0.75, -0.74 * AR , 0.74, 0.75 * AR , -0.75, 0.75 * AR];

You can see from the output that the canvas has the same size as before, but the shape is now sketched as a square (see ‘aspectRatio.html’).

Step 06 The gl.drawArrays function

The WebGL function used for drawing is called drawArrays.

The first argument to the gl.drawArrays function specifies the drawing mode. If you want to draw a solid triangle, you will use gl.TRIANGLES. Alternatively, you can use gl.LINES and gl.POINTS for drawing lines and points respectively. The third argument of the function is really important because it declares the number of points that you will get as input. When you have problems with your output, check this parameter first.

Step 07 Draw multiple shapes on-screen

This part will show you how to draw multiple rectangles and triangles on-screen (see ‘multipleShapes.html’). Each shape will have its own colour. This method is particularly useful as it shows how to create autonomous functions that generate objects based on user-defined parameters. This means that you can create your own JavaScript library of useful functions that you can reuse. The secret is that you fill the WebGL buffer with data – that is, the shapes you want – until you finish with your drawing and then you display the buffer on screen!

Multiple objects
Multiple objects

Step 08 Explaining the code

The program uses an external JavaScript file with various help functions called ‘utils.js’. Its purpose is to avoid writing the same functions inside your scripts every time. Another important reason for using an external file is that if you find a bug or you make an improvement to an existing function, you only have to make changes to one file.

The two shaders are now stored in two separate

×