macOSでOpenGLプログラミング（3-6. GLKitのプロジェクション行列を使う（左手座標系→右手座標系））

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

# はじめに

[前回](https://qiita.com/sazameki/items/958c26aa8f45ba794279)は、プロジェクション行列を自分で計算する方法について解説しました。もちろんこうして自前で用意した行列を使っても良いのですが、macOSで利用できるGLKitには、「[macOSでOpenGLプログラミング（その10. テクスチャを表示する）](https://qiita.com/sazameki/items/857720471e1be85210f2)」で解説したテクスチャの読み込み機能に加えて、プロジェクション行列などのよく使う行列を求めるための関数も用意されています。

今回はプロジェクション行列を求めるためのGLKitの関数、`GLKMatrix4MakePerspective()`を使って、奥行きを表現してみましょう。

ちなみに、`GLKMatrix4MakePerspective()`と同等の関数として、[OpenGL Utility Libraries (GLU)](https://www.opengl.org/resources/libraries/)の`gluPerspective()`関数、[OpenGL Mathematics (GLM)](https://glm.g-truc.net/)の`glm::perspective()`関数などがありますが、いずれも同じ計算をしてくれますので、これらの関数を採用する場合でも同じです。

# 1. Z座標の値を右手系に書き換える

これまでの記事では、GLSLのクリッピング座標に合わせて、原点(0, 0, 0)にあるカメラから、Z軸のプラス方向にあるデータを描画することを前提に解説してきました。すなわち、左手座標系でデータを考えてきたわけです。

```cpp:Game.cppにおける頂点データの宣言(Old)
    std::vector<VertexData> data;
    data.push_back({ { -0.6f, -0.5f, 5.0f }, { 1.0f, 0.4f, 0.7f, 1.0f } });
    data.push_back({ {  0.4f, -0.5f, 5.0f }, { 1.0f, 0.4f, 0.7f, 1.0f } });
    data.push_back({ {  0.4f,  0.5f, 5.0f }, { 1.0f, 0.4f, 0.7f, 1.0f } });

    data.push_back({ {  0.2f, -0.5f, 10.0f }, { 0.0f, 0.75f, 1.0f, 1.0f } });
    data.push_back({ {  1.2f, -0.5f, 10.0f }, { 0.0f, 0.75f, 1.0f, 1.0f } });
    data.push_back({ {  1.2f,  0.5f, 10.0f }, { 0.0f, 0.75f, 1.0f, 1.0f } });
```

OpenGLで採用されている右手座標系では、Z軸の方向が逆になります。ただしカメラの向きはこれまでと同じで、つまりカメラはZ軸のマイナス方向を向いています。

　　<img width="500" src="https://qiita-image-store.s3.amazonaws.com/0/166309/a6588627-4a44-c59c-ba38-764632924ad6.png">

そのため、デフォルトのカメラに映るように頂点データを用意するためには、Z座標をマイナスにしておく必要があります。そこで次のように、すべてのZ座標の値をマイナスに変更します。

```cpp:Game.cppにおける頂点データの宣言(New)
    std::vector<VertexData> data;
    data.push_back({ { -0.6f, -0.5f, -5.0f }, { 1.0f, 0.4f, 0.7f, 1.0f } });
    data.push_back({ {  0.4f, -0.5f, -5.0f }, { 1.0f, 0.4f, 0.7f, 1.0f } });
    data.push_back({ {  0.4f,  0.5f, -5.0f }, { 1.0f, 0.4f, 0.7f, 1.0f } });

    data.push_back({ {  0.2f, -0.5f, -10.0f }, { 0.0f, 0.75f, 1.0f, 1.0f } });
    data.push_back({ {  1.2f, -0.5f, -10.0f }, { 0.0f, 0.75f, 1.0f, 1.0f } });
    data.push_back({ {  1.2f,  0.5f, -10.0f }, { 0.0f, 0.75f, 1.0f, 1.0f } });
```

なお、**座標系が変わるとX座標やY座標の値まで書き換える必要があるのでは？**と気になってしまいますが、上の座標系の図でカメラの向きが固定されている様子を見ていただくと分かるように、**これまでz=5と言っていた座標がz=-5と呼ばれるようになるだけ**で、**それ以外の変化は実はありません**。ですので、Z座標にマイナス記号を付けるだけで、頂点データの変更は完了します。

# 2. GLKitの関数を使う

GLSL中のuniform変数`mat`にセットする行列の値を計算するコードを、GLKitの関数`GLKMatrix4MakePerspective()`を使うように書き換えましょう。`GLKMatrix4MakePerspective()`関数の第1引数はラジアン単位の画角、第2引数はアスペクト比、第3引数はnearZ、第4引数はfarZです。画角はカメラの上端から下端までの角度です。nearZとfarZはそれぞれ、クリッピング領域のz=-1.0とz=1.0に対応する値でしたね。

```cpp:行列の生成とセット
    program->Use();
    GLKMatrix4 mat = GLKMatrix4MakePerspective(
        GLKMathDegreesToRadians(60.0f), 640.0f / 480.0f, 1.0f, 50.0f);
    program->SetUniform("mat", mat);
```

実行してみると、前回と同じ実行結果になって、計算通り描画できていることが分かります。

　<img width="450" src="https://qiita-image-store.s3.amazonaws.com/0/166309/ebad0957-c2aa-5bc3-cf0b-6e0fe8612ed8.png">

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

# 3. まとめ

今回はGLKitの`GLKMatrix4MakePerspective()`関数を使ってパースペクティブ行列を生成し、右手座標系でデータを取り扱う方法について解説しました。

これで右手座標系でのデータの扱い方について理解できましたね。ここからは、GLKitの`GLKMatrix4MakePerspective()`関数を使ってパースペクティブ行列を作り、OpenGLの慣例に従って、右手座標系でデータを扱っていくことにしましょう。

これまではカメラの位置や方向は固定して、OpenGLのグラフィック描画を解説してきました。次回は、ビュー行列を使って、カメラを動かして、様々な位置の頂点データを描画する方法について解説したいと思います。

----

次の記事：[macOSでOpenGLプログラミング（3-7. ビュー行列でカメラを動かす）](https://qiita.com/sazameki/items/9dc58829517d92643941)