2011年10月19日星期三

Practical Blender with GLKit – Part 1 – Introducing GLKit [38leinaD]

Practical Blender with GLKit – Part 1 – Introducing GLKit [38leinaD]:
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 an 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 replicate 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” with name “GLKitAndBlender. I made it as 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 for us 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 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 if 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 made major changes 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 to become a Blender guru. This keyboard shortcut sheet helped me to at least get to a level a little above “Noob”.
  • If you read this, chances are high that you own 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.



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



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

没有评论:

发表评论