OpenGL Research
What is OpenGL

OpenGL is a low-level, 3D graphics and modeling library that is highly portable and very fast. It is used for rendering real-time 3D and 2D graphics such as games, music visualizations, screen savers and data visualizations on many platforms and systems like Windows, MacOS, Linux as well as mobile devices and gaming consoles. Essentially, OpenGL is an API that allows software programs to send drawing functions directly to the GPU (Graphics Processing Unit), located on a computer’s graphic card. Since graphic cards are designed and optimized for handling graphics, all the drawing and 3D rendering calculations are processed much faster on the GPU than on the computer’s CPU. OpenGL is an open standard API, developed and maintained by non-for-profit Khronos Group, which means that any graphic card manufacturer, such as Nvidea and ATI, are able to implement OpenGL in their hardware without any charges or royalties.
What OpenGL is NOT
- OpenGL is not a programming language
- It is not a game engine
- It is not a framework like Processing, OpenFrameworks (although these frameworks do use OpenGL)
- It is not able to create operating system windows or user interface objects
- It cannot read and write files
Without a programming language, OpenGL is useless. OpenGL requires a programming language to give it a window (called a context) to draw in, to allow user interaction, to create animations and provide it with data like 3D objects, textures and colours.
Virtually any programming language can execute OpenGL functions (C++, Java, Python, C# just to name a few), and it doesn’t matter which language is used, OpenGL will render the graphics the same way.
OpenGL is a procedural graphics API as opposed to descriptive. Instead of describing the 3D scene and how it should appear, the program needs to call OpenGL functions in a specific sequence in order to achieve a certain effect. These functions are used to draw graphics primitives such as points, lines, and triangles in a three-dimensional space. OpenGL also supports texture mapping, blending, transparency, animation, and many other special effects and capabilities.
My Research Approach
With the help of various tutorials and books, a list of which I provided in the end of the article, I created a web application that showcases some capabilities of OpenGL. I utilized a new technology called WebGL, which allows to execute OpenGL calls using Javascript withing a web browser. Keep in mind that WebGL is currently only available on the latest version of Google Chrome and Firefox (Safari and Opera should support it as well, although I haven’t tested it). Since the entire application is written in Javascript, and some HTML, the source code is available for anyone to view.
You may view the full application here: http://maxtherocket.com/projects/experimental/webgl/
Click left and right arrows to move through different scenes.
Process
I will outline the process of creating my application, but I will not go into too much technical detail. The description will cover the steps I had to take in order to render various 2D and 3D graphics, using OpenGL function calls. I will also display parts of the code that I used, if you are interested, full source code is available if you view the source on the page of my application.
Step 1 [Creating an OpenGL window]
WebGL lets you create an OpenGL window, it is actually called a context, inside an HTML5 element called CANVAS. Here’s the Javascript code that creates an OpenGl context, it executes as soon as the page loads:
canvas = document.getElementById("glcanvas");
initWebGL(canvas); // Initialize the GL context
// Here's the initWebGL() function
function initWebGL() {
gl = null;
try {
gl = canvas.getContext("experimental-webgl");
}
catch(e) {
}
// If we don't have a GL context, alert the user
if (!gl) {
alert("Unable to initialize WebGL. Your browser may not support it.");
}
}
After the gl object has been initialized, it will contain all the OpenGL functions.
And HTML code for the canvas element, which sets up the dimensions of the OpenGL window:
<canvas id="glcanvas" width="640" height="480"></canvas>
In a language like C++ creating the window for OpenGL would be different since you would have to create an operating system window.
Step 2 [Set a couple settings]
We need to tell OpenGL how to render the geometry that we’ll be creating in the 3D scene.
gl.enable(gl.DEPTH_TEST); // Enable depth testing, so 3D objects don't overlap each other gl.depthFunc(gl.LEQUAL); // Near things will obscure far things, this can be set the other way around, which would be weird
Step 3 [Setup Shaders] (This one is important!)
Shaders in OpenGL play a very important role. Shader code tells the hardware, the GPU, how to render 3D shaped in perspective and how to colour them. Without shaders, OpenGL cannot render anything. Shaders are written in a language very similar to C, called GLSL (GL Shading Language). Shaders come in 2 parts, a vertex shader and a fragment shader.
- The vertex shader manipulates each 3D point that we load into the OpenGL scene
- The fragment shader is responsible for colouring the objects and it manipulates each pixel of an object
Here’s is the source code for the basic shaders that I used in my application:
Vertex Shader
// This is the Vertex shader
// This little program loops through each 3D point (a vertex) that the OpenGL has in the scene
attribute vec3 aVertexPosition; // This variable contains a single 3D point, each point gets passed into this variable as the program loops through vertices
uniform mat4 uMVMatrix; // A translation matrix, used for moving/rotating shapes in 3D space
uniform mat4 uPMatrix; // Perspective matrix, creates the 3D look, pretty much a camera
void main(void) {
gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0); // This is where the point gets translated from 3D space to 2D space
vColor = aVertexColor; // Here we're just passing the color of a vertex along to the fragment shader
// there's no need to have this last line if we don't use the colours from vertices
}
Fragment Shader (Pixel Shader)
// This is the fragment shader
void main(void) {
// gl_FragColor is an OpenGL variable, it will draw the color that we pass it
// with the variable set to vec4(1.0, 1.0, 1.0, 1.0) OpenGL will color all objects plain white
// vec4 is a data type, vec4 stands for: vector with 4 values
// each of the values represent a color vec4(red, green, blue, opacity)
// By setting all the values to 1, we get white
gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
}
Shaders are very powerful, since they loop through every 3D point and every pixel for each frame of rendering (and it’s all done really fast). The colour of each pixel can be changed based on its relation to other pixels, 3D points and lights in the scene. 3D points can be modified as well through a vertex shader as well.
This is how I initialized the shaders in WebGL:
// Create a place for a shader in OpenGL memory shader = gl.createShader(gl.FRAGMENT_SHADER); // Load the shader source code gl.shaderSource(shader, theSource); // Compile the shader gl.compileShader(shader);
Step 4 [Adding Geometry]
Since the code for geometry gets fairly lengthy, I will only explain here the steps required to create a square shape in OpenGL.
In OpenGL, all geometry is created with points. There is a way to tell OpenGL how to connect and fill the points that you create. OpenGL offers 10 different drawing modes, each will render the points differently. Here’s a good graphic that showcases all the modes:
I passed 4 points into OpenGL geometry buffer and then used a mode called TRIANGLE_STRIP to draw the square shape.
// this creates a place in GPU memory for our array of points
squareVerticesBuffer = gl.createBuffer();
// then we 'bind' the buffer, get the memory ready to receive the points
gl.bindBuffer(gl.ARRAY_BUFFER, squareVerticesBuffer);
// Here's our list of 4 points
// each line represents a point in 3D space
// the order is x, y, z
// we leave the z as 0 since we are drawing a 2D shape
// The center of the square will be at coordinate 0,0,0
var vertices = [
1.0, 1.0, 0.0, // top right
-1.0, 1.0, 0.0, // top left
1.0, -1.0, 0.0, // botom right
-1.0, -1.0, 0.0 // bottom left
];
// Now pass the list of vertices (points) into WebGL to store the shape
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);

All objects created in OpenGL are automatically positioned at point 0x,0y,0z, and that point, in the cartesian coordinate system, is usually placed at the center point of the OpenGL window. When creating vertices for an object we have to keep in mind that all the points extend from the center of the object, so a vertex at position (1.0x ,1.0y, 0z) means that it’s positioned 1 unit of x and 1 unit of y away from the center of the screen.
Now that we stored the points in OpenGL memory we have to pass the vertices to the vertex shader and tell OpenGL to draw this shape.
Step 4 [Drawing]
Before we draw anything to the screen we need to clear the canvas. If we are animating something, we’ll need to clear the canvas on each frame and then re-draw everything again. This might seem counter-intuitive but, at lower level, that is how real-time computer animations works. So each frame we have to keep track of the position and states of each object.
Here’s how to clear the screen:
// Clear the canvas before we start drawing on it. gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
Then we need to create a perspective matrix, this matrix will tell the vertex shader how to render the 3D scene to a 2D image. This matrix acts as a camera that shows us the 3D scene.
I used special helper functions to create this camera matrix:
// Establish the perspective with which we want to view the // scene. Our field of view is 45 degrees, with a width/height // ratio of 640:480, and we only want to see objects between 0.1 units // and 100 units away from the camera. perspectiveMatrix = makePerspective(45, 640.0/480.0, 0.1, 100.0); // THis matrix gets passed to the vertex shader later on
If you are interested, you can view the full function in the glUtils.js file, it contains various 3D matrix helper functions.
// Get the points from memory gl.bindBuffer(gl.ARRAY_BUFFER, squareVerticesBuffer); // Pass the points array to the vertex shader (I initialized vertexPositionAttribute earlier in the program) gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0); // Tell OpenGL to draw gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
The drawArrays function simply tells OpenGL to execute the shaders, passing the number of points to take from the array and the mode to draw them with, which will then draw inside the window.
The steps I outlined above explain how to draw a simple 2D shape in OpenGL using Javascript. I also explained a fair bit about how OpenGL works. In my demo application, I have examples of animation, use of colour and texturing a 3D object. Below, I will briefly explain how these features we implemented.
Using Colour

Instead of colouring the entire shape with one colour, we can give each vertice it’s own colour. The cool thing about OpenGL is that the shaders will automatically fill the space between the vertices with a gradient, if the colours of each vertex is different. Just look at the image on the left. I gave each corner vertex a different colour and OpenGL figured out the rest. If I gave each vertex the same colour, the square would have been a solid colour.
Here’s how I set the colours using Javascript:
var colors = [ 1.0, 1.0, 1.0, 1.0, // white 1.0, 0.0, 0.0, 1.0, // red 0.0, 1.0, 0.0, 1.0, // green 0.0, 0.0, 1.0, 1.0 // blue ]; squareVerticesColorBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, squareVerticesColorBuffer); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
As you can see, this is very similar to how I created the points for the square. The number of colours has to be the same as the number of points in an object.
3D Objects

Theres are no 3D primitives in OpenGL, no cubes, no spheres, no cylinders, every 3D object has to be created by using vertices. So to create a 3D cube I had to create vertices for 6 different squares and place them accordingly within the 3D space. In OpenGL all 3D objects have to be constructed from 2D planes, which are placed together tightly, to make the objects look solid. There’s no magic for creating 3D objects, just lots of code.
Animation
Im the demo application I am rotating a 3D cube. In order to rotate the object OpenGL I had to apply another matrix, on top of the perspective matrix, to the object’s vertices inside the vertex shader, this matrix is called a transformation matrix. The transformation matrix modifies the position, rotation and scale of the object’s coordinate system and, as a result, transforms the object.
This is the code I am using to set the rotation matrix of the cube:
mvRotate(rotation, [1, 0, 1]);
function mvRotate(angle, v) {
var inRadians = angle * Math.PI / 180.0;
var m = Matrix.Rotation(inRadians, $V([v[0], v[1], v[2]])).ensure4x4();
multMatrix(m);
}
The mvRotate function accepts an angle of rotation and a vector representing the axis of rotation. It then uses some helper math function from a math library called Sylvester to generate that matrix. I increment the rotation variable on each frame so that the angle of rotation increases, causing the cube to spin. The translation matrix could affect many objects at once or just one object, depending on how many objects are rendered using the matrix.
This is the part of the shader code that applies the transformation matrix (it’s called uMVMatrix)
gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
Image Texture

Applying an image texture onto a 3D object requires a few extra steps. We need to first load the image into the OpenGL buffer and tell it how to treat it (wich scaling functions to use when scaling the image). Then we need to tell OpenGL how to place the image onto an object through an array of texture coordinates. We then need to use modify the shader to grab the colour for each pixel on the object from the image.
This is the code for loading the image from a url to the OpenGL buffer:
// This function loads the image from a url, when the image finishes loading an OpenGL texture gets created
function initTextures() {
cubeTexture = gl.createTexture();
cubeImage = new Image();
cubeImage.onload = function() { handleTextureLoaded(cubeImage, cubeTexture); }
cubeImage.src = "images/fridge.jpg";
}
function handleTextureLoaded(image, texture) {
gl.bindTexture(gl.TEXTURE_2D, texture); // Bind texture
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image); // Create texture from image
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); // Scaling functions for enlarging
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST); // Scaling functions for sizing down
gl.generateMipmap(gl.TEXTURE_2D);
gl.bindTexture(gl.TEXTURE_2D, null); // Complete
resetBuffers();
}
This is the code for specifying texture co-ordinates. Pretty much we’re just telling OpenGL how to place the image on the object. These points mean that the corners of the image should be placed on the corners of the square.
var textureCoordinates = [ // Front 0.0, 0.0, // Top left 1.0, 0.0, // Top right 1.0, 1.0, // Bottom right 0.0, 1.0, // Bottom left // Back 0.0, 0.0, 1.0, 0.0, ....
This is a part of the new shader code that reads the colour of each pixel in the image and applies it onto the object:
gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
Conclusion
WebGL provides a direct access to OpenGL, without much abstraction (I refer to abstraction as helper classes and functions that help create primitive 3D shapes, lights and provide ways to easily add colour and texture to objects). This low-level access to OpenGL functions, through WebGL, helped me to get a better understanding of how OpenGL works.
While OpenGL is very powerful, it also requires a lot of code, especially the process of creating objects and adding colours and textures to those objects. I think it is more productive if those tasks are done through abstracted classes and helper functions. Game engines and frameworks like Processing and OpenFrameworks already do these abstractions, and do them well. The main benefit of digging deeper into OpenGL comes from mastering the shading language. Since shaders offer a powerful, hardware optimized, way to manipulate how objects get drawn to the screen, learning the OpenGL shading language is a critical skill to have when working with real-time 3D graphics.
Unfortunately, during my research I barely had a chance to learn how to create custom shaders, since all my time went into learning how to create objects and setting up OpenGL for rendering. My next step is to get a better understanding of shaders and attempt to create my own. I will use a framework for dealing with object creation, such as OpenFrameworks, so that I can focus just on OpenGL shader development.
My name is Max Rusan. I work with different kinds of digital media. I love learning and working with new technologies. It would take too long to describe all my skills so just have a look around my blog. Contact me: max at maxtherocket.com 





