OpenGL ES 2.0 iOS Tutorial – Getting Started

So you’re here to learn OpenGL ES 2.0. Great, it’s indeed a lot of fun! Many people may say that learning OpenGL is difficult, but all things in life are difficult before we know them, right? All you need is some patience. I know there are quite a few tutorials on this topic out there already, but I’m sure there is room for another. I remember being new to OpenGL myself, and I know how complex it can appear in the beginning. Have faith, though! It’s extremely rewarding once you’re starting to grasp it.

OpenGL ES 2.0 is a broad subject, so where do we start? I’d say we start from the very beginning.

In case you want to jump straight into the action, this project can be downloaded from GitHub.

1. Create an Xcode project

You already know how to create a new project, don’t you? Then go to your target and select “Build Phases”. Expand the “Link Binary with Libraries” list and add “OpenGLES.framework” and “QuartzCore.framework”. Your target should now look something like this:

Next, we make these frameworks available to all files by adding them to our prefix file.

So let’s create a view controller. I prefer a simple one, all below code will be written in the viewDidLoad method, so that’s really the only method we need here.

Finally, we need somewhere to display our OpenGL content. For that we need a custom subclass of a UIView, let’s name it GLView. It needs only one method for this tutorial, layerClass, and that should return the CAEAGLLayer class.

2. Create a context

Now, go to the viewDidLoad method of the view controller. All code from now on goes in that method. We start out by creating a context. The context is what keeps everything together. Without it, we can’t do anything, so we’d better create it. Luckily, it’s easy!

EAGLContext *context = [[[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2] autorelease];
[EAGLContext setCurrentContext:context];

The parameter kEAGLRenderingAPIOpenGLES2 states that we are targeting version 2.0 of OpenGL ES. This is supported on iPhone 3GS and up and unless you really, really want to target older devices, I would advice you to forget about kEAGLRenderingAPIOpenGLES1. OpenGL ES 2.0 is the future. And a lot more fun!

3. Create a view

The view is of course also really important, since we need somewhere to draw. Since it’s a subclass of UIView, we can just create it like usual.

GLView *glView = [[[GLView alloc] initWithFrame:CGRectMake(0, 0, 320, 320)] autorelease];
[self.view addSubview:glView];

4. Create a renderbuffer

Unfortunately, OpenGL can’t draw directly to our GLView, but it can draw to something called a renderbuffer. That’s where the actual pixel data is stored. So what we do is that we draw to the renderbuffer, and then later we transfer our drawing to the glView. Doesn’t sound that complicated, right? Creating the renderbuffer is a three step process.

GLuint renderbuffer;
glGenRenderbuffers(1, &renderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);

1. Create an unsigned integer.
2. Let OpenGL generate a renderbuffer for us.
3. Bind the renderbuffer to GL_RENDERBUFFER. Binding is like saying to OpenGL “Hey! From now on, whenever I say GL_RENDERBUFFER, I really mean the renderbuffer (unsigned integer) that I created earlier”. In other words, GL_RENDERBUFFER becomes an alias of ‘renderbuffer’.

[context renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer*)glView.layer];

Finally, let OpenGL create storage for the pixels that we’re going to draw to. The context can help us with that. By passing the glView.layer, the context calculates how many pixels we need and allocates memory for them. The other thing we’re passing is GL_RENDERBUFFER, which now means ‘renderbuffer’ as we just described.

5. Create a framebuffer

You may be a bit confused now. Why the heck do we need a framebuffer when we already have a renderbuffer. Aren’t those the same thing? No, not really. The framebuffer contains the renderbuffer. It can also contain other things, like a depth buffer that stores depth values for each pixel, but we don’t need that now. In this example, the only thing the framebuffer contains is pixel color information. Creating the framebuffer is a three step process, very similar to creating the renderbuffer.

GLuint framebuffer;
glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer);

1. Create an unsigned integer.
2. Let OpenGL generate a framebuffer for us.
3. Bind it. When we have bound it GL_FRAMEBUFFER now means ‘framebuffer’. The last thing we need to do is to connect the framebuffer and the renderbuffer. This is done by glFramebufferRenderbuffer. GL_COLOR_ATTACHMENT0 defines that the renderbuffer we’re passing holds color information (pixels), not depth information. Since the framebuffer also can contain a depth buffer, we need to be clear on this.

6. Draw!

Now everything is set up for us to draw! The easiest way for us to output something to the renderbuffer is to define a clear color, and then clearing. This is easy.

glClearColor(1, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);

1. glClearColor defined the color we want to with four parameters, RGBA. We like red so we’re setting a red color with full alpha, but you can modify that to the color of your choice. Colors are defined from 0 to 1 instead of 0 to 255.
2. glClear “draws” our red color to the renderbuffer.

7. Transfer the pixels to our view

We have now drawn some nice red pixels to the renderbuffer. All we need now is to transfer those pixels to our view. This is done by presentRenderbuffer. And remember, GL_RENDERBUFFER, points to our renderbuffer.

[context presentRenderbuffer:GL_RENDERBUFFER];

You should now see a red 320x320px square in your view controller. It may not be the most exciting thing you’ve ever seen, but it’s a great start!

8. That’s all, folks!

That wasn’t so hard, was it? The next tutorial is about shaders. Drawing a Square.

2 Responses to OpenGL ES 2.0 iOS Tutorial – Getting Started
  1. Bilo Can Reply

    Hi,

    How do we now what files to add the prefix file? And how do you add them? Just manually typing the header files we need or use some shortcut?

  2. Anton Holmquist Reply

    I’ve added the Quartz and OpenGLES framework header files to the prefix file so that they are accessible from all files without importing. It’s just convenience really. I just write them manually, but let me know if you find a quicker way to do it!

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

About Me

I am developer based in Stockholm. For as long as I can remember I have been fascinated by code. My best lines of code are written at night.
Co-founder of Monterosa. Learning node.js at invoise.com.