GLKit Tutorial for iOS: Getting started with OpenGL ES

Learn how to use OpenGL ES in iOS in this GLKit tutorial. You’ll go from fresh project to spinning cube rendered using OpenGL and learn all the theory along the way! By Felipe Laso-Marsetti.

Leave a rating/review
Download materials
Save for later
Share
Update note: This tutorial has been updated to Swift 4.1 and Xcode 9.3 by Felipe Laso-Marsetti. The original tutorial was written by Ray Wenderlich.

If you’re interested in graphics programming, chances are that you’ve read about OpenGL, which remains the most-adopted API from a hardware and software perspective. Apple has developed a framework called GLKit to help developers create apps that leverage OpenGL and to abstract boilerplate code. It also allows developers to focus on drawing, not on getting the project set up. You’ll learn how all of this works in this GLKit tutorial for iOS.

GLKit provides functionality in four areas:

  • Views and View Controllers: These abstract much of the boilerplate code that GLKit uses to set up a basic OpenGL ES (Embedded Systems) project.
  • Effects: These implement common shading behaviors and are a handy way of setting up basic lighting, shading, reflection mapping and skybox effects.
  • Math: Provides helpers and functions for common math routines like vector and matrix manipulation.
  • Texture Loading: Makes it much easier to load images as textures to be used in OpenGL.
Note: You will use OpenGL ES 3.0, which is available on iPhone 5S and above, iPad Mini 2 and above, and iPad 5th generation and above.

Without further ado, it’s time to get started!

Getting Started

The goal of this tutorial is to get you up-to-speed with the basics of using OpenGL with GLKit, assuming you have no previous experience with this whatsoever. You will build an app that draws a cube to the screen and makes it rotate.

There’s no starter project for this tutorial. You’re going to make it all from scratch!

Open Xcode and create a brand new project. Select the iOS\Application\Single View App template.

Set the Product Name to OpenGLKit and the Language to Swift. Make sure none of the checkboxes are selected. Click Next, choose a folder in which to save your project and click Create.

Build and run. You’ll see a simple, blank screen:

Introducing GLKView and GLKViewController

Here’s where the fun begins! Open ViewController.swift and replace its contents with:

import GLKit

class ViewController: GLKViewController {

}

You need to import GLKit and your view controller needs to be subclass of GLKViewController.

GLKit is supported in Interface Builder, so this is the best way to set it up. Do that now.

Open Main.storyboard and delete the contents of the storyboard. Then, from the Object Library, drag a GLKit View Controller into your scene.

In the Identity inspector, change the class to ViewController. In the Attributes inspector, select the Is Initial View Controller checkbox.

Finally, change the Preferred FPS to 60:

With the Attributes inspector open, click the GLKView in the canvas and notice some of the settings for color, depth and stencil formats, as well as for multisampling. You only need to change these if you’re doing something advanced, which you’re not here. So the defaults are fine for this tutorial.

Your OpenGL context has a buffer that it uses to store the colors that will be displayed to the screen. You can use the Color Format property to set the color format for each pixel in the buffer.

The default value is GLKViewDrawableColorFormatRGBA8888, meaning that eight bits are used for each color component in the buffer (four total bytes per pixel). This is optimal because it gives you the widest possible range of colors to work with which means the app will look more high quality.

That’s all the setup you need to do in the storyboard. Your view controller is set up with a GLKView to draw OpenGL content into, and it’s also set as the GLKViewDelegate for your update and draw calls.

Back in ViewController.swift, add the following variable and method:

private var context: EAGLContext?

private func setupGL() {
  // 1
  context = EAGLContext(api: .openGLES3)
  // 2
  EAGLContext.setCurrent(context)

  if let view = self.view as? GLKView, let context = context { 
    // 3
    view.context = context
   // 4 
    delegate = self
  }
}

Here’s what’s happening in this method:

An EAGLContext manages all of the information that iOS needs to draw with OpenGL. It’s similar to needing Core Graphics context to do anything with Core Graphics. When you create a context, you specify what version of the API that you want to use. In this case, you want to use OpenGL ES 3.0.

OpenGL contexts should not be shared across threads, so you will have to make sure that you only interact with this context from whichever thread you used to call this method `setupGL()`.

  1. To do anything with OpenGL, you need to create an EAGLContext.
  2. Specifies that the rendering context that you just created is the one to use in the current thread.
  3. This sets the GLKView’s context. After unwrapping the necessary variables, you set the GLKView‘s context to this OpenGL ES 3.0 context that you created.
  4. This sets the current class (ViewController) as the GLKViewController’s delegate. Whenever state and logic updates need to occur, the glkViewControllerUpdate(_ controller:) method will get called.

Having done this, add the following to implement viewDidLoad() to call this method:

override func viewDidLoad() {
  super.viewDidLoad()
  setupGL()
}

So now you know which thread called `setupGL()` — it’s the main thread, which is the special thread that is dedicated to interactions with UIKit and that is used by the system when it calls `viewDidLoad()`.

At this point, you may notice that there’s an error. This is because you’re not conforming to GLKViewControllerDelegate yet. Go ahead and make it conform by adding the following extension:

extension ViewController: GLKViewControllerDelegate {
  func glkViewControllerUpdate(_ controller: GLKViewController) {

  }
}

Next, add the following method to the ViewController main class definition:

override func glkView(_ view: GLKView, drawIn rect: CGRect) {
  // 1
  glClearColor(0.85, 0.85, 0.85, 1.0) 
  // 2
  glClear(GLbitfield(GL_COLOR_BUFFER_BIT))
}

This is part of the GLKViewDelegate, which draws contents on every frame. Here’s what it does:

  1. Calls glClearColor to specify the RGB and alpha (transparency) values to use when clearing the screen. You set it to a light gray, here.
  2. Calls glClear to actually perform the clearing. There can be different types of buffers like the render/color buffer you’re displaying right now, and others like the depth or stencil buffers. Here you use the GL_COLOR_BUFFER_BIT flag to specify that you want to clear the current render/color buffer.

Build and run the app. Notice how the screen color has changed: