[Work/Class/OpenGL/1_OpenGL1x]

OpenGL 1.x系の透視投影 - 3Dグラフィックのプリミティブなオブジェクトの表示とカメラの設定・移動

gluPerspectiveの概念図

gluPerspectiveの概念図は上記のようになる.(画像はSource:unknownとして出回っている画像だが,公式赤本OpenGL Programming Guideが出展)

gluPerspective関数は,

  • カメラの画角(fovy)
  • 描画する最近の距離,描画する最遠の距離
  • 画面のアスペクト比

のパラメータからなる.概念図の染められている領域が透視図法によって描画される.

/* 3DGraphicsWithPerspectiveProjection_1.c */

#ifdef __APPLE__
#include <OpenGL/opengl.h>
#include <OpenGL/glu.h> //gluというのが新しく追加されたよ
#include <GLUT/glut.h>
#else
#include <GL/gl.h>
#include <GL/glu.h> //gluというのが新しく追加されたよ
#include <GL/glut.h>
#endif

//あらかじめ描画する座標を2次元配列として作っておく
double myTriangle1[3][3] = {
  {0.8, 0.1, 0.0},
  {-0.3, -0.2, 0.0},
  {0.4, -0.8, 0.0}};

double myTriangle2[3][3] = {
  {0.5, 0.0, 0.0}, //Z座標は0とする
  {-0.5, -0.3, 0.9},
  {0.2, -0.4, 0.8}};

float cameraPosZ = 1.0;

void display(void){
  //背景を塗りつぶす
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  //隠面消去指定をする(ちゃんと後ろにあるものは隠れるようにする)
  glEnable(GL_DEPTH_TEST); 

  //投影変換モードへ入る
  glMatrixMode(GL_PROJECTION); 
  glLoadIdentity(); //投影変換の変換行列を単位行列で初期化

  //gluPerspective()を実行することで透視変換を指定する.
  //引数はカメラの視野角(度数,ここでは120度),アスペクト比(ここでは4:3), 
  //見える範囲でカメラから一番近い距離,見える範囲でカメラから一番遠い距離,となる.
  gluPerspective(120.0, 1.333333, 0.1, 1000000.0);

  glMatrixMode(GL_MODELVIEW); //視野変換・モデリング変換モードへ
  glLoadIdentity(); //視野変換・モデリング変換の変換行列を単位行列で初期化
  //カメラの位置を指定
  float cameraPosX = 0.0; //カメラの位置
  float cameraPosY = 0.0;
  //cameraPosZ はtimer関数によって随時更新されていく
  float cameraCenterX = 0.0; //カメラが見る座標
  float cameraCenterY = 0.0;
  float cameraCenterZ = 0.0;
  float cameraAngleX = 0.0; //カメラの位置とカメラが見る座標の線分上で
  float cameraAngleY = 1.0; //カメラの「上」を定義する.
  float cameraAngleZ = 0.0; //通常はYだけ1にしておけば良い
  gluLookAt(cameraPosX, cameraPosY, cameraPosZ,
	    cameraCenterX, cameraCenterY, cameraCenterZ,
	    cameraAngleX, cameraAngleY, cameraAngleZ);

  //------ここから下でモデル・オブジェクトの描画をする-----------------

  glPushMatrix(); //ここからglPopMatrix()までひとまとまりとする.
  //これから描く色を指定する(RGBA)
  glColor4f(1.0, 0.0, 0.0, 0.0);
  //Teapotを描画する.
  glutSolidTeapot(0.5);
  glPopMatrix();


  glPushMatrix();//また新たにひとまとまりの描画を行う.

  //これから描画するモデルは回転させますよ,という命令.
  //引数は,回転する角度,残り三つが原点からそのポイントまでを回転軸とするx, y, z
  glRotatef(60, 1.0, 1.0, 1.0);
  //新たに線の色を指定する
  glColor4f(0.0, 1.0, 0.0, 0.0);
  //あらかじめ作っておいた頂点配列を描画する.
  glBegin(GL_LINE_LOOP);
  for(int i=0; i<3; i++){
    glVertex3d(myTriangle1[i][0], myTriangle1[i][1], myTriangle1[i][2]);
  }
  glEnd();
  glPopMatrix();

  glPushMatrix();
  //新たに色を指定する
  glColor4f(0.0, 0.0, 1.0, 0.0);
  //今度は塗りつぶす三角形
  glBegin(GL_TRIANGLES);
  for(int i=0; i<3; i++){
    glVertex3d(myTriangle2[i][0], myTriangle2[i][1], myTriangle2[i][2]);
  }
  glEnd();
  glPopMatrix();

  //-----------モデルの描画ここまで-------------------

  
  glutSwapBuffers();
  
}

void resize(int windowWidth, int windowHeight) {
    glViewport(0, 0, windowWidth, windowHeight); //ウインドウ全体に表示
}

void timer(int value){
  
  cameraPosZ += 0.01;
  glutPostRedisplay();
  glutTimerFunc(100, timer, 0);
}

int main(int argc, char *argv[])
{
  glutInit(&argc, argv);
 
  glutInitWindowSize(640, 480); 
  
  glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
  //GLUT_DEPTHを指定することで,Z軸が使える様になる.
  glutCreateWindow("3DGraphicsWithPerspectiveProjection_1");

  glutDisplayFunc(display);
  glutReshapeFunc(resize); //関数resizeをコールバックに設定

  //黒で塗りつぶす指定をする
  glClearColor(0.0, 0.0, 0.0, 0.0);

  glutTimerFunc(100, timer, 0);
  
  //メインループ開始
  glutMainLoop();
  return 0;
}