FCS(2) - OpenGLで描画!GLKitを活用しよう

QuartzのベースにはOpenGLの技術がつかわれていますので、OpenGL ESベースでアプリを作ってみましょう。

XCodeの新規プロジェクト作成を選ぶと、このようにOpenGL Gameというテンプレートがあらかじめ用意されていますので、それを選びます。

このテンプレートにはOpenGLベースのアプリを作る準備が一通りそろっています。プロジェクト作成後、ビルドして実行すると、このように2つの立方体が回転しながら表示されます。

テンプレートから生成されるコードには、OpenGLで必要な初期セットアップやアニメーション表示のための定期的なコールバックの仕組みが用意されています。また描画の仕組みも、OpenGL ES 2.0のシェーダーを使ったもの(青い立方体)と、Appleが用意したGLKitと呼ばれるシェーダーを直接呼ばなくてもOpenGL ES 2.0の機能を簡単に使えるもの(赤い立方体) の2種類が用意されています。

いきなりシェーダーでバリバリ実装をするのは敷居が高いので、今回はGLKitを使ってみましょう。

最初に作成されるViewControllerは、通常UIViewControllerですが、テンプレートでOpenGL Gameを選んだ場合、GLKViewControllerというOpenGL ESの描画の制御がしやすいクラスがベースクラスとして設定されます。

@interface FCBViewController : GLKViewController

@end

また、Viewも通常はUIViewですが、これもGLKViewというOpenGL用のUIViewになっています。GLKViewControllerでGLKViewをviewとして設定すると、

Note: When you set the view property to point to a GLKView object, if the view does not already have a delegate, then the view controller is automatically set as the view’s delegate

このように自動的にdelegateもセットされますから、GLKViewDelegateのglkView:drawInRect: を実装することで、フレーム毎の再描画が簡単に実現できます。

では、まずdrawInRectで、シェーダーによる描画をコメントアウトして、GLKitだけの描画にしてみましょう。

- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
    glClearColor(0.65f, 0.65f, 0.65f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glBindVertexArrayOES(_vertexArray);

    // Render the object with GLKit
    [self.effect prepareToDraw];

    glDrawArrays(GL_TRIANGLES, 0, 36);

#if 0
    // Render the object again with ES2
    glUseProgram(_program);

    glUniformMatrix4fv(uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX], 1, 0, _modelViewProjectionMatrix.m);
    glUniformMatrix3fv(uniforms[UNIFORM_NORMAL_MATRIX], 1, 0, _normalMatrix.m);

    glDrawArrays(GL_TRIANGLES, 0, 36);
#endif
}

このように、glUseProgramから2回目のglDrawArraysまでをifマクロでコメントアウトしてみます。そうすると、下の左の画像のように、赤い立方体だけが表示されるようになったかと思います。

これでGLKitのみの描画になりました。以下のシェーダー関連のメソッドは必要ありませんので削除してしまいましょう。

- (BOOL)loadShaders;
- (BOOL)compileShader:(GLuint *)shader type:(GLenum)type file:(NSString *)file;
- (BOOL)linkProgram:(GLuint)prog;
- (BOOL)validateProgram:(GLuint)prog;

また、最初は視点を固定した2次元描画を行いますので、updateメソッドの最初でreturnしてしまいます。

- (void)update
{
    // Disable rotation.
    return;

    float aspect = fabsf(self.view.bounds.size.width / self.view.bounds.size.height);
    GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(65.0f), aspect, 0.1f, 100.0f);
    ...
}

そうすると上の右の画像のように画面サイズの比率と同じ比率の黒い四角形が表示されると思います。これがZ軸から投影した画面比率調整をする前の立方体の画像です。

これで2次元描画の準備が整いましたので、次からは実際の描画に移りたいと思います。