HOME > natural science Laboratory > コンピュータ・シミュレーション講座 > コンピュータ・シミュレーション講座 授業日誌

VisualC++ を使った OpenGL 入門
【1.1日目】OpenGL の基本形

前回では、 「世界の始まり」ウィンドウの生成までを行ないました。 が、ただ白い画面が描画できたに過ぎません。「直線」を描画することで世界に大地を創造しましょう。

以下のソースを貼り付けて、「デバック開始」ボタンをクリックすると、上の図のように「世界の始まり」ウィンドウが生成されます。

#include <GL/glut.h>

//----------------------------------------------------
// 変数の宣言
//----------------------------------------------------
int WindowPositionX = 200;  //生成するウィンドウ位置のX座標
int WindowPositionY = 200;  //生成するウィンドウ位置のY座標
int WindowWidth = 512;      //生成するウィンドウの幅
int WindowHeight = 512;     //生成するウィンドウの高さ
char WindowTitle[] = "世界の始まり";  //ウィンドウのタイトル

//----------------------------------------------------
// 関数プロトタイプ(後に呼び出す関数名と引数の宣言)
//----------------------------------------------------
void Initialize(void);   //初期設定時に呼び出す関数
void Idle(void);         //アイドル時に呼び出す関数
void Display(void);      //画面描画時に呼び出す関数
void Ground(void);       //大地の描画用の関数
//----------------------------------------------------
// メイン関数
//----------------------------------------------------
int main(int argc, char *argv[]){
  glutInit(&argc, argv);                                     //環境の初期化
  glutInitWindowPosition(WindowPositionX, WindowPositionY);  //ウィンドウの位置の指定
  glutInitWindowSize(WindowWidth, WindowHeight);             //ウィンドウサイズの指定
  glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE); //ディスプレイモードの指定
  glutCreateWindow(WindowTitle);                             //ウィンドウの作成
  glutIdleFunc(Idle);                                        //プログラムアイドル状態時に呼び出される関数
  glutDisplayFunc(Display);                                  //描画時に呼び出される関数を指定する(関数名:Display)
  Initialize();                                              //初期設定の関数を呼び出す
  glutMainLoop();
  return 0;
}
//----------------------------------------------------
// 初期設定の関数
//----------------------------------------------------
void Initialize(void){
  glClearColor(1.0, 1.0, 1.0, 0.0); //背景色
  glEnable(GL_DEPTH_TEST);//デプスバッファを使用:glutInitDisplayMode() で GLUT_DEPTH を指定する

  //透視変換行列の設定------------------------------
  glMatrixMode(GL_PROJECTION);//行列モードの設定(GL_PROJECTION : 透視変換行列の設定、GL_MODELVIEW:モデルビュー変換行列)
  glLoadIdentity();//行列の初期化
  gluPerspective(30.0, (double)WindowWidth/(double)WindowHeight, 0.1, 1000.0); //透視投影法の視体積gluPerspactive(th, w/h, near, far);
  //------------------------------------------------
  gluLookAt(
       0.0, -200.0, 50.0, // 視点の位置x,y,z;
       0.0, 0.0, 20.0,   // 視界の中心位置の参照点座標x,y,z
       0.0, 0.0, 1.0);  //視界の上方向のベクトルx,y,z
}
//----------------------------------------------------
// アイドル時に呼び出される関数
//----------------------------------------------------
void Idle(){
  glutPostRedisplay(); //glutDisplayFunc()を1回実行する
}
//----------------------------------------------------
// 描画の関数
//----------------------------------------------------
void Display(void) {
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //バッファの消去
  //モデルビュー変換行列の設定--------------------------
  glMatrixMode(GL_MODELVIEW);//行列モードの設定(GL_PROJECTION : 透視変換行列の設定、GL_MODELVIEW:モデルビュー変換行列)
  glLoadIdentity();//行列の初期化
  glViewport(0, 0, WindowWidth, WindowHeight);
  //----------------------------------------------

  Ground();

  glutSwapBuffers(); //glutInitDisplayMode(GLUT_DOUBLE)でダブルバッファリングを利用可
}
//----------------------------------------------------
// 大地の描画
//----------------------------------------------------
void Ground(void) {
    double ground_max_x = 300.0;
    double ground_max_y = 300.0;
    glColor3d(0.8, 0.8, 0.8);  // 大地の色
    glBegin(GL_LINES);
    for(double ly = -ground_max_y ;ly <= ground_max_y; ly+=20.0){
      glVertex3d(-ground_max_x, ly,0);
      glVertex3d(ground_max_x, ly,0);
    }
    for(double lx = -ground_max_x ;lx <= ground_max_x; lx+=20.0){
      glVertex3d(lx, ground_max_y,0);
      glVertex3d(lx, -ground_max_y,0);
    }
    glEnd();
}

プログラムの説明

今回のプログラムは OpenGL を実行していく上での基本要素がそろっているますので、一通りの説明を行ないます。

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

#include <GL/glut.h>

OpenGL は「glut.h」ファイルをインクルードすることで利用することができます。

変数の宣言

//----------------------------------------------------
// 変数の宣言
//----------------------------------------------------
int WindowPositionX = 200;  //生成するウィンドウ位置のX座標
int WindowPositionY = 200;  //生成するウィンドウ位置のY座標
int WindowWidth = 512;      //生成するウィンドウの幅
int WindowHeight = 512;     //生成するウィンドウの高さ
char WindowTitle[] = "世界の始まり";  //ウィンドウのタイトル

ウィンドウ生成時に必要なパラメータを、変数宣言と同時に代入します。 変数名は任意ですが、覚えやすい名前をつけるといいでしょう。

関数プロトタイプ

//----------------------------------------------------
// 関数プロトタイプ(後に呼び出す関数名と引数の宣言)
//----------------------------------------------------
void Initialize(void);   //初期設定時に呼び出す関数
void Idle(void);         //アイドル時に呼び出す関数
void Display(void);      //画面描画時に呼び出す関数
void Ground(void);       //大地の描画用の関数

C言語では、関数が定義される前の関数を呼び出すことはできません。 しかしながら、使用する順番にどおり関数を定義するのは、非常に非生産的な作業となります。 また、関数が入れ子となるような場合には、そもそも不可能となる場合があります。 そのために用意されているのが、プログラムの最初に後で利用する関数名とその引数のタイプのみを宣言する「関数プロトタイプ」です。 任意の場所で、改めて関数を定義することがでます。 機能ごとに関数を定義し呼び出すようにすることで、プログラムの構造をシンプルとすることができ、可読性を高めることができます。

メイン関数

//----------------------------------------------------
// メイン関数
//----------------------------------------------------
int main(int argc, char *argv[]){
  glutInit(&argc, argv);//環境の初期化
  glutInitWindowPosition(WindowPositionX, WindowPositionY);  //ウィンドウの位置の指定
  glutInitWindowSize(WindowWidth, WindowHeight);             //ウィンドウサイズの指定
  glutCreateWindow(WindowTitle);                             //ウィンドウの作成
  glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE); //ディスプレイモードの指定
  glutIdleFunc(Idle);                                        //プログラムアイドル状態時に呼び出される関数
  glutDisplayFunc(Display);                                  //描画時に呼び出される関数を指定する(関数名:Display)
  Initialize();                                              //初期設定の関数を呼び出す
  glutMainLoop();
}

上のプログラムは、OpenGL 利用時のメイン関数です。 それぞれの関数の意味は、プログラム内にコメントアウト文に記載されているとおりです。 先に宣言した変数がここで使われています。

glutInit(&argc, argv);                                     //環境の初期化
glutInitWindowPosition(WindowPositionX, WindowPositionY);  //ウィンドウの位置の指定
glutInitWindowSize(WindowWidth, WindowHeight);             //ウィンドウサイズの指定
glutCreateWindow(WindowTitle);                             //ウィンドウの作成

メイン関数のうち、上記の4つの関数はOpenGL を利用する上で必須の設定です。「変数の宣言」で設定した変数を使用して、生成するウィンドウのパラメータを実際に設定している部分となります。

glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE); //ディスプレイモードの指定

glutInitDisplayMode 関数では、OpenGL の描画時に利用するモードを指定することができます。 後に物理アニメーションを行なうことを想定して利用するモードを決めています。
詳説は必要時に行ないますが、一応意味だけを説明しておきます。
GLUT_RGBA:カラーモードを RGBA に指定
GLUT_DEPTH:デプスバッファの利用
GLUT_DOUBLE:ダブルバッファの利用

glutDisplayFunc(Display); //描画時に呼び出される関数を指定する(関数名:Display)

glutDisplayFunc 関数は、引数で指定した関数(関数ポインタ=関数名)を描画が必要な時に呼び出します。例では、関数プロトタイプで指定した関数名「Display」を呼び出す用に指定しています。

glutIdleFunc(Idle); //プログラムアイドル状態時に呼び出される関数

glutIdleFunc 関数は、プログラム全体が「ひま」になった時に、指定した関数(例では「Idle」関数)を呼び出す関数です。アニメーションを実行するために必須の関数です。後述する「Idle」関数 の説明時に詳しく触れます。

Initialize();  //初期設定の関数を呼び出す
glutMainLoop();

Initialize():関数プロトタイプに記述した「Initialize」関数に記述する初期設定を呼び出します。
glutMainLoop():この関数は、OpenGL の終了を意味します。

初期設定の関数

//----------------------------------------------------
// 初期設定の関数
//----------------------------------------------------
void Initialize(void){
  glClearColor(1.0, 1.0, 1.0, 0.0); //背景色
  glEnable(GL_DEPTH_TEST);//デプスバッファを使用:glutInitDisplayMode() で GLUT_DEPTH を指定する

  //透視変換行列の設定------------------------------
  glMatrixMode(GL_PROJECTION);//行列モードの設定(GL_PROJECTION : 透視変換行列の設定、GL_MODELVIEW:モデルビュー変換行列)
  glLoadIdentity();//行列の初期化
  gluPerspective(30.0, (double)WindowWidth/(double)WindowHeight, 0.1, 1000.0); //透視投影法の視体積gluPerspactive(th, w/h, near, far);
  //------------------------------------------------
  gluLookAt(
       0.0, -200.0, 50.0, // 視点の位置x,y,z;
       0.0, 0.0, 20.0,   // 視界の中心位置の参照点座標x,y,z
       0.0, 0.0, 1.0);  //視界の上方向のベクトルx,y,z
}

関数プロトタイプで記述した「Initialize」関数を定義します。

glClearColor(GLclampf red , GLclampf green , GLclampf blue , GLclampf alpha)

glClearColor 関数は、red, green, blue をそれぞれ 0.0~1.0 の値で指定することで、初期の背景色を指定します。 また、alpha で透明度を 0.0~1.0 の値で指定しますが、今回は透明度は利用していないので、0を指定します。 red, green, blue は光の3原色なので、すべてが 1.0 の場合に白色、0.0 の場合に 黒色となります。

glEnable(GL_DEPTH_TEST);//デプスバッファを有効にする

デプスバッファを有効にします。

//透視変換行列の設定------------------------------
glMatrixMode(GL_PROJECTION);//行列モードの設定(GL_PROJECTION : 透視変換行列の設定、GL_MODELVIEW:モデルビュー変換行列)
glLoadIdentity();//行列の初期化
gluPerspective(30.0, (double)WindowWidth/(double)WindowHeight, 0.1, 1000.0); //透視投影法の視体積gluPerspactive(th, w/h, near, far);
//------------------------------------------------

「透視変換行列の設定」 gluPerspective 関数は、透視投影法の視体積を指定する関数です。

gluLookAt(
    0.0, -200.0, 50.0, // 視点の位置x,y,z;
    0.0, 0.0, 20.0,    // 視界の中心位置の参照点座標x,y,z
    0.0, 0.0, 1.0);    //視界の上方向のベクトルx,y,z

gluLookAt 関数は、描画時の視点の位置と向きを指定する関数です。 次の「視点の設定」で詳しく説明します。

アイドル時に呼び出される関数の定義

//----------------------------------------------------
// アイドル時に呼び出される関数
//----------------------------------------------------
void Idle(){
  glutPostRedisplay(); //glutDisplayFunc()を1回実行する
}

glutIdleFunc 関数によって呼び出される「Idle」関数の定義をここでします。 上記の例では「Idle」関数が呼び出された時に、「glutPostRedisplay()」を実行しています。 「glutPostRedisplay()」は「glutDisplayFunc()」を1回実行する関数で、 結果として、メイン関数で「glutDisplayFunc()」に指定された関数(例では「Display」関数)を1度実行する意味を持ちます。
つまり、

1.main 関数内の「glutIdleFunc(Idle)」→
2.Idle 関数内の「glutPostRedisplay()」→
3.main 関数内の「glutDisplayFunc(Display)」→
4.Display 関数の実行(描画)→
5.ひま → 1へ

のサイクルで連続的に描画することでアニメーションを実現します。

描画の関数

void Display(void) {
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //バッファの消去

  Ground();

  glutSwapBuffers(); //glutInitDisplayMode(GLUT_DOUBLE)でダブルバッファリングを利用可
}

関数プロトタイプで記述されている「Display」関数の定義を行なっています。 main 関数内で記述されている「glutDisplayFunc(Display)」関数が実行されると呼び出されます。

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //バッファの消去

glClear 関数は、指定したバッファを特定の色(glClearColor 関数で指定した色)で塗りつぶします。

大地の描画

void Ground(void) {
    double ground_max_x = 300.0;
    double ground_max_y = 300.0;
    glColor3d(0.8, 0.8, 0.8);  // 大地の色
    glBegin(GL_LINES);
    for(double ly = -ground_max_y ;ly <= ground_max_y; ly+=10.0){
      glVertex3d(-ground_max_x, ly,0);
      glVertex3d(ground_max_x, ly,0);
    }
    for(double lx = -ground_max_x ;lx <= ground_max_x; lx+=10.0){
      glVertex3d(lx, ground_max_y,0);
      glVertex3d(lx, -ground_max_y,0);
    }
    glEnd();
}

この例では、直線を等間隔で描画することで大地を表現しています。 2点をつなぐ直線は次のように記述します。

glBegin(GL_LINES);
  glVertex3d(x0, y0, z0);
  glVertex3d(x1, y1, z1);
glEnd();

OpenGL では直線以外にも様々な図形を書くことができます。

次は「視点の設定」を行ないます。

【目次】 (VisualC++ を使った OpenGL 入門)

未分類




▲このページのトップNPO法人 natural science トップ

関連記事

OpenGL入門







コンピュータ・シミュレーション講座 授業日誌







▲このページのトップNPO法人 natural science トップ




Warning: mysqli_connect(): (28000/1045): Access denied for user 'xsvx1015071_ri'@'sv102.xserver.jp' (using password: YES) in /home/xsvx1015071/include/natural-science/include_counter-d.php on line 8
MySQL DBとの接続に失敗しました