macOSでOpenGLプログラミング（2-6. 頂点データにGLKitの構造体を使う）

[macOSでOpenGLプログラミングの目次に戻る](https://qiita.com/sazameki/items/d060f20f621c658046d9)

# はじめに

[前回](https://qiita.com/sazameki/items/8529169d355df667bed6)までで、テクスチャを複数枚組み合わせて表示できるようになりました。

今回はGLKitの構造体を使って、2〜4次元のベクトルや、4x4行列や、クォータニオンといった、ゲーム開発には必須になってくる数学ライブラリが利用できるように準備しましょう。


# 1. ヘッダファイルのインクルード

GLKitで定義されているベクトル、行列、クォータニオンを表す構造体を使うためには、GLKitのGLKMath.hをインクルードします。GLKitフレームワークは[第1回](http://qiita.com/sazameki/items/12adb193dc1472c6316a)でプロジェクトを作成した直後に追加していますので、ヘッダファイルをインクルードするだけで簡単に利用できます。

```cpp:Game.hpp（一部）
...
#include <OpenGL/OpenGL.h>
#include <OpenGL/gl3.h>
#include <GLKit/GLKMath.h>
...
```

なお、GLKitフレームワークのすべての機能を利用するためには、通常は`#import <GLKit/GLKit.h>`と書きますが、これはObjective-Cの機能を利用するため、C++を併用する時には関連の実装ファイルの拡張子を「.mm」にしなければいけません。これまで使ってきたGame.cppではPure C++で実装を進めていきたいと思いますので、GLKit.hは使いません。GLKMath.hからは、C言語でもC++でも利用可能な構造体や関数のみが定義されたファイルがインクルードされますので、こちらを使います。

これでベクトルを表すGLKVector2, GLKVector3, GLKVector4などの構造体、行列を表すGLKMatrix4構造体、クォータニオンを表すGLKQuaternion構造体が利用できるようになります。また、それらに関係した関数も使えるようになります。


# 2. 頂点データの定義をGLKitの構造体で置き換える

GLKitフレームワークが提供する構造体が利用できるようになったので、Game.cppでGLfloat型の配列を使って定義してきた頂点データを表すVertexData構造体を、これらの構造体を使うように変更します。

```cpp:Game.cpp（VertexData構造体―変更前）
struct VertexData
{
    GLfloat     pos[3];
    GLfloat     color[4];
    GLfloat     uv[2];
};
```

```cpp:Game.cpp（VertexData構造体―変更後）
struct VertexData
{
    GLKVector3  pos;
    GLKVector4  color;
    GLKVector2  uv;
};
```

これに伴って、VAOから参照するバッファのフォーマットを指定するための`glVertexAttribPointer()`関数を呼び出している箇所の修正が必要になります。配列の時には変数名を直接書くだけでポインタ値が取得できますが、これが構造体になったので、`&`演算子を使ってポインタ値を取得するように変更します。

```cpp:Game.cpp（Game::Game()―変更前）
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), ((VertexData *)0)->pos);
    glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(VertexData), ((VertexData *)0)->color);
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(VertexData), ((VertexData *)0)->uv);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
```

```cpp:Game.cpp（Game::Game()―変更後）
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), &((VertexData *)0)->pos);
    glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(VertexData), &((VertexData *)0)->color);
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(VertexData), &((VertexData *)0)->uv);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
```

以上の変更が完了したら、実行してみましょう。前回までの動作と変わらないことが確認できます。

　<img width="420" src="https://qiita-image-store.s3.amazonaws.com/0/166309/ca87e30e-6044-1222-8e7f-1fd839eb052c.png">

ここまでのプロジェクト：[MyGLGame_step2-6.zip](http://sazameki.jp/temp/MyGLGame_step2-6.zip)


# 3. まとめ

今回はこれだけです。Game.cppで使っているPure C++からも、GLKitフレームワークの構造体やそれに関する関数が利用できるので、今後はそれを使ってゲーム開発を進めていきましょうというお話でした。

OpenGLは、それ自体は、ベクトルや行列を扱うための構造体やクラスを提供していません。そのため、OpenGLでベクトルや行列を扱うためには、それらのクラスを自分で作成するか、既存のライブラリやフレームワークを利用する必要があります。

OpenGL用の数学ライブラリとして有名なものに、[GLM (OpenGL Mathematics)](https://glm.g-truc.net/0.9.8/index.html)というライブラリがあります。WindowsやLinuxでもコンパイルしたい場合は、こちらを使うのがおすすめです。

---
次の記事：[macOSでOpenGLプログラミング（3-1. 行列を使わずに3Dの透視変換を行う）](http://qiita.com/sazameki/items/916f06f7c391d8727eba)