OpenGLとは
計算機序論2, 
www.kameda-lab.org 
2005/09/25
    
    OpenGLによるグラフィックス描画
    
      - 三次元グラフィックス・ライブラリ(二次元グラフィックスも可能) 
      
- 高速な描画が可能 
      
- ハードウェア化が比較的簡単 (SGIのワークステーション, PCのグラフィックスカード等)
      
- 公式サイト:OpenGL
      
最近ではWWW上に公式文書を含め様々な解説が公開されているので、興味のある人は自分で探して使い方を追求してみましょう。
    また、各関数の説明に限って言えば、man ページも役に立ちます。活用してください。
    
    描画のための基本
    
    色の指定
 
    
    ワイヤー、ポリゴンの色を RGB モードで指定する関数群は、glColor*() です。
    glColor*() は, glColor3f() や glColor4fv() などいくつかの関数をまとめた表現です。
    (* には, 接尾子が付きます. )
    
    glColor3f(float r, float g, float b)
    glColor4f(float r, float g, float b, float a)
    glColor3fv(float *rgb)
    glColor4fv(float *rgba)
      : 
     
    
    このように, 最初の接尾子が 3 のものが RGB の値を指定するもので、4 のものがが, RGB に加えてα値(透過係数) も指定するものです。
    2 番目の接尾子は, 引数の型を指定するものです。
    f は float を, dは, double を表します。
    3番目の接尾子vが付いているものは, 配列のポインタで指定するものです。
    
    
    ワイヤーやポリゴンは, glColor*() 関数で指定した色で表示されます。 
    色の設定は、ポリゴン単位で行う必要はなく, 再度 glColor*() 関数でカレントカラーを変更するまで, 同じ色でポリゴン等を描画します。
    
    プリミティブ
    
    プリミティブとは, 基本物体のことです. OpenGL では, ポリゴンやワイヤフレーム等を指します。
    プリミティブは, 次のような手順で表示します。 
    
    
        glBegin( タイプ );
            glVertex{2,3,4}{s,i,f,d}[v] (.....);
            glVertex{2,3,4}{s,i,f,d}[v] (.....);
                   :
        glEnd();
     
    
    プリミティブの頂点リストの開始と終了を示す関数が, glBegin() とglEnd() です。
    glBegin() の引数には, GL_LINES(ライン), GL_POLYGON(ポリゴン)等のタイプを指定します。
    プリミティブの頂点を指 定する関数が, glVertex*() です。
    glColor*() の時と同じように, 引数の 種類によって使用する関数が異なります。
    glVertex*() は, glVertex2f() や glVertex3fv() などいくつかの関数をまとめた表現です。
    (* には, 接尾子が付きます. )
    
    
    glVertex2f(GLfloat x, GLfloat y)
    glVertex3f(GLfloat x, GLfloat y, GLfloat z)
    glVertex2fv(GLfloat *coords)
    glVertex3fv(GLfloat *coords)
      : 
        
    
    このように, 最初の接尾子が 2 のものが, 二次元の座標(x,y)を指定するもので, 3のものが, 三次元の座標(x,y,z) を指定するものです。
    2 番目の接尾子は, 引数の型を指定するものです。 
    f は float であり, dは, double を表します。
    3番目の接尾子 v が付いているものは, 配列のポインタで指定するものです。
    
    
    なお, 頂点は glBegin() と glEnd() の間に指定しなければなりません。
    
    ワイヤフレーム
    
    ワイヤフレームとは, 物体を線(ワイヤ)で表現するものです。
    単純であることから描画が速く, アニメーションのプレビューなど, 速度を要求される場面によく利用されます。
    
    
    GL_LINES と GL_LINE_LOOP の違いは, 終点から始点に線を結ぶかど うかの違いです。
    
    
    glBegin(GL_LINES);       /* ラインの開始宣言 */
      glVertex3fv(ax1);      /* 第1頂点を指定 */
      glVertex3fv(ax2);      /* 第2頂点を指定 */
    glEnd();                 /* ラインの終了宣言 */
    
    glBegin(GL_LINE_LOOP);   /* GL_LINES と GL_LINE_LOOP の違いは, */
      glVertex3fv(ax3);      /* 終点から始点を結ぶかどうかです.    */
      glVertex3fv(ax2);      /* GL_LINE_LOOP は終点から始点を結び  */
      glVertex3fv(ax4);      /* ます.                              */
    glEnd();
        
    ポリゴン
    
    ポリゴンは, あくまでも一平面ですから, ポリゴンを構成するすべての頂点が,同一平面上になければなりません。
    もし, 同一平面上にない場合は, 面が正しく表示されません. 
    
    
    glColor3fv(blue);       /* ポリゴン・カラーの設定 */
    glBegin(GL_POLYGON);    /* ポリゴン開始宣言 */
      glVertex3fv(v1);      /* 第1頂点    箱の一つの面は,  */
      glVertex3fv(v2);      /* 第2頂点    正方形であるから */
      glVertex3fv(v3);      /* 第3頂点    頂点が4つになり */
      glVertex3fv(v4);      /* 第4頂点    ます.            */
    glEnd();                /* ポリゴン終了宣言 */
        
    
    GLUTを使ったプログラムの流れ
    
     
    GLUTを使ったプログラミングでは,main関数が,似たもの(ほとんど同じような形式)になります。
    いったん形式を覚えておくと,ずっと使い回しができるでしょう。
    
    
int main (int argc, char **argv) {
  // glutの初期化 
  glutInit (&argc, argv);
  // ウィンドウを開く
  glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB); // モード設定
  glutInitWindowSize (400, 400);                // ウィンドウの大きさ
  glutInitWindowPosition (100, 100);            // ウィンドウの位置
  glutCreateWindow (argv[0]);                   // ウィンドウの生成
  glClearColor (0.0, 0.0, 0.0, 0.0);   // ウィンドウ全体を書き直すときの色 
  glShadeModel (GL_FLAT);              // シェーディングのモデル(理解しなくて良い) 
  glutDisplayFunc (display);  // 表示関数の登録 
  glutReshapeFunc (reshape);  // 画面設定関数の登録 
  glutKeyboardFunc (keyfunc); // キー入力処理関数の登録 
  glutMainLoop ();            // 実行 
  return 0;
}
    まずは,最初から。
    
  glutInit (&argc, argv);
    
    glutの初期化をしています。「おまじない」と思って下さい。興味のある人は man glutInit で調べてみましょう。
    
  glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB); // モード設定 
  glutInitWindowSize (400, 400);                // ウィンドウの大きさ 
  glutInitWindowPosition (100, 100);            // ウィンドウの位置 
  glutCreateWindow (argv[0]);                   // ウィンドウの生成 
    
    ウィンドウに関する命令です。
    画面の左上(100, 100)に幅400,高さ400のウィンドウを開きます。
    このウィンドウ内にOpenGLコマンドによって描画することになります。
    
  glClearColor (0.0, 0.0, 0.0, 0.0);   // ウィンドウ全体を書き直すときの色 
  glShadeModel (GL_FLAT);              // シェーディングのモデル(理解できなくて良い) 
    
    最初の行は書き直されるときにバックの色が黒になるようにします。
    2行目は描画する際の濃淡のつけ方を指定します。
    時間があれば授業で説明しますが、とりあえずは「おまじない」と思って下さい。
    
  glutDisplayFunc (display);  // 表示関数の登録 
  glutReshapeFunc (reshape);  // 画面設定関数の登録 
  glutKeyboardFunc (keyfunc); // キー入力処理関数の登録 
        
    この3つの関数はこの順番で実行されるというものではありません。
    あるイベントが起こったときにどの関数が実行されるかを定義しています。
    
  glutDisplayFunc(display);
    
    はウィンドウに描画イベントが起こったときに、 display() が呼び出されるようシステムにお願いしています。
    この場合、 display() 自体はユーザがプログラミングしておきます。
    
  glutReshapeFunc(reshape); 
    
    はウィンドウのサイズ変更が起こったときに呼び出される関数が rehape()であることを指定しています。
    マウスでウィンドウのサイズが変えられたりすると reshape() が呼び出されます.
    
  glutKeyboardFunc (keyfunc); 
  glutMouseFunc   (mousefunc);
    
    はキーボードやマウスによって入力があったときに呼び出される関数が、各々、 keyfunc(), mousefunc()になるように指定しています。
    キーボードのキーが押されたときや、マウスのボタンが押されたり離されたりしたときにこれらの関数が呼ばれます。
    
    keyfunc()そのものはユーザが記述するのですが,宣言部分は
    
    void keyfunc (unsigned char key , int x, int y) 
    
    という形で引数をとらなければなりません。
    呼ばれるときには,システムによって、key: 押されたキーのコード(文字)と,x,y: キーが押された時のマウスカーソルの位置(Xウィンドウ中での位置) が与えられます.
    
  
    
    mousefunc()は,
    
    void mousefunc (int button, int status, int x, int y)
    
    という形になります.
    buttonには,左ボタン,中ボタン,右ボタンを区別するための数が入り,
    左ボタン: button → GLUT_LEFT_BUTTON,
    中ボタン: button → GLUT_MIDDLE_BUTTON,
    右ボタン: button → GLUT_RIGHT_BUTTON
    となります.
    statusには,押されたか,離されたかを区別するための数が入ります. 
    押した場合: status → GLUT_DOWN,
    離した場合: status → GLUT_UP
    になります.
    x,y はkeyfuncと同様,マウスカーソルの位置です.
    
  
    最後に、
    
  glutMainLoop();
    
    が実行されると、プログラムはその場で無限ループを実行しはじめます。
    ループが無限にまわるあいだ、(上で行った定義に基づいて)イベントが起こるのを待ち続け、生じたイベントに合わせて指定された関数を呼び出してます。
    実行が済むと、また無限ループに戻ります。
    
    OpenGLのライブラリ
    実習用の計算機に標準でインストールされている OpenGL 関連ライブラリには , 以下のものがあります。
    
      - GLライブラリ: 
      
- 関数名が, "gl" で始まる基本的な描画コマンド。
          射影変換, 形状設定やライティングの設定等を行う。
      
- GLU ライブラリ: 
      
      
- 関数名が "glu" で始まるユーティリティ関数群。 
          GL ライブラリ・関数を組み合わせて作られた, 有用なライブラリ。
      
- GLX ライブラリ: 
      
- 関数名が "glX" で始まる。
      ウィンドウ操作やイベント操作に関する, X Window System に依存するライブラリ。
      利用するには, X の知識がある程度必要。
      このライブラリは, Microsoft系OS では利用できない。
      
- GLUT ライブラリ
      
- "glut" で始まる。 
      GLを利用するときに現在標準的に使われている便利なライブラリ。
      Microsoft系OSでも利用可能であるため, このライブラリを使用すれば,ほぼ同じプログラムを UNIX と Windowsで動かすこと ができる。
    
この他にもOpenGLに関連した以下のような補助ライブラリがありますが、授業では取り扱いません。      
      - GLUI ライブラリ:
      
- glutライブラリを用いて作られたGUI用のライブラリ。
      一般的なGUIボタンなど)だけでなく、トラックボールのような外見の回転用GUIなどもVer2.0から追加された.
      GLUTを元に作られているので、Windowsでも同じGUIで動かすことができる。実験用計算機には標準では載っていない。
      
- AUX ライブラリ: 
      
- 関数名が, "aux" で始まるもの。
      近年はあまり使われていない。
      GLX を使わなくてもイベント処理を 行うことができる。
      複数の Window を開くことができない等の欠点がある。
      実験用計算機には標準では載っていない。
      
- TK ライブラリ: 
      
- 関数名が, "tk" で始まるもの。
      AUX ライブラリより低レベルのライブラリであり, AUX ライブラリは, この TK ライブラリで作られている。
    
ただし, OpenGL を用いてイベント操作やウィンドウ操作など, 複雑な処理を行うには, 結局 Xlib や Motif を使うほうがよい可能性もあります。
    Mesaに基づくプログラミング環境
    Mesa
    工シスサテライトのLinuxには既にOpenGL開発環境がインストール済みである。
    これは Mesa (http://www.mesa3d.org) と呼ばれるOpenGL互換の開発環境である。
    
    
      gl.h                            libGL.a
      glu.h                           libGLU.a
      glx.h                        
      glut.h                          libglut.a
      
    コンパイル
    
      % gcc sample.c -o sample -I(OpenGL関係のヘッダディレクトリパス) -L(OpenGL関係のライブラリディレクトリパス) -lX11 -Xmu -lXi -lGL -lGLU -lglut -lm
    
    ないしは、本授業用に用意したMakefileという設定ファイルを作業ディレクトリに用意した上で、makeコマンドを利用することもできる。
    (参照)
    
      % make sample
    
    
    より深みにハマりたい人へ
    
    C言語によるプログラミング解説については、UNIX対応を謳っている解説書であれば自分に合ったものを選べばいいでしょう。
    OpenGLの参考書としては、バイブルとも呼ばれる "Opengl Programming Guide: The Official Guide to Learning Opengl, Version 1.4" (通称Open GL 赤本)があります(Version 2.0もリリースされました)。
    CG、特にリアルタイム処理を意識したCGに興味があるのなら一度手に取ってみてください。
    英文ですが、それほど難しい文章ではないので、英語の勉強にもなります(高いですが‥)。
    日本語翻訳版もあります(翻訳版はバージョンが古いですが、基礎原理を学ぶだけなら支障ありません)。
Yoshinari Kameda: 2004/09/05-
Yuichi Nakamura: Fri Aug 27 18:07:24 JST 1999