30
OCT
2009

Simple Vertex Shader for 2D Graphics

As I mentioned in an earlier post, OpenGL ES 2.x replaces the fixed function pipeline of OpenGL ES 1.x with a programmable pipeline. This means that you have to write a vertex shader program and a fragment shader program that perform the operations that the fixed function pipeline used to do. What you gain is an unprecedented level of flexibility as you are no longer restricted to hardwired calculations in the GPU.

The vertex shader processes polygon vertices and the fragment shader processes rasterized pixels. There are lots of tutorials and documentation on the basics of shaders, so I won't go into all the details. Suffice it to say that the vertex shader program is run once for each vertex in the polygon and the fragment shader is run for each polygon pixel to be drawn. Instead, I will show you a couple of examples of extremely basic vertex shaders.

Each polygon vertex has a position in 3D space. One of the primary responsibilities of the vertex shader is to project the vertex position into 2D space. By default, the OpenGL 2D coordinate system of the iPhone looks like this:

Without view projection matrix

This is an orthographic projection, which means there is no sense of perspective and the depth component of the vertex position is more or less ignored. For a (non-degenerate) polygon to be visible in the default coordinate system, at least one of its vertices would have to have an XY position within the range shown in the image.

The following vertex shader simply copies the position attribute of the vertex to the gl_Position variable, which is the predefined vertex position that will be used by the hardware when the polygon is rasterized and drawn.

attribute vec4 position;
 
void main()
{
    gl_Position = position;
}

This is probably really the simplest possible vertex shader you can write without hardcoding the position. However, you rarely want to use the default coordinate system, because it has an awkward aspect ratio and no perspective projection.

Let's say we want to create a 2D game where the coordinate system matches the resolution of the iPhone screen, which is 320x480 pixels. We wouldn't have to worry about perspective in this case, since we're not going to do 3D, so it's ok to still have an orthographic projection. Basically, we want a coordinate system that is more common when dealing with 2D pixel graphics in general, where the upper left corner is the origin. Here's an illustration of the coordinate system we want:

With view projection matrix

To accomplish this, we would have to create a view projection matrix that could be used to project the vertex position from our coordinate system to the default coordinate system. To perform the projection transformation in the vertex shader, we simply multiply the vertex position with the view projection matrix:

attribute vec4 position;
 
uniform mat4 viewProjectionMatrix;
 
void main()
{
    gl_Position = viewProjectionMatrix * position;
}

As you may have noticed, the position is represented by a vector with 4 components instead of 3. This is because the vector has to be expressed in homogenous coordinates for affine matrix transformations to be possible. If this makes no sense to you, it is safe (most of the time) to just accept that there has to be a 1 in the fourth component of the vector.

The last remaining piece of the puzzle is to create the view projection matrix, so that it can be fed to the vertex shader and bound to the viewProjectionMatrix variable. Those of you who have a perverted math fetish may go ahead and calculate the transformation matrix manually, but the rest of us will use a preexisting math library function instead. I highly recommend the free GLGX library for matrix and vector operations. It was created specifically for use with OpenGL. Moreover, GLGX is heavily inspired by the DirectX utility library D3DX. For almost every function in D3DX, there is a corresponding GLGX function.

Using GLGX, you would create the view projection matrix by using the following function call:

GLGXMatrixOrthoOffCenter2D(&viewProjectionMatrix, 0.0, 320.0, 480.0, 0.0);

I'm too lazy to go into how to bind the C matrix to the matrix variable in the vertex shader, so I'll leave it as an exercise to the reader for now.


About This Site

Hello, my name is Martin Johannesson and this is my home on the web. I live in Stockholm, Sweden, where I work as a software engineer at a software company.

Ever since I was a kid and discovered the art of programming on my C64, I've been tinkering with my own little software projects and experiments. This site is one such experiment.
more...

Recent Entries RSS Feed

Tags

Amiga blog C Cocoa game GLGX GLSL iOS iPad iPhone Java jQuery Mac Mac OS X Objective-C OpenAL OpenGL Programming REBOL Shaders Vertex Shader web

Blog Archive

2011: 01 02 03 04 05 06 07 08 09 10 11 12
2010: 01 02 03 04 05 06 07 08 09 10 11 12
2009: 01 02 03 04 05 06 07 08 09 10 11 12

Random Images Load new images

loading
loading
loading
loading
loading
loading
loading
loading
loading
loading
loading
loading