OpenGLのとっかかり GLFW Ubuntu16.04


目次

目的

 OpenGLをやってみたいけどOpenGL, GLFW, GLUT, GLEWなどいろいろ種類があってわけがわからずどっから手を付ければいいかわからない人のための記事です。
 この記事は以下の文書の序盤の大いに参考にしました。WindowsやmacOSでの例なども詳細にそしてわかりやすく書いてありますし、ちゃんと勉強したい人は最初からこちらを読むといいと思います。

 ただ、Ubuntuで実装する際にapt経由でインストールしたときはgccのオプション指定が少し異なるので、そこらへんを参考にしていただければと思います。

OpenGLとは

OpenGL

 まずOpenGLとはコンピュータグラフィックスなどに必要なグラフィックス表示機能を抽象化し、整理したグラフィックスライブラリです。ただ、ここで注意が必要なのはOpenGLはあくまでグラフィックスの演算部分を担当するだけであり、実際に画面に表示するのはOSにもっと近い部分が担当します。OpenGLはそれに描画する内容を渡す役割を持ちます。

GLUT

 OpenGLはプラットフォーム非依存ではありますが、多少プラットフォームごとに異なる実装が必要となるためその部分を吸収したツールキットがいくつか存在します。
 そのなかにGLUT (OpenGL Utility Toolkit) があり、マルチプラットフォーム対応であるため、UNIX/Linux、Windows、macOS 間で共通なコードを書くことができます。
 しかしながら、オリジナルのサイトでじゃメンテナンスがあまりされていないようです。

GLUT - The OpenGL Utility Toolkit

freeGLUT

 GLUTの代わりに、GLUTと互換性を持ったfreeGLUTが開発されています。

GLFW

 GLUT以外のオープンソースマルチプラットフォーム対応ライブラリとしてGLFWがあります。他のツールキットに比べて小さめのキットで学習用にはちょうどいいようです。

GLEW

 OpenGLの拡張機能を手軽に使うことができるようにするためのマルチプラットフォーム対応ライブラリがGLEW (The OpenGL Extension Wrangler Library)です。

 GLFWの特徴として以下のようなことが挙げられていました。1

  • コンパクト
  • マルチプラットフォーム
  • OpenGLのバージョンやプロファイルが指定可能
  • 最初からでダブルバッファリング
  • イベントループを自分で書く
  • ポーリング方式とコールバック方式のどちらにも対応
  • マルチウィンドウやマルチモニタに対応
  • ユーザ定義のポインタを保存できる
  • 入力デバイスの取り扱い方法が異なる
  • GLUTにあってGLFWにない機能
    • CubeやSphere、Teapotのような図形を表示する機能は省かれている
    • ビットマップフォントをレンダリングする機能がない
    • ポップアップメニュー表示機能がない

環境

Version
OS Ubuntu16.04
OpenGL
GLFW
GLEW

※Ubuntu以外でやりたい方は元の文書からどうぞ 1

環境構築

$ sudo apt-get install -y libx11-dev xorg-dev \
                          libglu1-mesa libglu1-mesa-dev \
                          libgl1-mesa-glx libgl1-mesa-dev
$ sudo apt install -y libglfw3 libglfw3-dev
$ sudo apt install -y libglew-dev

背景色のみ表示するコードを書いてみる

コード

 同一ディレクトリ内に以下のMakefilemain.cppファイルを作成します。

Makefile
CXXFLAGS = -g -Wall -std=c++11
LDLIBS = -lGL \
         -lglfw
OBJECTS = $(patsubst %.cpp,%.o,$(wildcard *.cpp))
TARGET = sample


${TARGET} : ${OBJECTS}
    ${LINK.cc} $^ ${LOADLIBES} ${LDLIBS} -o $@

.PHONY : clean
clean :
    -${RM} ${TARGET} ${OBJECTS} *~ .*~ core
main.cpp
#include <cstdlib>
#include <iostream>
#include <GLFW/glfw3.h>


int main()
{
  ////////////////////////////////////////////////////////////////////////////////
  // GLFW の初期化 (GLFW)
  if (glfwInit() == GL_FALSE){
    // 初期化に失敗した処理
    std::cerr << "Can't initialize GLFW" << std::endl;
    return 1;
  }


  ////////////////////////////////////////////////////////////////////////////////
  // 終了時の処理登録 (GLFW)
  atexit(glfwTerminate);


  ////////////////////////////////////////////////////////////////////////////////
  // ウィンドウを作成 (GLFW)
  GLFWwindow * const window(glfwCreateWindow(/* int           width   = */ 640,
                                             /* int           height  = */ 480,
                                             /* const char  * title   = */ "Hello!",
                                             /* GLFWmonitor * monitor = */ NULL,
                                             /* GLFWwindow  * share   = */ NULL));
  if (window == NULL){
    // ウィンドウ作成に失敗した処理
    std::cerr << "Can't create GLFW window." << std::endl;
    return 1;
  }

  // 作成したウィンドウを処理対象とする (GLFW)
  glfwMakeContextCurrent(/* GLFWwindow *  window = */ window);

  // 背景色 (OpenGL)
  glClearColor(/* GLfloat red   = */ 0.2f,
               /* GLfloat green = */ 0.2f,
               /* GLfloat blue  = */ 0.2f,
               /* GLfloat alpha = */ 0.0f);


  ////////////////////////////////////////////////////////////////////////////////
  // ループ処理

  // ウィンドウが開いている間繰り返す
  while (glfwWindowShouldClose(/* GLFWwindow * window = */ window) == GL_FALSE){
    // ウィンドウを消去 (GLFW)
    glClear(/* GLbitfield mask = */ GL_COLOR_BUFFER_BIT);

    // 描画処理

    // カラーバッファ入れ替え <= ダブルバッファリング (GLFW)
    glfwSwapBuffers(window);

    // イベント待ち (GLFW)
    glfwWaitEvents();
  }

  return 0;
}

解説

  1. GLFW の初期化
    1. glfwInit()
  2. ウィンドウ作成
    1. GLFW: Window reference
    2. glfwCreateWindow()
      1. ウィンドウを作成したとしてもそのウィンドウが描画の対象にしていされていないので次のglfwMakecontextCurrent()で処理対象にします。
    3. glfwMakeContextCurrent()
      1. ウィンドウを処理対象に指定
    4. glClearColor()
      1. 最初のカラーバッファ設定
  3. ループ処理
    1. glfwWindowShouldClose()
      1. ウィンドウを閉じるかどうかの判断
    2. glClear()
      1. maskに指定したバッファを塗りつぶす
    3. glfwWailEvents()
      1. マウスの操作などのイベント待ち
      2. イベント発生後に処理再開
  4. ダブルバッファリングのバッファ入れ替え
    1. glfwSwapBuffers()
      1. ダブルバッファリングにおけるカラーバッファの入れ替え
  5. ウィンドウを閉じ、終了処理
    1. glfwTerminate()
      1. GLFWの終了処理
      2. 初期化成功したときにプログラム終了前にこの関数の実行が必要

実行

$ ./sample

図形を描画してみる

結構、長くなりそうなので近いうちに別記事で ( _ _ )

参照