OpenGL

ARToolkitを実現するにはOpenGLも習得しておく必要があります。

各種要素となるプログラムソースを公開しておきます。
開発環境はARToolkitを参照してください。

プログラミングに関してはARToolkitでも紹介した書籍、
および下記HP「NaturalScience」様を参考にしております。
そちらではソースの解説があまりないので、必要に応じて補足、コメントなどしています。
ただし、読者の方々にはC言語に関する基礎知識があるものとして説明しております。

(c)NaturalScience


VisualStudio2010ではどう設定するの?

VisualStudio2010が公開されましたね。2008とは若干仕様が変わりましたので、それを紹介します。

まずGLUTのインストールですが、glut.hをどこに置くかが問題になります。アドレスは以下の通り。
C:\Program Files\Microsoft Visual Studio 10.0\Vc\Include\gl\glut.h
glフォルダはデフォルトで存在しないので、自分で作ってください。

また、2010ではプロジェクトでのプロパティ設定のみとなっているので、
「インクルードディレクトリ」と「ライブラリディレクトリ」は「プロジェクトのプロパティ」から設定してください。
「VC++ディレクトリ」という項目が2010では新設されておりますので。


とりあえずWindowを表示してみよう(2010/5/5 編集中)


まずはOpenGLでウィンドウを表示してみましょう。
かといって真っ白画面だと味気ないので、格子状の地面も表示します。

+ ←ソースを表示するにはこちらをクリック


#include ‹math.h›
#include ‹fstream›
#include ‹sstream›
#include ‹iostream›
#include ‹direct.h›
#include ‹GL/glut.h›

int WindowPositionX = 400;  //生成するウィンドウ位置のX座標
int WindowPositionY = 200;  //生成するウィンドウ位置のY座標
int WindowWidth     = 640;  //生成するウィンドウの幅
int WindowHeight    = 480;  //生成するウィンドウの高さ
char WindowTitle[]  = "ロボット視点";  //ウィンドウのタイトル

double ViewPointX   = 0.0;//視点X座標
double ViewPointY   = -300.0;//視点Y座標
double ViewPointZ   = 50.0;//視点Z座標

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

  //透視変換行列の設定------------------------------
  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(
       ViewPointX, ViewPointY, ViewPointZ, // 視点の位置x,y,z;
       0.0,        0.0,        ViewPointZ, // 視界の中心位置の参照点座標x,y,z
       0.0,        0.0,        1.0 ) ;     //視界の上方向のベクトルx,y,z
  //----------------------------------------

  //モデルビュー変換行列の設定--------------------------
  glMatrixMode(GL_MODELVIEW);//行列モードの設定(GL_PROJECTION : 透視変換行列の設定、GL_MODELVIEW:モデルビュー変換行列)
  glLoadIdentity();//行列の初期化
  glViewport(0, 0, WindowWidth, WindowHeight);
  //----------------------------------------------

  glEnd();
  glPopMatrix();
  Ground();//地面描画
  glutSwapBuffers(); //glutInitDisplayMode(GLUT_DOUBLE)でダブルバッファリングを利用可
}
//----------------------------------------------------
// アイドル時に呼び出される関数
//----------------------------------------------------
void Idle(){
  glutPostRedisplay(); //glutDisplayFunc()を1回実行する
}

//----------------------------------------------------
// 地面の描画(格子)
//----------------------------------------------------
void Ground(void){
  double ground_max_x = 500.0;//x方向広さ
  double ground_max_y = 500.0;//y方向広さ
  glColor3d(0.5, 0.5, 1.0);  // 大地の色
  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();
}
下のようなウィンドウが実行されたでしょうか?




真っ白なウィンドウを表示するだけなら↓のソースで可能です。

+ ←表示するにはこちらをクリック


#include ‹GL/glut.h›
int WindowPositionX = 100;  //生成するウィンドウ位置のX座標
int WindowPositionY = 100;  //生成するウィンドウ位置のY座標
int WindowWidth = 512;    //生成するウィンドウの幅
int WindowHeight = 512;    //生成するウィンドウの高さ
char WindowTitle[] = "世界の始まり"  ;//ウィンドウのタイトル
//----------------------------------------------------
// 関数プロトタイプ(後に呼び出す関数名と引数の宣言)
//----------------------------------------------------
void Initialize(void);
void Display(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);  //ウィンドウの作成
  glutDisplayFunc(Display); //描画時に呼び出される関数を指定する(関数名:Display)
  Initialize(); //初期設定の関数を呼び出す
  glutMainLoop();
  return 0;
}
//----------------------------------------------------
// 初期設定の関数
//----------------------------------------------------
void Initialize(void){
  glClearColor(1.0, 1.0, 1.0, 1.0); //背景色
  glEnable(GL_DEPTH_TEST);//デプスバッファを使用:glutInitDisplayMode() で GLUT_DEPTH を指定する
}
//----------------------------------------------------
// 描画の関数
//----------------------------------------------------
void Display(void) {
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //バッファの消去
  glutSwapBuffers(); //glutInitDisplayMode(GLUT_DOUBLE)でダブルバッファリングを利用可
}


ここでのキーワードは以下の通りです。
  1. プログラムの全体的流れの把握
  2. 視点という概念
  3. 地面の描写

地面の上に立方体を表示して、視点を変えてみよう(2010/5/5 編集中)


地面だけでは味気ないですね。さて、実際に物体、ここでは立方体を描写しましょう。
ソースはこちらです。
下のようなウィンドウが実行されたでしょうか?



ここでのキーワードは以下の通りです。
  1. 視点の移動
  2. オブジェクトの描画

マウスドラッグで立方体をグリグリ回してみよう(2010/5/5 編集中)

キーボード入力をしてみよう(2010/5/5 編集中)


ここではキーボードからの入力によって視点(ViewPoint)を変えてみましょう。

下記のソースを実行すると下図のようなウィンドウが開きます。
キー操作は「a,s,d,wがそれぞれ左、下、右、上」「qが終了」となっています。

+ ←ソースを表示するにはこちらをクリック


#include ‹math.h›
#include ‹fstream›
#include ‹sstream›
#include ‹iostream›
#include ‹direct.h›
#include ‹GL/glut.h›

double PI = acos(-1.0);

int WindowPositionX = 400;  //生成するウィンドウ位置のX座標
int WindowPositionY = 200;  //生成するウィンドウ位置のY座標
int WindowWidth     = 640;  //生成するウィンドウの幅
int WindowHeight    = 480;  //生成するウィンドウの高さ
char WindowTitle[]  = "ロボット視点ぐりぐり";  //ウィンドウのタイトル

double ViewPointX   = 0.0;
double ViewPointY   = -200.0;
double ViewPointZ   = 50.0;

int tn = 0,zn=50 ;
double t = 0;
double dt = 0.1;
double omega = 2.0 * PI / 20.0;

//----------------------------------------------------
// 立方体の定義
//----------------------------------------------------
GLdouble vertex[][3] = {
  { -10.0, -10.0, 0.0 },
  { 10.0, -10.0, 0.0 },
  { 10.0, 10.0, 0.0 },
  { -10.0, 10.0, 0.0 },
  { -10.0, -10.0, 20.0 },
  { 10.0, -10.0, 20.0 },
  { 10.0, 10.0, 20.0 },
  { -10.0, 10.0, 20.0 }
},;
int face[][4] = {//面の定義
  { 0, 1, 2, 3 },
  { 1, 5, 6, 2 },
  { 5, 4, 7, 6 },
  { 4, 0, 3, 7 },
  { 4, 5, 1, 0 },
  { 3, 2, 6, 7 },
}
GLdouble normal[][3] = {//面の法線ベクトル
  { 0.0, 0.0,-1.0 },
  { 1.0, 0.0, 0.0 },
  { 0.0, 0.0, 1.0 },
  {-1.0, 0.0, 0.0 },
  { 0.0,-1.0, 0.0 },
  { 0.0, 1.0, 0.0 },
}
//----------------------------------------------------
// 物質質感の定義
//----------------------------------------------------
struct MaterialStruct {
  GLfloat ambient[4];
  GLfloat diffuse[4];
  GLfloat specular[4];
  GLfloat shininess;
}
//jade(翡翠)
MaterialStruct ms_jade = {
  {0.135,     0.2225,   0.1575,   1.0},
  {0.54,      0.89,     0.63,     1.0},
  {0.316228,  0.316228, 0.316228, 1.0},
  12.8}
//----------------------------------------------------
// 色の定義の定義
//----------------------------------------------------
GLfloat green[] = { 0.2, 0.8, 0.2, 1.0 }//緑色
GLfloat shininess = 30.0;//光沢の強さ
//-----------------------------------------

//----------------------------------------------------
// 関数プロトタイプ(後に呼び出す関数名と引数の宣言)
//----------------------------------------------------
void Initialize(void);
void Display(void);
void Idle();
void Ground(void);  //大地の描画
void Keyboard(unsigned char key, int x, int y);

//----------------------------------------------------
// メイン関数
//----------------------------------------------------
int main(int argc, char *argv[]){

  glutInit(&argc, argv);//環境の初期化
  glutInitWindowPosition(WindowPositionX, WindowPositionY);//ウィンドウの位置の指定
  glutInitWindowSize(WindowWidth, WindowHeight); //ウィンドウサイズの指定
  glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE);//ディスプレイモードの指定
  glutCreateWindow(WindowTitle);  //ウィンドウの作成
  glutDisplayFunc(Display); //描画時に呼び出される関数を指定する(関数名:Display)
  glutKeyboardFunc(Keyboard);//キーボード入力時に呼び出される関数を指定する(関数名:Keyboard)
  glutIdleFunc(Idle);       //プログラムアイドル状態時に呼び出される関数
  Initialize(); //初期設定の関数を呼び出す
  glutMainLoop();
  return 0;
}
//----------------------------------------------------
// 初期設定の関数
//----------------------------------------------------
void Initialize(void){
  glClearColor(0.6, 0.6, 0.9, 1.0); //背景色
  glEnable(GL_DEPTH_TEST);//デプスバッファを使用:glutInitDisplayMode() で GLUT_DEPTH を指定する

  //光源の設定--------------------------------------
  GLfloat light_position0[] = { -50.0, -50.0, 20.0, 1.0 }//光源0の座標
  glLightfv(GL_LIGHT0, GL_POSITION, light_position0); //光源0を

}
//----------------------------------------------------
// 描画の関数
//----------------------------------------------------
void Display(void) {
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //バッファの消去
  
  t = dt * tn;//tnは後ほどインクリメントされる
  ViewPointX = -100.0 * cos( omega * t);//立方体の周りをぐるぐる視点が回転する
  ViewPointY = -100.0 * sin( omega * t);//Z軸方向から見ると回転運動
  ViewPointZ = 50+zn; //Z軸方向から見ると回転運動

  //透視変換行列の設定------------------------------
  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(
       ViewPointX, ViewPointY, ViewPointZ, // 視点の位置x,y,z;
       0.0,        0.0,        0.0, // 視界方向
       0.0,        0.0,        1.0 ) ;     //重力方向、要するに「上・空」はどっち?
  //----------------------------------------

  //モデルビュー変換行列の設定--------------------------
  glMatrixMode(GL_MODELVIEW);//行列モードの設定(GL_PROJECTION : 透視変換行列の設定、GL_MODELVIEW:モデルビュー変換行列)
  glLoadIdentity();//行列の初期化
  glViewport(0, 0, WindowWidth, WindowHeight);
  //----------------------------------------------

  //陰影ON-----------------------------
  glEnable(GL_LIGHTING);
  glEnable(GL_LIGHT0);//光源0を利用
  //-----------------------------------
  
  //立方体
  glPushMatrix();
  glMaterialfv(GL_FRONT, GL_AMBIENT, ms_jade.ambient);
  glMaterialfv(GL_FRONT, GL_DIFFUSE, ms_jade.diffuse);
  glMaterialfv(GL_FRONT, GL_SPECULAR, ms_jade.specular);
  glMaterialfv(GL_FRONT, GL_SHININESS, &ms_jade.shininess);
  glTranslated(0.0, 0.0, 0.0);//平行移動値の設定
  glBegin(GL_QUADS);
  for (int j = 0; j < 6; ++j) {
    glNormal3dv(normal[j]); //法線ベクトルの指定
    for (int i = 0; i < 4; ++i) {
      glVertex3dv(vertex[face[j][i]]);
    }
  }
  glEnd();
  glPopMatrix();
  //陰影OFF-----------------------------
  glDisable(GL_LIGHTING);
  //-----------------------------------
  Ground();
  glutSwapBuffers(); //glutInitDisplayMode(GLUT_DOUBLE)でダブルバッファリングを利用可
}
//----------------------------------------------------
// アイドル時に呼び出される関数
//----------------------------------------------------
void Idle(){
  glutPostRedisplay(); //glutDisplayFunc()を1回実行する
}

//----------------------------------------------------
// 地面の描画
//----------------------------------------------------
void Ground(void){
  double ground_max_x = 500.0;
  double ground_max_y = 500.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();
}
//----------------------------------------------------
// キーボード入力時に呼び出される関数
//----------------------------------------------------
void Keyboard(unsigned char key, int x, int y){
  switch ( key )
  {
  case 'a'://「a」を押したら反時計回り
    tn--;
    break;
  case 'd'://「d」を押したら時計回り
    tn++;
    break;
  case 'w'://「w」を押したら視点上昇
    zn++;
    break;
  case 's'://「s」を押したら視点下降
    zn--;
    break;
  case 'q'://「q」を押したら終了
    exit(0);
    break;

  default:
    break;
  }
}

文字の表示をしてみよう(2010/5/5 編集中)

ウィンドウ映像をビットマップで紙芝居的に保存しよう(2010/5/5 編集中)

ゲームパッド(コントローラ)で入力してみよう(2010/5/5 編集中)

半透明な物体を表現してみよう(2010/5/5 編集中)

動く笑い男を表示してみよう(2010/5/5 編集中)



















最終更新:2010年05月21日 21:52