fruitfly

a technical blog

Practical Blender with GLKit – Part 1 – Introducing GLKit

with 21 comments

This is my first post for idevblogaday.com and I am quiet excited to be part of this community. The main reason to do this is so I do more constant iOS development. Hopefully I can keep up with the bi-weekly schedule.

With this post, I would like to start a series about the use of Blender for iOS game development. I will additionally base this series on the new iOS 5 framework GLKit. I will try to keep it rather practical and  assume knowledge of OpenGL ES and Blender basics. If that is not the case for you, I will give reference to some literature for self-learning:

The general idea for the different parts of the series is at the moment as follows:

  1. Introduction: Basically set up a GLKit-based project from ground. This will be rather a beginners-type topic to get started. As GLKit is a just newly introduced API in iOS 5 I think that it makes sense to spend a whole post on it.
  2. Blender and Python: I will try to introduce the powerful python scripting engine underneath Blender. How to write own scripts that access the modeled object and modify them.
  3. Blender Exporting: We will use Blender’s python scripting engine to write our own export-function to a custom 3D model format and write the corresponding model-loader for our GLKit project of Part 1.
  4. Blender Animations: We will extend our model to contain skeletal animation and add the necessary adjustments to our Blender export-script and our GLKit project.
  5. We will see what I can come up with. I am not this far yet.
Please note that this series is supposed to be rather practical on how to use GLKit and in specific Blender for game-development. So, I will assume knowledge on OpenGL and some self-teaching on Blender and Python (whatever basics you are missing). I will not try to write just another introduction to OpenGL and Blender as there are already plenty good out there that I will hint to.

OpenGL ES Links

If you have followed this blog before, you might know that I expect you to read some external resource on your own to get the necessary concepts if you don’t know them yet. So here, some external literature for OpenGL ES, if you need to refresh your knowledge:

Introduction

So what is actually GLKit? If you have been working with OpenGL ES 1 and its fixed-function pipeline a lot and then at some point in time tried to switch to OpenGL ES 2 with its shader-based freely programmable model (because Apple said this is the way to go), you know that this transition is not easy at first.
OpenGL ES 2 gives you great flexibility if you are an advanced developer in this area (unlike me) but you feel overwehlmed when you first see the Xcode template for it:
  • You have to learn the shader language
  • You have to write the code for loading, compiling and linking the shaders yourself (well, it is in the template; but anyway)
  • You have to set up the different buffers (pixelbuffer, depthbuffer, stencilbuffer, …) yourself (again; in the template, but it just leaves a bad feel in your stomach)
  • You loose a lot of the beloved APIs for manipulating the modelview and projection matrices.
The overhead when you start a new project is just quiet high. GLKit tries to tackel this and actually does this quiet well by replicating the fixed-function pipeline of OpenGL ES 1; so you can choose to do some basic rendering with the capabilities of the fixed-function pipeline and only resort to OpenGL ES 2 features for some advanced effects. Lets have a look.

Project Setup

Open up Xcode 4 and create a “Single View Application” named “GLKitAndBlender. I made it a “storyboard-based” application and Automatic-Reference-Counted  as it is the new hip thing to do; but note that we will not really need anything related to the storyboard as we only have one scene worth of information (our OpenGL view).
As we will use OpenGL ES and the new GLKit framework, add them both to the linked libraries in the Build Phase pane.

Link the project with GLKit and OpenGLES

Next, go to the autogenerated GLKitAndBlenderViewController.h header-file and give it the protocols, methods, and member as you see below:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#import <UIKit/UIKit.h>
#import <GLKit/GLKit.h>

@interface GLKitAndBlenderViewController : GLKViewController <GLKViewControllerDelegate, GLKViewDelegate> {
@private
    GLKBaseEffect *effect;
}

#pragma mark GLKViewControllerDelegate
- (void)glkViewControllerUpdate:(GLKViewController *)controller;

#pragma mark GLKViewDelegate
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect;

@end

We do four main things here:

  1. Define this controller as a subclass of GLKViewController. This controller plus the GLKView we will define in the next step in interface-builder save a lot of work in regard of automatically setting up a render-loop and managing the framebuffer.
  2. We make this controller its own delegate by implementing the GLKViewControllerDelegate protocol. This protocol defines the method glkViewControllerUpdate: that is called each time before a new frame will be render. You can use it for any kind of calculations that have to be performed prior to the actual rendering; so, the render-method itself is as lightweight as possible. In a game you might also use this method to update your game-physics and -state.
  3. We also implement the GLKViewDelegate that defines us our actual render-method glkView:drawInRect:.
  4. Also, don’t forget to import the GLKit header-files!
Additionally, we have defined a member of type GLKBaseEffect that we will see in action later. GLKit defines different effects that basically bundle vertex- and fragment shaders internally, and allow you to easily set the uniforms of the shaders via convenient properties.
GLKBaseEffect is the class that gives use the OpenGL ES 1 fixed-function pipeline very conveniently in the OpenGL ES 2 context. It will internally load the right shaders that implements the lightning-, texture- and material-model of the fixed-function pipeline. Lightning setup is no longer done via glLight(), glLightModel() and friends but with the methods/properties defined on GLKBaseEffect. Have a look in the API for details. We will shortly see the basics on setting up the modelview and projection matrices as only one example.
The next small step is to select the storyboard-file (this is a new feature of iOS 5 and basically a bundle of NIBs; so don’t be suprised that there is no MainMenu.xib) and make the view an instance of GLKView via the inspector on the right side. You might have to repeat this for the iPhone- or iPad-storyboard file depending on if you want use/test both.

Make the view an instance of GLKView

Reimplementing the Swinging Square

You might know the standard OpenGL ES template in XCode, that displays a swinging, multi-colored square. We will reimplement this with the help of GLKit and the GLKBaseEffect. Once you have that running, you have a minimal GLKit template and we have a good basis for the next part of the series.

Let’s first review the viewDidLoad-method:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
- (void)viewDidLoad
{
    [super viewDidLoad];

    EAGLContext *aContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];

    GLKView *glkView = (GLKView *)self.view;
    glkView.delegate = self;
    glkView.context = aContext;

    glkView.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;
    glkView.drawableDepthFormat = GLKViewDrawableDepthFormat16;
    glkView.drawableMultisample = GLKViewDrawableMultisample4X;

    self.delegate = self;
    self.preferredFramesPerSecond = 30;

    effect = [[GLKBaseEffect alloc] init];

    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
}

First, we set up the OpenGL Context (EAGLContext) for OpenGL ES 2 and set it on the GLKView (line 9). We also define us as the delegate for the GLKView and set some properties on the view so it can set up the framebuffer correctly.

From line 15 one, we first set us as the delegate for ourself (always good if you know how to help yourself!) and set the prefered framerate the GLKViewController will try to manage for us.

Oh; and we create an instance of GLKBaseEffect. If we look into the implementation of the GLKViewController delegate-method, we see what we can do with this effect-class:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
- (void)glkViewControllerUpdate:(GLKViewController *)controller
{
    static float transY = 0.0f;
    float y = sinf(transY)/2.0f;
    transY += 0.175f;

    GLKMatrix4 modelview = GLKMatrix4MakeTranslation(0, y, -5.0f);
    effect.transform.modelviewMatrix = modelview;

    GLfloat ratio = self.view.bounds.size.width/self.view.bounds.size.height;
    GLKMatrix4 projection = GLKMatrix4MakePerspective(45.0f, ratio, 0.1f, 20.0f);
    effect.transform.projectionMatrix = projection;
}

As OpenGL ES 2 is missing all the APIs to easily manipulate the modelview and projection matrix (except from within the vertex-shader), GLKit defines a rich set of methods to create and manipulate matrices. So, equivalent to the code

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslate3f(0, y, -5.0f);

we can do a GLKMatrixMakeTranslation() to create the translation-matrix and then set it on our GLKBaseEffect effect.transform.modelview-property. The internals will make sure to hand this over to the vertex-shader.

Same for defining our projection-matrix. Instead of glPerspective() in good ole OpenGL ES 1, we use GLKMatrix4MakePerspective() and set it on the effect-instance so these uniforms are internally passed to the shaders.

In fact, in the render-method, the first thing we have to do is call prepareToDraw on our GLKBaseEffect. Here the magic happends and the instance will bind uniforms/attributes that are internally defined and link the shaders. After that, it is rather standard OpenGL ES 2 code that defines verticies and colours for the vertecies and sticks them into the the standard glVertexAttribPointer-methods to feed them in the vertex-shader. Note though, that we have to use the GLKit constants GLKVertexAttribPosition and GLKVertexAttribColor so GLKit binds the attributes correctly to the variables in the shaders.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
    [effect prepareToDraw];

    static const GLfloat squareVertices[] = {
        -0.5f, -0.5f, 1,
        0.5f, -0.5f, 1,
        -0.5f,  0.5f, 1,
        0.5f,  0.5f, 1
    };

    static const GLubyte squareColors[] = {
        255, 255,   0, 255,
        0,   255, 255, 255,
        0,     0,   0,   0,
        255,   0, 255, 255,
    };

    glClear(GL_COLOR_BUFFER_BIT);

    glEnableVertexAttribArray(GLKVertexAttribPosition);
    glEnableVertexAttribArray(GLKVertexAttribColor);

    glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 0, squareVertices);
    glVertexAttribPointer(GLKVertexAttribColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, squareColors);

    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

    glDisableVertexAttribArray(GLKVertexAttribPosition);
    glDisableVertexAttribArray(GLKVertexAttribColor);
}

And, due to the glDrawArrays()-call we actually should see the swinging square when your run the project in the simulator. You can find the full project over at github.

The final result

So you see, GLKit is a quiet nice API that makes the transition to OpenGL ES 2 not so harsh. You get a great matrix-library and can also use the fixed-function pipeline from OpenGL ES 1 for some rendering where you are just fine with those capabilities.

And there is more: A class for easy texture-loading (GLKTextureLoader; no copying of  Texture2D into your project as the first action), skybox-effects (GLKReflectionMapEffect) and Quaternions (GLKQuaternion). All stuff that you normally have to redo/reimport into your project to even get started.

What I was missing a bit at first was a base-class to derive and define your own effects. So, basically, get at least some help in loading and linking the shaders with a nice object-oriented API (there only is a protocol GLKNamedEffect you can implement to define your own effects). But this is only a minor point compared to all the other stuff you get for free. And, I assume we can look forward to some quiet nice additional effect in iOS 6+.

Blender Links & Hints

In the next part, we will start to use some advanced Blender scripting features. So, I will assume some basic blender knowledge up front. Here comes a list of what has helped me a lot to get started:

  • The best resources can be found directly at blender.org in the Tutorials section. I basically did the introductory series and some advanced tutorials (1, 2) to model static objects. Once you have done the steps in the webcasts on your own, you should have a good overview of the basic blender features and check on advanced topics if you like. And don’t worry if you don’t get everything in the advanced tutorials; every part you get is great, the rest will come later.
  • A great online-resource is the Blender 3D: Noob to Pro series.
  • There is a great number of Blender video tutorials out there. Unfortunately, a lot are for older version. As the interface has been changed over time, be sure to look for the right tutorials; i.e. the interface in the webcasts should look the same as for your Blender version (presumable 2.5X) or you might not get the most out of it.
  • Blender has a lot of keyboard shortcuts and mastering them is the key in becoming a Blender guru. This keyboard shortcut sheet helped me a lot in that regard.
  • If you read this, chances are high that you work on a MacBook. Unfortunately, Blender makes good use of the numerical keypad and the third mouse-button for changing the viewport in the 3D view. So, I recommend using a three-button mouse for modeling. To at least emulate the 3-button mouse and the numerical keypad, there exist useful settings in the Preferences of Blender (File -> User Preferences): Check “Emulate 3-button mouse” to use Alt-left-mouse-button to rotate the 3D view and “Emulate numpad” to use the standard number-keys as a replacement for the num-pad. Don’t forget to press “Save as Default” if you want Blender to remember this until the next launch.

Check "Emulate 3-button mouse" and "Emulate numpad" on your MacBook

Have fun modeling. You will see Blender is just an amazing tool.

Written by 38leinad

October 19, 2011 at 10:36 am

21 Responses

Subscribe to comments with RSS.

  1. […] Practical Blender with GLKit – Part 1 – Introducing GLKit 12 OCT 0 Share Categories: iPhone, Programming Tags: iPhone, Programming /* […]

  2. […] the second part of this practical series on Blender for the use with GLKit-based iOS-applications. The first part focused on setting up a basic GLKit Xcode-project as the prerequisite for the following parts. As […]

  3. Hi 38leinad,

    This post is wonderful in terms of learning GLKit and Blender.
    I have been looking for a blog which can guide beginners on
    studying opengl es 2.0, blender, ios and finally I find this one.

    Thankyou 38leinad!

    Johnson Tsay

    November 4, 2011 at 5:30 pm

  4. Seems to be a problem in Xcode 4.2: –
    the lines below in the (void)viewDidLoad method cause errors: –

    self.delegate = self;
    self.preferredFramesPerSecond = 30;

    Semantic Issue: Property ‘delegate’ not found on object of type ‘GLKitAndBlenderViewController *’

    Semantic Issue: Property ‘preferredFramesPerSecond’ not found on object of type ‘GLKitAndBlenderViewController *’

    Can anyone help?

    Mick

    November 5, 2011 at 10:47 pm

    • Did you use the sample-code from github or develop the steps on your own?
      If the later, you maybe missed to make the GLKitAndBlenderViewController inherit from GLKViewController. Check your header-file:

      @interface GLKitAndBlenderViewController : GLKViewController {
      @private
      GLKBaseEffect *effect;
      MyModel *model;
      }

      38leinad

      November 5, 2011 at 11:03 pm

      • Thank you 38leinad, you’re right I missed the inherit 🙂

        Mick

        November 5, 2011 at 11:19 pm

  5. Great post., This is a much easier approach. Just one question:

    How do you implement lights and textures without making the shaders yourself?

    Justin

    January 30, 2012 at 1:42 am

  6. I have a big problem here. I have to reload the texture from the pvrtc file every single time it draws. I have managed to bring the frames per second up to twenty five, but reloading everything is extremely expensive. Using the same texture and OpenGL ES 2.0, I was able to average 63 frames per second. Would you mind helping me to debug the code (I may have to send the project to you)?

    Justin

    January 30, 2012 at 11:30 pm

  7. – (void)glkViewControllerUpdate:(GLKViewController *)controller

    should be in:

    -(void) update

    no?

    adam

    May 2, 2012 at 1:32 pm

  8. Also, your glPerspective call looks odd. This:

    GLKMatrix4 projection = GLKMatrix4MakePerspective(45.0f, ratio, 0.1f, 20.0f);

    seems it should be in radians, according to the Apple docs (var name is “F.O.V. for y, radians”) not degrees?

    adam

    May 2, 2012 at 5:42 pm

  9. ARGH! There’s an enormous bug in this code! It *WILL NOT WORK* correctly 😦

    You haven’t set your EAGLContext as “current” – without that, half of the OGL commands will simply be ignored (and things like the depth buffer won’t work).

    [EAGLContext setCurrentContext:aContext]; // do this before making any of your GL calls.

    adam

    May 2, 2012 at 9:45 pm

  10. Awesome post, but adam is right, there are some things missing in the code. I found that, to enable the Depth Buffer, I needed the following calls as well:

    GL.ClearDepth(30);
    GL.Enable(EnableCap.DepthTest);
    GL.DepthFunc(DepthFunction.Lequal);

    This is MonoTouch/C# code, but its easy to translate to Objective-C.

    Thank you!

    Jonas

    August 6, 2012 at 10:19 pm

    • you are right that it might make sense to enable the depth buffer if you want to tinker with some more advanced geometry, but the example i give does not real need/make use of depth buffering; so, i rather left it out.

      38leinad

      August 6, 2012 at 10:55 pm

  11. I tend not to leave a response, but after reading a few of
    the remarks on this page Practical Blender with GLKit – Part 1 – Introducing GLKit | fruitfly.
    I actually do have a few questions for you if it’s allright. Is it simply me or do some of these responses look like they are left by brain dead visitors? 😛 And, if you are posting on additional online social sites, I would like to keep up with you. Could you make a list of the complete urls of your public pages like your linkedin profile, Facebook page or twitter feed?

    binary options

    November 6, 2012 at 7:09 pm

  12. I know this web page provides quality depending articles and
    extra data, is there any other web site which provides such stuff in quality?

    disabled dating website

    April 21, 2013 at 11:52 am

  13. tnx!

    yoni

    July 24, 2013 at 12:39 pm

  14. […] Practical Blender with GLKit – Part 1 – Introducing GLKit […]


Any thoughts?