2019/10/16
参考 : http://marina.sys.wakayama-u.ac.jp/~tokoi/GLFWdraft.pdf
## OpenGLとは
OpenGL APIは様々なグラフィックスハードウェアを抽象化し、制御するための基本的な機能のみをもつ。3DCGを描画するにはCGの理論の知識も必要である。
OpenGLはIRIX(UNIX系OS)を搭載したEWSのグラフィックス表示に用いられていたIRIS GLを様々なプラットフォームで動作するよう再実装され、オープンソース化されたものである。
最初シリコングラフィックス社により開発され、現在はクロノス(Khronos Groups)によって規格が策定されている。
他のグラフィックスライブラリ APIには、
* Microsoft社が開発しているXbox・Windows向けのDirect X
* Apple社が開発しているiPhone・iPad・macOSむけのMetal
が存在する。
これらは各社が各社のデバイス向けに開発しているものであり、Windows・Linuxの両方で動作するものとしてはOpenGL、その後継のVulkanしか存在しない。
なおApple社の製品は、以前はOpenGLに対応していたが、今年のアップデートで非対応とし、Metalへの移行を強制化した。
そして、組み込み機器向けのOpenGLとして OpenGL ESが存在し、Xilinx Zynq UltraScaleが搭載するARM GPUが対応しているものはOpenGL ESのみである。
そのため、今回はOpenGL ESを用いたプログラム開発を行う。
## GLFWとは
OpenGLそのものはマルチプラットフォームにだが、ウインドウ生成などプラットフォーム依存の部分はそれぞれに応じてコードが必要になる。
このプラットフォームごとの差異を吸収するツールキットとして、GLFWがある。
ツールキットは他にもGLUT、Qtなどが存在するが、GLUTはメンテナンスが滞っており、Qtは高機能すぎるため、今回研究で行いたいことが十分達成できそうな小さなツールキットとしてGLFWを採用する。
なお、ライセンスはzlib/libpng licenseである。
## GLEWとは
GLEW (the OpenGL Extension Wrangler Library) を用いることで、OpenGLのVersionを指定できるようになる。
Windows環境ではデフォルトのOpenGL Versionが1.1となっており、ハードウェアがそれ以上のバージョンに対応していたとしても、1.1で動作してしまう。
OpenGL環境でOpenGL ESを動かすにはOpenGL 4.1が必要である。
GLEWを用いて、PC上でもOpenGL ES環境を有効化し、開発を行う。
## プログラミング
### データ型
| OpenGLのデータ型 | 最小ビット数 | 説明 |
| -------- | -------- | -------- |
| GLboolean | 1 | bool型 |
| GLbyte | 8 | 1byteの符号付き二進整数(二の補数表現)|
| GLubyte | 8 | 1byteの符号なし二進整数 |
| GLchar | 8 | char型 |
| GLshort | 16 | short int型 |
| GLushort | 16 | unsigned short int型 |
| GLint | 32 | int型 |
| GLuint | 32 | unsigned int型 |
| GLint64 | 64 | long int型 |
| GLuint64 | 64 | unsigned long int型 |
| GLsizei | 32 | 非負の二進整数で表したサイズ |
| GLenum | 32 | 二進整数で表した列挙子 |
| GLintptr | | int * (ポインタ) |
| GLsizeiptr| | GLsizeiのポインタ |
| GLsync | | 同期オブジェクトのハンドル |
| GLbitfield| 32 | ビットフィールド |
| GLhalf | 16 | 符号なしの値に符号化された半精度浮動小数点数(CPU側には存在しない) |
| GLfloat | 32 | float型 |
| GLdouble | 64 | double型 |
### ウインドウの生成
GLFWを使ってウインドウを生成する際には、
1. glfwInit() : GLFWの初期化
2. glfwCreateWindow() : ウインドウの生成
3. glfwMakeContextCurrent(window) : OpenGLの処理対象のウインドウを指定
4. glClearColor(Red,Green,Blue,Alpha) : ウインドウの塗りつぶし
5. glfwWindowShouldClose() : ウインドウが開いている間の繰り返し描画
6. glfwSwapBuffers() : ダブルバッファリングのバッファ入れ替え
7. glfwTerminate() : ウインドウを閉じた際の終了処理
の順で処理を行う。
#### 1. GLFWの初期化
main関数内に
```
if (glfwInit() == GL_FALSE)
{
std::cerr << "Can't initilize GLFW" << std::endl;
return 1;
}
```
と記述することでGLFWの初期化が行える。
#### 2. ウインドウの生成 , 3. OpenGLの処理対象のウインドウを指定 , 4. ウインドウの塗りつぶし
```
// ウィンドウを作成する
GLFWwindow* const window = glfwCreateWindow(640, 480, "SAMPLE", NULL, NULL);
if (window == NULL)
{
std::cerr << "Can't create GLFW window." << std::endl;
glfwTerminate();
return 1;
}
// 作成したウィンドウを OpenGL の処理対象にする
glfwMakeContextCurrent(window);
// 背景色を指定する
glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
```
とすることで、640x480のSAMPLEというタイトルのウインドウが生成され、OpenGLの処理対象となり白(R:1,G:1,B:1,Alpha:0)で塗りつぶされる。
### シェーダープログラム
GLSLのシェーダープログラムの流れは、
1. glCreateProgram() : プログラムオブジェクト作成
2. glCreateShader() : バーテックス(頂点)シェーダーとフラグメントシェーダーのシェーダーオブジェクトを作成
3. glShaderSource() : シェーダーオブジェクトにソースプログラムを読み込む
4. glCompileShader() : ソースプログラムをコンパイル
5. glAttachShader() : プログラムオブジェクトにシェーダーオブジェクトを組み込み
6. glLinkProgram() : プログラムオブジェクトをリンク
#### バーテックスシェーダー
バーテックスシェーダーの`in` 変数にはCPUから送られた図形データの一つの頂点データが格納される。この頂点データを **頂点属性(attribute)** といい、このin変数を特に **attribute 変数** という。
シェーダープログラムは引数、返り値をもたない `void main()` 関数から実行される。
頂点属性(attribute)はCPUからGPUの **頂点バッファオブジェクト** メモリに格納される。その後CPUから描画命令(ドローコール)を送ると、GPUは頂点バッファオブジェクトから頂点属性(attribute)を取り出しattribute変数に格納し、バーテックスシェーダー処理を行う。
`gl_Position` はGLSLの組み込み変数で、この値がレンダリングパイプラインの次のステージに送られる。
#### フラグメントシェーダー
out 変数に代入したデータはレンダリングパイプラインの次のステージに送られる。
フラグメントシェーダーのout変数はフレームバッファのカラーバッファに格納される。
もしフレームバッファに値を格納しない (画素を描かない) なら、フラグメントシェーダで discard 命令を実行します。
####