'OpenGL 활용/1장 - Basic'에 해당되는 글 6건

  1. 2013.01.22 1장 6절 - Mouse Motion Event
  2. 2013.01.22 1장 5절 - Mouse Event
  3. 2013.01.21 1장 4절 - Animation by Idling
  4. 2013.01.20 1장 3절 - Keyboard Event
  5. 2013.01.20 1장 2절 - Resize OpenGL Window
  6. 2013.01.19 1장 1절 - Create a Simple OpenGL Window

1장 6절 - Mouse Motion Event

|

Mouse Motion Event

 

 

 

GLUT 는 Mouse 를 Window 위에서 움직여 Window 상에 있는 물체에 움직임을 줄 수 있는 다음 2개의 callback 함수를 제공하고 있다.

  

 void glutMotionFunc( void (*func)(int x, int y) );
 void glutPassiveMotionFunc( void (*func)(int x, int y) );

 

위 두 개의 함수중 위의 것은 Mouse 를 눌렀을때의 Window 상의 위치 (x, y), 아래의 함수는 Mouse를 누르지 않았을 때의 위치를 기억한다. 위의 함수는 Mouse callback 함수 glutMouseFunc() 과 함께 사용하여,  필요한 실행에 대해 명령을 하게된다.

 

앞절의 프로그램에서 다음을 수정하여 보자.

전역지역에 다음의 변수와 함수의 prototype 을 새로 더한다.

 

           .

      .

enum      actions { MOVE_OBJECT, ROTATE_OBJECT, ZOOM_OBJECT, DO_NONE };
GLsizei   action;
GLsizei   xini = 0,   yini = 0;
GLfloat   xmov = 0.0, ymov = 0.0;

 

// function prototypes

      .

void  motion( int, int );

      .

      .

 

main() 함수:

 

                     .

            . 
      // handling input events
      glutKeyboardFunc( keyboard );
      glutSpecialFunc( special );
      glutMotionFunc( motion );
      glutMouseFunc( mouse );

 

      // idle function registration for animation
   // glutIdleFunc( idle );   // 주석처리

           .

           .

 

display() 함수:

 

          .

          . 

     // draw a point on the center of window
      glColor4f( 1.0, 1.0, 1.0, 1.0 );
      glPointSize( 5.0 );
      glBegin( GL_POINTS );
            glVertex3f( 1.0, 1.0, 0.0 );
      glEnd();

 

      /*  Translate & rotate the image  */
      glPushMatrix();                       // Save the transformations performed
      glTranslatef( 1.0, 1.0, 0.0 );        // move axes origin to center
      glRotatef( xrot, 1.0f, 0.0f, 0.0f );  // rotate the image
      glRotatef( yrot, 0.0f, 1.0f, 0.0f );
      glRotatef( zrot, 0.0f, 0.0f, 1.0f );
      glTranslatef( -1.0, -1.0, 0.0f );     // move axes origin to center
      glTranslatef( xmov, ymov, 0.0f );     // translate location by mouse move

          .

          .

 

mouse() 함수:   왼쪽 Mouse 를 물체의 회전을 실행하는 것 대신에 물체의 이동에 대한 실행을 하고,  대신 중간 Mouse button 을 눌렀을 때 물체의 회전이 서로 toggling 하도록 다음과 같이 새로 작성한다.

 

 void mouse( int button, int state, int x, int y )
{
      if (state == GLUT_DOWN) {  // when the button is released
            switch (button) {
               case GLUT_LEFT_BUTTON:
                        action = MOVE_OBJECT;
                        break;
               case GLUT_MIDDLE_BUTTON:
                        action = ROTATE_OBJECT;
                        rot_status = !rot_status;
                        if (rot_status) glutIdleFunc( idle );
                        else            glutIdleFunc( NULL );
                        glutPostRedisplay();
                        break;

               case GLUT_RIGHT_BUTTON:
                        action = ZOOM_OBJECT;
                        break;
            }

            /* Update the saved mouse position */
            xini = x;
            yini = y;
      } else {
            action = DO_NONE;
      }
}

 

motion() 함수:

 

void  motion( int x, int y )
{      
      // this will only be true when the left button is down
      if (action == MOVE_OBJECT) { // update dx, dy
            xmov += (GLfloat)(x - xini) * 0.025f;
            ymov += (GLfloat)(yini - y) * 0.025f;
      }

      /* Update the stored mouse position for later use */
      xini = x;
      yini = y;

 

      glutPostRedisplay();
}

 

위의 두 함수를 분석해 보면,  mouse() 함수에서는 Mouse button 을 눌렀는지, 해지했는지에 대한 정보와 Mouse 를 눌렀을 때의 초기위치를 기억한다.  motion() 함수에서는 현재의 Mouse 위치를 찾아 Mouse 가 움직인 거리를 계산하고,  항상 Mouse  위치를 초기화 시킨다.  glutPostRedisplay() 함수를 통해 화면을 다시 정리하고 있다.  주의 깊게 보아야 할 점은 두 함수 모두 초기값을 기억하도록 하고 있는데, 이는 두 함수 모두에게 초기치를 기억시켜 mouse 에 대한 정확한 위치계산을 하기 위한 것이다.  두 함수 중에 하나에 대한 초기화를 하지 않았을 경우 움직임을 살펴보면, 사용자가 의도한 정확한 거리계산에 에러가 생기게 된다.   motion() 함수에 대한 변수들은 항상 전역변수화 되어 전체 Program 에 영향을 주도록 하는것이 일반적이다.  

Mouse 를 누르지 않은 상태에서 어떤 움직임에 대한 실행을 하고자 한다면,  위 두 함수의 Up, Down 의 조건을 서로 바꾸어 주고,  glMotionFunc()  대신 glPassiveMotionFunc() callback 함수 를 사용하면 된다.  이 경우는 Mouse button 을 눌렀을 시 요구하는 명령을 실행하지 않게 된다.

 

Program 을 컴파일 한 후 화면내의 Image 를 Mouse 로 이리저리 Drag 해보면 Image 가 순조롭게 이동하는 것을 볼 수 있다.  화면의 중앙의 위치를 보여주기 위하여,  흰색 점을 하나 추가 하였다.   화살표나 Page Up, Down key,  또는 Space bar 를 사용하여 삼각형을 회전 시켰을 경우 Mouse 의 이동에 대한 물체의 이동 방향이 서로 바꾸어 지는것은 물체의 회전에 따라 좌표축이 회전하고, 그에 따라 Window 의 (x, y) 위치가 서로 뒤집어져 나타나는 현상이다.  Program 을 분석하여 보면 그 이유를 이해를 할 수 있을 것이다.  따라서 Home key 를 눌러 회전위치를 원위치로 돌려놓은 후에 Mouse 을 이동 시키면 물체가 Mouse 의 이동방향에 따라 움직이게 된다.

 

 

 

 

 

 

 

 

 

응용 Program:

 

 

1장 3 절에 있는 advanced_keyboard  프로그램을 수정하면서 Mouse Motion 에 대한 부분을 좀 더 살펴보자.  이 프로그램은 화살표 Key 를 좌우로 움직여 360 도로 보는 방향을 회전시키고,  상하 화살표 Key 로 물체를 화면의 전후로 이동 (Zoom In & Out) 시키도록 구성되어 있었다.   Special key 에 의한 작동을 Mouse 의 왼쪽 과 오른쪽 Button 으로 대체 하여 보는 시각을 이동시키도록 수정하여 보자.  Mouse 의 왼쪽 Button 은 시각의 회전, 오른쪽 Button 은 Zoon In/Out 의 역할을 맡는다.

 

전역 지역에 다음의 변수와 함수의 Prototype 을 첨가한다. 

 

      .

      .

GLsizei   xini = 0, yini = 0;

// function prototypes
      .

      .

// void  pressKey( int, int, int );    // 2개의 함수 주석처리
// void  releaseKey( int, int, int );

void  motion( int, int );              // 새로운 함수 추가
void  mouse( int, int, int, int );
      .

      .

 

main() 함수:

 

                 .

          .


      // handling input events
      glutKeyboardFunc( keyboard  );
   // glutSpecialFunc( pressKey );  // 다음 3개의 함수를 주석처리
   // glutIgnoreKeyRepeat(1);       // ignore key repeat press
   // glutSpecialUpFunc( releaseKey );
      glutMotionFunc( motion );     // 2개의 함수 추가 

      glutMouseFunc( mouse );

 

      // enter GLUT event processing cycle
      glutMainLoop();

          .

          .

 

display() 함수아래 2개의 함수는 keyboard 를 통해서 들어오는 값은 처리하는 함수이므로 주석처리한다.

 

         .

    // if (dmov) computePos( dmov ); // 주석처리
    // if (drot) computeDir( drot );

         .

 

 pressKey()  와  releaseKey() 함수를 지운 후에, 다음의 motion() mouse() 함수를 만든다.

 

mouse() 함수:

 

void  mouse( int button, int state, int x, int y )
{
      // only start motion if the button is pressed
      if (state == GLUT_UP) { // when the button is released
            switch (button) {
               case GLUT_LEFT_BUTTON:
                        angle += drot;
                        xini = 0;
                        break;
               case GLUT_RIGHT_BUTTON:
                        yini = 0;
                        break;
            }
      } else {
            switch (button) {
               case GLUT_LEFT_BUTTON:
                        xini = x;
                        break;
               case GLUT_RIGHT_BUTTON:
                        yini = y;
                        break;
            }
      }
}

 

motion() 함수:

 

 void  motion( int x, int y )
{      
      // this will only be true when the mouse button is down
      if (xini > 0) {  // left mouse button is pressed
            drot = (GLfloat)(xini - x) * 0.002f; // update drot

            // update camera's direction
            lx =  sin(angle + drot);
            lz = -cos(angle + drot);
      }
      if (yini > 0) {  // right mouse button is pressed

            dmov = (GLfloat)(yini - y) * 0.05f;
            xx += dmov * lx * 0.1f;
            zz += dmov * lz * 0.1f;
      }
}

 

여기서 보면,   Mouse 위치에 대한 초기값과,  최종적인 계산값 angle 에 대한 함수의 위치가, 위에서 설명한 것과 조금 다름을 엿볼 수 있다.  이는 변수 angle 이 motion() 함수에서보다 mouse() 함수에 있을 때 움직임이 좀더 부드럽기 때문이다 (motion() 함수에서 사용하려면 drot 값을 아주 낮게 잡아주어야 함).   이와 같이 Mouse motion 에 대한 것은 mouse() 함수 와  motion() 함수가 전역변수를 통하여 서로 밀접하게 연계되므로,  프로그램하기에 따라 여러 형태로 구성을 할 수 있다. 

이제는 좌우 화살표 Key 대신에 Mouse 의 좌우 Button을 누른다음 커서를 이동시켜가며 화면의 물체를 시각을 달리하여 볼 수 있게 되었다.

 

 

 

 

 

 

Source Code:         01_6 - motion.zip                 01_6 - advanced_motion.zip       

 

 

 

 

'OpenGL 활용 > 1장 - Basic' 카테고리의 다른 글

1장 5절 - Mouse Event  (0) 2013.01.22
1장 4절 - Animation by Idling  (0) 2013.01.21
1장 3절 - Keyboard Event  (0) 2013.01.20
1장 2절 - Resize OpenGL Window  (0) 2013.01.20
1장 1절 - Create a Simple OpenGL Window  (0) 2013.01.19
And

1장 5절 - Mouse Event

|

Mouse Event

 

 

GLUT 에서는 Mouse 의 Button 을 눌러 Event 를 Handling 하는 것을 제공하고 있다. Mouse event 에 대한 callback 함수는

 

 void glutMouseFunc( void (*func)(int button, int state, int x, int y) );

 

로 표현하는데,  변수 button 은 mouse 의 왼쪽, 중간, 오른쪽 button 을 선택하고,  state 는 누름과 해지, x, y 는 Window 위의 pixel 위치를 확인한다.  위 함수는 단독으로 사용하는것은 별로 많지 않지만,  다음에 배울 mouse motion 과 Popup Menu 의 기능을 함께 할 때 연계되어 많이 사용된다.

 

이전 animation 프로그램에서 몇 가지를 새로 수정해보자.

 

전역변수:

 

GLboolean rot_status = FALSE;

 

main() 함수:

  

            .

            .

      // handling input events
      glutKeyboardFunc( keyboard );
      glutSpecialFunc( special );
      glutMouseFunc( mouse );

 

      // idle function registration for animation
   // glutIdleFunc( idle );    // 주석처리
   // Timer( 0 ); // glutTimerFunc( 1, Timer, 0 );
            .

            .

 

main() 함수에서 새로 glutMouseFunc() callback 함수를 첨가하고, glutIdleFunc() callback 함수를 주석 처리 하였다.

 

다음의 glutMouseFunc() callback 함수에 필요한 mouse() 함수를 다음과 같이 작성해 program 에 첨가해 보자.

 

void  mouse( int button, int state, int x, int y )
{
      switch (button) {
         case GLUT_LEFT_BUTTON:
                  if (state == GLUT_DOWN) {
                         rot_status = TRUE;
                         glutIdleFunc( idle );

                  }
                  break;
         case GLUT_MIDDLE_BUTTON:
         case GLUT_RIGHT_BUTTON:
                  if (state == GLUT_DOWN) {
                         rot_status = FALSE;
                         glutIdleFunc( NULL );

                  }
                  break;
         default:
                  break;
      }
}

 

쪽 mouse button 을 누르면,  idle  callback 함수를 활성화 시키고, 가운데, 또는 오른쪽 mouse button 을 눌렀을 시 비활성화 시키도록 하였다.  따라서 왼쪽과 오른쪽 mouse button 을 눌러 삼각형의 회전을 멈추고, 다시 시작하고 할 수 있다.  '<'  ,  '>' key 를 사용하여 회전 속도를 변화시킬수 있다.

 

 

 

Source Code:           01_5 - mouse.zip

 

 

 

'OpenGL 활용 > 1장 - Basic' 카테고리의 다른 글

1장 6절 - Mouse Motion Event  (0) 2013.01.22
1장 4절 - Animation by Idling  (0) 2013.01.21
1장 3절 - Keyboard Event  (0) 2013.01.20
1장 2절 - Resize OpenGL Window  (0) 2013.01.20
1장 1절 - Create a Simple OpenGL Window  (0) 2013.01.19
And

1장 4절 - Animation by Idling

|

Animation by Idling

 

 

 

OpenGL  에서 이미지의 움직임과 동작을 주기 위한 방법으로 glutIdleFunc() glutTimerFunc() callback 함수가 있다.  함수의 syntax 는 다음과 같다.

 

void glutIdleFunc( void (*func)(void) );

void glutTimerFunc( unsigned int millisec, void (*func)(int value), int value );

 

참고 Site:    glutIdleFunc()    http://www.opengl.org/resources/libraries/glut/spec3/node63.html

                    glutTimerFunc()     http://www.opengl.org/resources/libraries/glut/spec3/node64.html

 

 

간단한 Animation 을 해보기 위해 다음의 함수를 main() 함수에 등록하고,  idle() 함수 와 Timer() 함수를 만들어 보자.

 

추가 전역변수:

 

 GLfloat   speed = 1.0;

 GLboolean rot_status = TRUE;

 

main() 함수:

 

           .

           .

      // init GLUT and create Window
      glutInit( &argc, argv );
      glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH );
      glutInitWindowSize( wwidth, wheight );
 
          .

           . 
      // handling keyboard input events
      glutKeyboardFunc( keyboard  );
      glutSpecialFunc( special );
      glutIdleFunc( idle );
   // Timer( 0 ); // glutTimerFunc( 1, Timer, 0 );

 

      // enter GLUT event processing cycle
      glutMainLoop();

           .

           .

 

diaplay() 함수:  마지막의 glFlush(); 를 주석처리 해주고 대신

 

            .

            .

   // glFlush();        // 주석처리
      glutSwapBuffers();
}

 

keyboard() 함수:  삼각형의 회전 속도의 변화를 주기위하여 다음을 더한다.

 

             .

             .
         case '+':
                  if (magfac <= 2.0f) magfac += 0.02;
                  break;
         case '-':
                  if (magfac >= 0.04) magfac -= 0.02;
                  break;
         case '>':
                  speed += 1.0f;
                  break;
         case '<':
                  speed -= 1.0f;
                  break;

         case ' ': // space bar
                  rot_status = !rot_status;
                  if (rot_status) glutIdleFunc( idle );
                  else            glutIdleFunc( NULL );
                  break;
         case 27:

                  exit(0);
                  break;

            .

            .

 

idle() 함수:

 

 void  idle( void )
{
      zrot += speed * 0.025f;
      if (zrot > 360.0f) zrot -= 360.0f;
      glutPostRedisplay(); // tell GLUT that the display has changed
}

 

Timer() 함수:

 

 void  Timer( int value )
{
      zrot += speed * 1.0f;
      if (zrot > 360.0f)  zrot -= 360.0f;
      glutPostRedisplay(); // tell GLUT that the display has changed
     
      // tell GLUT to call update again in 25 milliseconds
      glutTimerFunc( 25, Timer, 0 );
}

 

main() 에 있는 glutInitDisplayMode() 의 Mode 가 GLUT_SINGLE 에서 GLUT_DOUBLE 로 변화되었음을 볼 수 있다.  그리고 display() 함수의 마지막을 glFlush() 대신 glutSwapBuffers() 를 사용하였다.   이는 GLUT_DOUBLE 로 이중 Buffer 를 사용할여 앞, 뒤의 Buffer 를 서로 Swapping 하면서 교환하라는 명령을 주기 위함이다. 

한 Buffer 에서 지웠다 그리기를 계속 반복하면 깜박거림이 발생하여 눈에 거슬리므로 두 개의 Buffer 를 교대로 사용한다.  초기화시에 GLUT_DOUBLE  flag 를 전달하면 OpenGL 은 화면에 출력하는 Front Buffer 와 뒤에서 그리는 작업을 하는 Back Buffer, 두 개의 Buffer 를 준비한다.  glutSwapBuffers() 에 의해  Front Buffer 와 Back Buffer 가 일시에 교체됨으로써 Back Bufff  에 미리 준비해 놓은 그림이 바로 나타난다.  순간적으로 교체되므로 깜박거림은 전혀 느낄 수 없다.  이 과정을 계속 반복하면 animation 이 되는 것이다.  Buffer 를 교체하는 것 자체가 출력이므로 glFlush() 는 호출하지 않아도 상관없다.  위 에서 speed 는 전역변수로 rotation 속도를 조절하기 위한 변수이다.  '<'  와 '>' key 로 크기를 조절하게 하였다.

 

idle() 함수는 단지 idling 시간만을 지정해 주고,  glutPostRedisplay() 함수를 불러 display 할 내용을 변화시키도록 한다.

위 두개의 함수의 차이를 보면 Timer() 함수는 함수내에서 다시 재귀 (recursive) 형태로 자신을 다시 호출한다는 것이다.  이유는 glutTimerFunc() 은 지정된 시간후에 지정된 함수를 딱 한번 호출한다.  주기적으로 계속 호출하려면 callback 함수에서 자신을 다시 호출해야 한다. 지속적으로 호출되는 방식에 비해 약간 불편하지만 매 호출시마다 다음 주기를 가변적으로 결정할 수 있다는 면에서 활용성은 오히려 더 높다.     더 이상 Timer() 호출이 필요없으면 callback 을 재등록하지 않으면 된다.   함수의 동작형태는 millisec 후에 Timer() 함수를 호출하며 인수로 value를 전달한다.   value는 Timer callback 으로 전달되어 작업 시간의 거리를 지시하는데,  Timer 의 용도가 하나뿐이라면 아무 값이나 주어도 상관없다.   callback 을 등록해 놓으면 millisec 후에 callback 함수가 호출된다.    main() 에서는 다만 시동만 걸어줄 뿐이고 다음 타이머 호출 시점은 callback 함수가 자체적으로 결정할 수 있다.

 

System 이 초당 60 frame 을 refresh 한다고 가정하면,  가장 빠른 frame 율은 60 fps 이다.  따라서 1/60 초 이내에 frame 이 정리되고 다시 그려져야 부드럽게 움직이는 animation  이 된다.   그림이 복잡하여 한 frame 을 그리는데 1/45 초가 걸린다면,  frame 율은 30 fps 가 될 것이다.  이 경우 graphic 은 1/30 - 1/45 = 1/90 초의 frame 당 시간 (sec per frame) 의 idle 이 요구된다.    만일 Back Buffer 에서 각각의 그림들이 그려지는 시간이 일정하지 않다면,  어떤 frame 은 시간을 좀더 많이 쓰고, 어떤 frame 은 시간을 적게 쓰게 되는 현상들이 발생할 것이다.  이러한 현상들에 의해 부드러운 Animation 진행과정이 방해 받게된다.

 

프로그램을 컴파일한 후 실행하면서, 앞 절, keyboard 프로그램 실행시 Test 해 보았던 것들을 해보면, 어떤 변화가 일어나는지를 볼 수 있을 것이다.  

 

 

 

 

응용 Program:

 

무한정 움직이는 1개의 당구공을 생각해 보자.  당구공은 당구대의 벽면에 대한 입사각에 대하여 같은 반사각으로 튕겨진다.  이 원리를 적용하여 공의 위치를 속도에 따른 움직이는 거리를 계산하여 glTranslate() 함수를 사용,  공이 Table 내에서 계속 움직이도록 프로그램 한것이다.  

 

우선 몇개의 전역변수를 정의 하였다.

 

 #define   angle   -30.0          // launching angle

 

// set window size & image size coordinates & image view mode
GLsizei   wwidth = 640, wheight = 320; // initial window width & height
GLfloat   ix1 = 0.0, ix2 =131.0,       // set size of table
          iy1 = 0.0, iy2 = 67.0,
          iz1 =-3.0, iz2 =  3.0;       // depends on radius of ball
GLfloat   radii = 3.0, dt = 3.0;       // radius of ball & table edge thickness
GLfloat   xtr = 20.0, ytr = 10.0;      // initial ball location
GLfloat   speed = 0.02, xdeg = angle, ydeg = angle; // initial ball speed & launching angle
GLfloat   red = 1.0, green = 0.0, blue = 0.0, alpha = 1.0;  // initial ball color

 

다음 display() 함수를 다음과 같이 수정한다.

 

             .

             .

     // clear all color & depth buffers
      glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT );


      drawTable();

 

      /*  Translate & rotate the image  */
      glPushMatrix();                   // Save the transformations performed
      glTranslatef( xtr, ytr, 0.0 );    // move ball to initial position

 

      /*  Draw circular ball  */
      glColor4f( red, green, blue, alpha );
      glBegin( GL_POLYGON);
            glVertex3f( 0.0, 0.0, 0.0 );
            for (int i = 0; i <= 360; i += 10) {
                  GLdouble  degree = (GLdouble)i * (PI/180.0);
                  glVertex3f( radii*cos(degree), radii*sin(degree), 0.0 );
            }
      glEnd();
      glPopMatrix();     // Restore the transformations

 

      sprintf( info, "x=%.1f, y=%.1f, launching angle=%.3f", xtr, ytr, angle );
      glutSetWindowTitle( info );

 

      glutSwapBuffers();
}

 

위에서 drawTable(); 함수의 내용을 지금 설명에는 조금 이른감이 있어 아래 Source Code 에 포함 되어있는것을  사용하기로 한다.  

 

다음 idle() 함수 또는 Timer() 함수를 다음과 같이 작성한다.

 

void  idle( void )
{
      GLfloat  xmin = ix1 + radii + dt, xmax = ix2 - radii - dt;
      GLfloat  ymin = iy1 + radii + dt, ymax = iy2 - radii - dt;


      if (xdeg > +360.0) xdeg -= 360.0;
      if (xdeg < -360.0) xdeg += 360.0;
      if (ydeg > +360.0) ydeg -= 360.0;
      if (ydeg < -360.0) ydeg += 360.0;

 

      xtr += speed * cos( xdeg * PI/180.0 );
      ytr += speed * sin( ydeg * PI/180.0 );

 

      if (ytr >= ymax)  ydeg = -ydeg;
      if (xtr >= xmax)  xdeg += 180.0;
      if (ytr <= ymin)  ydeg = -ydeg;
      if (xtr <= xmin)  xdeg += 180.0;

 

      glutPostRedisplay(); // tell GLUT that the display has changed
}

 

ball 의 table 을 향한 입사각과 반사각에 대한 계산이므로 조금만 깊이 살펴보면 원리를 이해할 수 있을것이다.

 

그외 reshape() keyboard() special() 함수를 약간 수정하여 컴파일 후 실행배보면 재미있는 결과를 볼것이다.
실행할 때 선택사항은 다음과 같다.

 

'>'  와  '<' key           -   공의 속도를 변화.

'arrow'  keys            -   공의 입사각의 변화

'r',  'g', 'b', 'w' key     -   공의 색상 변화

'F11' & 'F11'            -   Toggle fullsize window

 

 

 

 

 

 

 

Source Code:         01_4 - animation.zip         01_4 - moving_ball.zip

 

 

'OpenGL 활용 > 1장 - Basic' 카테고리의 다른 글

1장 6절 - Mouse Motion Event  (0) 2013.01.22
1장 5절 - Mouse Event  (0) 2013.01.22
1장 3절 - Keyboard Event  (0) 2013.01.20
1장 2절 - Resize OpenGL Window  (0) 2013.01.20
1장 1절 - Create a Simple OpenGL Window  (0) 2013.01.19
And

1장 3절 - Keyboard Event

|

Keyboard Event

 

 

 

OpenGL programming 에서의 Keyboard 로 Event 를 처리하기 위한 기능으로 2개의 callback 함수가 있다.  일반 Keyboard 를 처리하는 glKeyboardFunc() 와 특수 Keyboard 를 처리하는 glSpecialFunc() 이다.  함수의 syntax 를 보면...

 

void glutKeyboardFunc( void (*func)(unsigned char key, int x, int y) );
void glutSpecialFunc( void (*func)(int key, int x, int y) );

 

과 같다.

 

참고 Site:    glutKeyboardFunc()   http://www.opengl.org/resources/libraries/glut/spec3/node49.html

                   glutSpecialFunc()   http://www.opengl.org/resources/libraries/glut/spec3/node54.html

 

 

main() 함수에 위 2개의 callback 함수를 call 한 다음, 필요한 함수를 작성해 보자.

 

             .

             .
      // initialize rendering & register callbacks
      initRendering();
      glutDisplayFunc( display );
      glutReshapeFunc( reshape );

 

      glutKeyboardFunc( keyboard );

      glutSpecialFunc( special );

 

      glMainLoop();

      return 0;

}

 

keyboard() 함수:

 

void  keyboard( unsigned char key, int x, int y )
{
      int   mod;

 

      switch (key) {
         case 'r':
                  red = 1.0f; green = 0.0f; blue = 0.0f;
                  mod = glutGetModifiers();
                  if (mod && GLUT_ACTIVE_ALT) {
                        red = 0.5f;
                  }
                  break;

         case 'g':
                  red = 0.0f; green = 1.0f; blue = 0.0f;
                  mod = glutGetModifiers();
                  if (mod && GLUT_ACTIVE_ALT) {
                        green = 0.5f;
                  }
                  break;

         case 'b':
                  red = 0.0f; green = 0.0f; blue = 1.0f;
                  mod = glutGetModifiers();
                  if (mod && GLUT_ACTIVE_ALT) {
                        blue = 0.5f;
                  }
                  break;

         case 'y':
                  red = 1.0f; green = 1.0f; blue = 0.0f;
                  mod = glutGetModifiers();
                  if (mod && GLUT_ACTIVE_ALT) {
                        red = 0.5f; green = 0.5f;
                  }
                  break;

         case 'c':
                  red = 0.0f; green = 1.0f; blue = 1.0f;
                  mod = glutGetModifiers();
                  if (mod && GLUT_ACTIVE_ALT) {
                        green = 0.5f; blue = 0.5f;
                  }
                  break;

         case 'm':
                  red = 1.0f; green = 0.0f; blue = 1.0f;
                  mod = glutGetModifiers();
                  if (mod && GLUT_ACTIVE_ALT) {
                        red = 0.5f; blue = 0.5f;
                  }
                  break;

         case '+':
                  magfac += 0.02;
                  break;
         case '-':
                  magfac -= 0.02;
                  break;
         case 27:

                  exit(0);
                  break;

         default:
                  red = 1.0f; green = 1.0f; blue = 1.0f; alpha = 1.0f;
                  break;
      }

      glutPostRedisplay();
}

 

special() 함수:

 

void  special( int key, int x, int y )
{
      switch (key) {
         //  select image view mode when reshape the window
         case GLUT_KEY_F1: // both object shape & size is not changed
                  viewmode = 1; // Ortho view mode
                  break;

         case GLUT_KEY_F2: // both object shape & size is chaned
                  viewmode = 2; // Ortho view mode
                  break;

         case GLUT_KEY_F3: // object shape is not changed but object size is chaned
                  viewmode = 3; // Frustum view mode
                  break;
         case GLUT_KEY_F4: // object shape is not changed but object size is chaned
                  viewmode = 4; // Perspective view mode
                  break;


         //  spin key for image rotation
         case GLUT_KEY_UP:
                  xrot -= 2.0f;
                  if (xrot < -360.0f) xrot += 360.0f;
                  break;
         case GLUT_KEY_DOWN:
                  xrot += 2.0f;
                  if (xrot > +360.0f) xrot -= 360.0f;
                  break;
         case GLUT_KEY_LEFT:
                  yrot -= 2.0f;
                  if (yrot < -360.0f) yrot += 360.0f;
                  break;
         case GLUT_KEY_RIGHT:
                  yrot += 2.0f;
                  if (yrot > +360.0f) yrot -= 360.0f;
                  break;
         case GLUT_KEY_PAGE_DOWN:
                  zrot -= 2.0f;
                  if (zrot < -360.0f) zrot += 360.0f;
                  break;
         case GLUT_KEY_PAGE_UP:
                  zrot += 2.0f;
                  if (zrot > +360.0f) zrot -= 360.0f;
                  break;
         case GLUT_KEY_HOME:
                  xrot = yrot = zrot = 0.0f;
                  break;

         case '+':
                  magfac += 0.02;
                  break;
         case '-':
                  magfac -= 0.02;
                  break;

         case GLUT_KEY_F10:
                  glutFullScreen();
                  break;

         case GLUT_KEY_F9:
                  glutReshapeWindow( wwidth, wheight );
                  glutPositionWindow( 100, 100 );
                  break;

         default:
                  break;
      }

      glutPostRedisplay();
}

 

그리고 display() 함수를 다음과 같이 수정하고,  몇개의 전역변수를 더한다.

 

// global variables

GLfloat   xrot, yrot, zrot;
GLfloat   red=1.0, green=1.0, blue=1.0, alpha=1.0;

 

void  display( void )
{
      char  info[128];

 

      // clear all color & depth buffers
      glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

 

      /*  Translate & rotate the image  */
      glPushMatrix();
      glTranslatef( 1.0, 1.0, 0.0 );       // move rotation axis to triangle center
      glRotatef( xrot, 1.0f, 0.0f, 0.0f ); // rotate the image
      glRotatef( yrot, 0.0f, 1.0f, 0.0f );
      glRotatef( zrot, 0.0f, 0.0f, 1.0f );
      glTranslatef(-1.0, -1.0, 0.0 );      // restore axis origin


      /*  Draw triangle  */
      glColor4f( red, green, blue, alpha ); // color set as RGBA 
      glBegin( GL_TRIANGLES );
            glVertex3f( 0.0f, 0.0f, 0.0f );
            glVertex3f( 2.0f, 1.0f, 0.0f );
            glVertex3f( 1.0f, 2.0f, 0.0f );
      glEnd();
      glPopMatrix();     // restore the coord. matrix


      sprintf( info, "x=%.1f, y=%.1f, z=%.1f,  mag=%.2f", xrot, yrot, zrot, magfac );
      glutSetWindowTitle( info );

 

      glFlush();
}

 

함수 glPushMatrix() 는 이전 변환행렬을 저장하고  glPopMatrix() 는 Push 로 저장된 행렬값을 가져오는 역할을 한다.  따라서 glRotate*(), glTranslate*(), glScale*() 등의 함수의 기능을 활성화하기 위하여 앞뒤로 위의 두 함수를 지정해 놓는다.

 

컴파일 후 프로그램을 실행하고,  'g' key 를 누르고, PgUp key 로 삼각형을 회전시키면 다음과 같은 결과를 얻는다.  Window Title 창에 x, y, z 축에 대한 회전각이 나타난다.  이는 glutSetWindowTitle() 함수를 통해 실현된다.   위,아래, 좌,우 화살표로 여러 방향으로 회전을 시켜 이미지를 관찰할 수 있다.   또한 '+' 와 '-' key 를 사용하여 이미지의 크기를 확대하고 줄일 수 있다.   'Esc' key 를 누르면 프로그램이 종료된다.   위 프로그램에서 glRotate*(angle, x, y, z );  함수는 좌표계의 축에 따라 주어진 각만큼 이미지를 회전시키는 역할을 한다.

 

 

 

 

일반키와 특수키에 대한 내용은 쉽게 이해할 수 있다.  키 callback 함수에서 SHIFT, CTRL 또는 ALT 키를 동시에 눌러 Event 를 Handle 할 경우에는 glutGetModifiers() 함수와 함께 GLUT_ACTIVE_SHIFT, GLUT_ACTIVE_CTRL, GLUT_ACTIVE_ALT  mode 를 연계시켜 사용한다.

위의 프로그램에서 Alt + r, 또는 Alt + b 등을 Test 해 보면 삼각형의 색상변화를 볼 수 있다.  Special key 에서의 Ctrl+Alt+F7 과 같이 동시에 3개의 키를 사용할 때는 다음과 같이 표현한다.

 

          .

          .

      mod = glutGetModifiers();
      if (mod && (GLUT_ACTIVE_CTRL | GLUT_ACTIVE_ALT)) {

          .

          .

 

참고 Site: glutGetModifiers() http://www.opengl.org/resources/libraries/glut/spec3/node73.html

 

 

 

 

Advanced Keyboard 기능

 

화살표 같은 key 를 계속눌러 자동반복을 실행하면, 약간의 delay 현상이 일어난다.  이러한 자동반복의 문제점을 해결해주는 함수들을 살펴보자.

 

 int  glutSetRepeat( int repeatMode );

 

Parameters:

  • GLUT_KEY_REPEAT_OFF      -  자동반복 Mode 기능 비활성
  • GLUT_KEY_REPEAT_ON       -  자동반복 Mode 기능 활성
  • GLUT_KEY_REPEAT_DEFAUT   -  default 상태로 자동반복 Mode 를 Reset

 

위 함수는 전역기반으로 작용한다. 즉 Application 으로부터 하나가 아닌 모든 Window 의 반복기능에 영향을 준다.  따라서 이 함수를 자동 mode 의 비활성화로 사용할 때는 Application 을 끝내기 전 default 상태로 복원하는 것이 편리하다.

 

Key 반복이 일어날 때의 callback 받는것을 비활성화 시켜, 다른 Application 에 영향을 주지않고 안전하게 key 누름을 무시해야 할 때가 있다.  이러한 경우의 함수는

 

int  glutIgnoreKeyRepeat( int repeatMode );

 

Parameters:

  • repeatMode – 0 이면 자동반복 mode 활성, 0 이 아니면 자동반복 mode 비활성 

 

어느 경우,  key 반복이 일어날 때 callback 받는것을 멈출것이다.  만약 key 를 누르고 있는 동안에만 어떤 Action 이 실행되기를  원한다면,  그 key 가 누르기를 해지하는 때를 또한 알아야 한다.  GLUT 는 key 가 해지 되었을 때를 위한 두개의 register callback 기능을 제공한다.

 

void  glutKeyboardUpFunc( void (*func)(unsigned char key,int x,int y) );
void  glutSpecialUpFunc( void (*func)(int key,int x, int y) );

 

Parameters:

  • func – callback 함수 이름 

 

 

 

 

Source Code:         01_3 - keyboard.zip             01_3 - advanced_keyboard.zip

 

 

 

 

 

'OpenGL 활용 > 1장 - Basic' 카테고리의 다른 글

1장 6절 - Mouse Motion Event  (0) 2013.01.22
1장 5절 - Mouse Event  (0) 2013.01.22
1장 4절 - Animation by Idling  (0) 2013.01.21
1장 2절 - Resize OpenGL Window  (0) 2013.01.20
1장 1절 - Create a Simple OpenGL Window  (0) 2013.01.19
And

1장 2절 - Resize OpenGL Window

|

Resize OpenGL Window

 

 

 

OpenGL Window 에 그려진 이미지를 확대, 또는 축소를 해서 보기 위해, Mouse 로 Window 의 크기를 조정할 때, 원래의 모형에 따라 보여지는 형태가 어떻게 변하는지를 살펴보기로 하자.

 

지난 절에서 만든 삼각형이 그려진 Window 의 크기를 Mouse 로 조정해 보면, OpenGL Window 안에 있는 이미지의 형태가 뒤바뀜을 볼 수 있다.  새로운 모양의 삼각형을 좌표를 지난 절에서 그린것과는 다르게 잡아 그려보기로 하자.  display() 함수를 다음과 같이 수정하였다.

 

 void  display()
{
      // clear all color & depth buffers
      glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

 

      glColor4f( 1.0f, 1.0f, 0.0f, 1.0f );  // triangle color as RGBA
      glBegin( GL_TRIANGLES );
            glVertex3f( 0.0f, 0.0f, 0.0f );
            glVertex3f( 2.0f, 1.0f, 0.0f );
            glVertex3f( 1.0f, 2.0f, 0.0f );
      glEnd();

 

      glFlush();
}

 

삼각형의 각 꼭지점의 (x, y) 좌표에 대응하는 위치가 (0, 0), (2, 1), (1, 2) 로  원점에서 옮겨져 x-y 좌표의 제 1 4분면에 위치하였다.  실행결과 이미지가 다음과 같이 나타내진다.   OpenGL 은 default 로 이미지를 보는 영역을 이미지 크기의 창에서 원점을 중심으로 보기 때문이다.  즉 삼각형의 이미지 크기 영역은 가로 2, 세로 2의 크기로  꼭지점이 직교좌표계의  (0, 0), (2, 1), (1, 2)  에 위치하여 있지만,  이 이미지를 투시하여 보는 영역이 x 축에서 (-1,1),  y축에서 (-1,1) 의 범위이기 때문이다.

 

 

 

 

이 좌표계를 조금 옮기기 위해 display() 함수를 조금더 수정해 보자. 

 

 void  display( void )
{
      // clear all color & depth buffers
      glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

 

      glPushMatrix();
      glTranslatef( -1.0, -1.0, 0.0 );      // move coord. to -1.0 in x- & y-axis

 

      glColor4f( 1.0f, 1.0f, 0.0f, 1.0f );  // triangle color as RGBA
      glBegin( GL_TRIANGLES );
            glVertex3f( 0.0f, 0.0f, 0.0f );
            glVertex3f( 2.0f, 1.0f, 0.0f );
            glVertex3f( 1.0f, 2.0f, 0.0f );
      glEnd();
      glPopMatrix();

 

      glFlush();
}

 

함수 glPushMatrix() glPopMatrix() 사이에 glTranslatef( -1.0, -1.0, 0.0 )  를 집어 넣어 x-축과 y-축 방향으로 -1.0 만큼의 크기로 좌표를 옮겼다. 결과를 보면 삼각형의 이미지가 Window 중앙으로 옮겨짐을 볼 수 있다.  glTranslate*() 함수는 Image 의 좌표를 옮기는데 사용되는 함수이다.  * 에 들어가는 문자가 f  이면 함수내의 변수값을 float 로 사용한다는 의미이다 (i 일 경우는 int( 정수형)).   glPushMatrix()  glPopMatrix()  함수는 좌표계의 위치와 방향 행렬을 저장, 복원하기 위한 함수이다.   앞, 뒤의 두 함수를 지우고 실행을 해보면 어떤 결과가 나오는지 알 수 있을것이다.

 

 

 

 

그러나 여기에서도 Window 크기를 조절해보면 이미지의 형태가 변형되는 것을 볼 수 있다.  이 것을 해결하기 위해 새로운 glut callback 함수 glReshapeFunc() 가 필요하다.  다음의 program 을 살펴보자.

 

main() 함수에 다음의 새로운 Line 을 넣는다. 

 

          .

          .
      // initialize rendering & register callbacks
      initRendering();
      glutDisplayFunc( display );
      glutReshapeFunc( reshape );

 

      glMainLoop();

      return 0;

}

 

다음의 reshape() 함수를 작성하고 위의 첫번째 display() 함수와 함께 program 을 컴파일한 후 실행한다.

 

void  reshape( int w, int h )
{

      if (h == 0) h = 1;
      GLdouble  aspect = (GLdouble)w / (GLdouble)h;

 

      // Tell OpenGL how to convert from coordinates to pixel values   
      glViewport( 0, 0, w, h );
      glMatrixMode( GL_PROJECTION );     // Select the Projection Matrix
      glLoadIdentity();                  // Reset  the Projection Matrix

 

      if (w >= h) {
            glOrtho( 0.0*aspect, 2.0*aspect, 0.0, 2.0, -1.0, 1.0 );
         // gluOrtho2D( 0.0*aspect, 2.0*aspect, 0.0, 2.0 );
            glTranslatef( 1.0*aspect - 1.0, 0.0, 0.0 );
      } else {
            glOrtho( 0.0, 2.0, 0.0/aspect, 2.0/aspect, -1.0, 1.0 );
         // gluOrtho2D( 0.0, 2.0, 0.0/aspect, 2.0/aspect );
            glTranslatef( 0.0, 1.0/aspect - 1.0, 0.0 );
      }

 

      glMatrixMode( GL_MODELVIEW );  // Select the Modelview Matrix
      glLoadIdentity();              // Reset  the Modelview Matrix
} 

 

Window 크기를 조절해보면 이미지의 형태가 변형되지 않고 크기도 Window 는 크기와 함께 항상 Window 중앙에 위치 하면서 변해 가는 것을 볼수 있다.   또한 위 함수에서 glViewport( 0, 0, w, h ); 부분의 함 인자를 glViewport( 50, 50, 0.7*w, 0.7*h ); 로 수정하여 실행을 해보았을 때 어떤 결과가 나오는지 살펴보았으면 한다. Window 내의 이미지 크기가 작아짐을 볼 수 있다.  


 

다음은 2차원과 3차원의 이미지를 투시하여 보는 방법과 원근적인 시각으로 보는 방법을 정리한 reshape() 함수이다. 3개의 global variable (전역변수) 를 사용하여 이미지의 크기, Viewing Method 등을 선택하도록 구성되어 있다.   viewmode 와 magfac 값을 요구조건에 맞게 바꾸어 필요한 Viewing Mode 와 Window 내에서의 이미지 크기를 결정할 수 있다.

 

 // global variables
GLsizei   viewmode;      // view mode: Ortho View = 1 & 2, Frustum View = 3, Perspective View = 4 
GLdouble  magfac = 0.65; // image magnification factor

 

void  reshape( int w, int h )
{

      // set window size & image size coordinates & image view mode
      double  PI = 3.1415926535897932384626;
      GLsizei wwidth = 320, wheight = 320; // initial window width & height
      double  ix1 =  0.0,  ix2 = 2.0,      // image size coord.
              iy1 =  0.0,  iy2 = 2.0,
              iz1 = -1.0,  iz2 = 1.0;

 

      double  x1, x2, y1, y2, z1, z2;
      double  aspect, ww, hh, ixc, iyc, izc;
      double  theta, distance;

 

      // Calculate coordinates & object size
      ixc = 0.5 * (ix2 + ix1);  // x-coord. center point in image
      iyc = 0.5 * (iy2 + iy1);  // y-coord. center point in image
      izc = 0.5 * (iz2 + iz1);  // z-coord. center point in image

 

      x1 = (ix1 - (1.0-magfac)*ixc) / magfac;
      x2 = (ix2 - (1.0-magfac)*ixc) / magfac;
      y1 = (iy1 - (1.0-magfac)*iyc) / magfac;
      y2 = (iy2 - (1.0-magfac)*iyc) / magfac;
      z1 = (iz1 - (1.0-magfac)*izc) / magfac;
      z2 = (iz2 - (1.0-magfac)*izc) / magfac;

 

      ww = (GLdouble)w / (GLdouble)wwidth;
      hh = (GLdouble)h / (GLdouble)wheight;


     /*---------------------------------------------------------------!
      *  Set Image View Mode
      *---------------------------------------------------------------!
      */
      // Prevent a divide by zero, when window is too short
      if (h == 0) h = 1;
      aspect = (GLdouble)w / (GLdouble)h;

 

      // Tell OpenGL how to convert from coordinates to pixel values   
      glViewport( 0, 0, w, h );
     
      glMatrixMode( GL_PROJECTION );     // Select the Projection Matrix
      glLoadIdentity();                  // Reset  the Projection Matrix


      switch (viewmode)
      {
         case 1:  // Set range of the ortho view area
                  glOrtho( x1*ww, x2*ww,
                           y1*hh, y2*hh, z1, z2 );
               // gluOrtho2D( x1*ww, x2*ww, y1*hh, y2*hh );
                  glTranslatef( ixc*ww - ixc, iyc*hh - iyc, izc );
                  break;


         case 2:  // Set range of the ortho view area & magnify the image
                  if (w >= h) {
                  glOrtho( x1*aspect, x2*aspect,
                           y1*1.000f, y2*1.000f, iz1, iz2 );
               // gluOrtho2D( x1*aspect, x2*aspect, y1, y2 );
                  glTranslatef( ixc*aspect - ixc, iyc*1.000f - iyc, izc );
                  } else {
                  glOrtho( x1/1.000f, x2/1.000f,
                           y1/aspect, y2/aspect, z1, z2 );
               // gluOrtho2D( x1, x2, y1/aspect, y2/aspect );
                  glTranslatef( ixc/1.000f - ixc, iyc/aspect - iyc, izc );
                  }
                  break;


         case 3:  // Set range of the Frustum view area & magnify the image
                  if (w >= h) {
                  glFrustum( x1*aspect, x2*aspect,
                             y1*1.000f, y2*1.000f,
                             100.0*(double)w, 1000.0*(double)w );
                  gluLookAt( ixc - ixc*aspect, iyc - iyc*1.000f, 101.0*(double)w,
                             ixc - ixc*aspect, iyc - iyc*1.000f, 0.0f,
                             0.0, 1.0, 0.0 );
                  } else {
                  glFrustum( x1/1.000f, x2/1.000f,
                             y1/aspect, y2/aspect,
                             100.0*(double)w, 1000.0*(double)w );
                  gluLookAt( ixc - ixc/1.000f, iyc - iyc/aspect, 101.0*(double)w,
                             ixc - ixc/1.000f, iyc - iyc/aspect, 0.0f,
                             0.0, 1.0, 0.0 );
                  }
                  break;


         case 4:  // Set the camera perspective
                  distance = 100.0f * (double)w;
                  theta = 2.0f * atan2( abs(y2-y1)/2.0, distance ) / (PI/180.0f);
                  gluPerspective( theta,                // camera angle
                                  aspect,               // w-to-h ratio
                                  100.0*(double)w, 1000.0*(double)w );
                  gluLookAt( ixc, iyc, 101.0*(double)w,
                             ixc, iyc, 0.0f,
                             0.0, 1.0, 0.0 );
                  break;


         default:
                  gluOrtho2D( x1*ww, x2*ww,  y1*hh, y2*hh );
                  // move the coord. to the center of image
                  glTranslatef( ixc*ww - ixc, iyc*hh - iyc, izc );
                  break;
      }

 

      glMatrixMode( GL_MODELVIEW );
      glLoadIdentity();
}

 

각각의 viewmode 에 대한 함수들의 사용방법은 OpenGL Reference 를 통하여 찾을 수 있다.  다음은 행렬 및 투영 등,  Image Object 를 표현하는데 필요한 함수들에 대한 간단한 설명이다.

 

- 행렬 (Matrix)

 

        • glMatrixMode();          -   현재 행렬을 설정
        • glLoadIdentity();         -   현재 행렬을 단위행렬 (Identity Matrix) 로 설정
        • glLoadMatrix[f,d]();     -   지정된 행렬을 최상위 행렬 Stack 에 Loading
        • glMultiMatrix[f,d]();     -   현재 행렬과 지정된 행렬을 곱하기

 

- 투영 (Projection)

 

        • glOrtho();                   -   범위가 정해진 직교투영
        • gluOrtho2D();            -   Z 방향의 범위가 -1.0~1.0 인 직교투영
        • glLoadMatrix[f,d]();    -   비대칭 절두체 원근투영
        • gluPerspective();       -   원근투영

 

- 조망 (View)

 

        • glViewport();             -   Viewport 설정
        • gluLookAt();              -   카메라의 위치와 방향 설정

 

- 모델링 변환 (Modeling Transform)

 

        • glRotate[f,d]();           -   Image Object 의 회전 방향 설정
        • glTranslate[f,d]();       -   Imgae Object 의 좌표 위치 이동

        • glScale[f,d]();             -   Imgae Object 의 확대 및 축소 

 

 

참고 Site:

 

glMatrixMode();

glLoadIdentity();

glTranslate*();

glOrtho();

gluOrtho2D();

glFrustum();

gluPerpective();

gluLookAt();

http://www.opengl.org/sdk/docs/man2/xhtml/glMatrixMode.xml

http://www.khronos.org/opengles/sdk/1.1/docs/man/glLoadIdentity.xml

http://www.talisman.org/opengl-1.1/Reference/glTranslate.html

http://www.opengl.org/sdk/docs/man2/xhtml/glOrtho.xml

http://www.opengl.org/sdk/docs/man2/xhtml/gluOrtho2D.xml

http://www.opengl.org/sdk/docs/man2/xhtml/glFrustum.xml

http://www.opengl.org/sdk/docs/man2/xhtml/gluPerspective.xml

http://www.opengl.org/sdk/docs/man2/xhtml/gluLookAt.xml

 

 

 

 

 

Viewing Theory:

 

참고 Site:   http://fly.cc.fer.hr/~unreal/theredbook/chapter03.html

  

 

 

 

 

  

Source Code:         01_2 - reshape.zip

 

 

 

'OpenGL 활용 > 1장 - Basic' 카테고리의 다른 글

1장 6절 - Mouse Motion Event  (0) 2013.01.22
1장 5절 - Mouse Event  (0) 2013.01.22
1장 4절 - Animation by Idling  (0) 2013.01.21
1장 3절 - Keyboard Event  (0) 2013.01.20
1장 1절 - Create a Simple OpenGL Window  (0) 2013.01.19
And

1장 1절 - Create a Simple OpenGL Window

|

Create a Simple OpenGL Window

 

 

 

OpenGL Programming 을 하는 방법의 여러가지 중에서 GLUT (Graphic Library Utility Tools)을 이용하여 하는 기초적인 사항들을 알아보기로 하자. GLUT 은 graphic 처리에 대한 event handling 의 기본적인 callback 함수들을 제공하고 있는데, 대표적인것이

 

      • 도형을 화면에 표현하는 Display Event Handler
      • OpenGL 화면의 크기를 조정하는 Reshape Event Handler
      • Keyboard 의 일반 key 에 대한 Keyboard Event Handler
      • Keyboard 의 특수 key 에 대한 Special Event Handler
      • Mouse Button 에 대한 Mouse Event Handler
      • Mouse 움직임에 따른 Motion Event Handler
      • 화면에서 Object 의 움직임과 동작을 주는 Idle Event Handler
      • Menu 에 대한 Menu Event Handler

 

등이 있다.  이번 장에서는 이러한 사항에 대한 기초적인 부분을 알아보기로 한다.

 

    MS Windows 환경에서 OpenGL Programming 을 하는 방법에는 Console 모드를 사용하는 방법과 Win32 API 를 사용하는 두가지 방식이 있다. 여기에서는 간단히 두가지의 Programming 하는 방법을 비교해 보고 GLUT 기본적인 사용법을 알아 보기로 한다.

     

    OpenGL 의 처음 시작으로 간단한 OpenGL 창을 만들어 보기로 하자.

    OpenGL Programming 을 위한 Header File 은 다음을 준비해 두는게 일반적이다. 때에 따라 필요하지 않은 Header 도 있지만 컴파일된 파일 Size가 큰 문제가 되지 않는다면, 다음의 Header File 들은 일반적으로 붙여서 사용하는 것이 programming 하는데 편리하다.

     

    #include <stdio.h>
    #include <stdlib.h>

    #include <gl/glew.h>
    #include <gl/wglew.h>
    #include <gl/glut.h>

     

    위의 Header File 중 #include <gl/wglew.h> 부분은 생략해도 일반적으로 별 문제가 없다.

     

    다음은 GLUT 를 사용한 main 함수를 살펴보자.

     

    void showOpenGLInfo( void );
    void initRendering( void );
    void display( void );

     

    int   main( int argc, char *argv[] )
    {
          // init GLUT and create Window
          glutInit( &argc, argv ); // glut 의 초기화
          glutInitDisplayMode( GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH );
          glutInitWindowSize( 320, 320 ); // 초기 Window 크기
          glutInitWindowPosition( 100, 100 ); // 초기 Window 위치, 화면 왼쪽상단에서 가로,세로 100 pixel의 위치
          glutCreateWindow( "OpenGL: Open a Simple Window" ); // OpenGL Window Title
          showOpenGLInfo(); // Show general OpenGL Infomations.

     

          // initialize rendering & register callbacks
          initRendering();
          glutDisplayFunc( display );

     

          // enter GLUT event processing cycle
          glutMainLoop();

     

          return 0;
    }

     

    위에서 glutInitDisplayMode() 부분은 매우 중요한 부분으로 몇가지의 옵션이 있는데, 여기에 보여주는것은 Buffer 는 SINGLE Buffer, 색상은 RGB, 그리고 깊이 Buffer 를 사용하겠다는 의미이다. 초기 단순한 Window 를 만드는데는 GLUT_DEPTH 는 필요치 않으나 일반적으로 포함시켰다.

     

    다른 glut*() 함수들은 그 의미를 쉽게 이해할 수 있을것이다. showOpenGL(); 함수는 기본적인 OpenGL 정보를 보여주기 위한것이다. 꼭 필요한 부분이 아니므로 일반적으로 사용하지는 않는다. 이 함수는 아래에 첨부되었다.

    여기까지가 GLUT 을 사용하여 OpenGL Programming 을 하기위한 거의 필수 함수들이다.

     

    void  showOpenGLInfo( void )
    {
          if (glewInit() != GLEW_OK) {
                fprintf( stderr, "Error: %s\n", glewGetErrorString(glewInit()) );
                exit(0);
          }
          fprintf( stderr, "OpenGL Vender: %s\n", glGetString(GL_VENDOR) );
          fprintf( stderr, "OpenGL Version: %s\n", glGetString(GL_VERSION) );
          fprintf( stderr, "GLU Version: %s\n", gluGetString(GLU_VERSION) );
          fprintf( stderr, "GLEW Version: %s\n", glewGetString(GLEW_VERSION) );

     

          return;
    }

     

    다음의 initRendering(); 함수는 OpenGL programming 의 초기화에 필요한 부분들에 대한 함수들을 묶어놓은 함수이다.

     

    void  initRendering( void )
    {
          glClearColor( 0.0f, 0.0f, 0.0f, 0.0f ); // black background color
          glEnable( GL_DEPTH_TEST ); // Enable hidden--surface--removal
    }

     

    위에서 glClearColor( 0.0f, 0.0f, 0.0f, 0.0f ); 는 검은색 배경색을 나타낸다. 함수내의 숫자는 RGBA 의 크기를 나타내는데, 0에서 1 사이의 값을 가진다. 변수형태는 float 로 표현된다. glEnable( GL_DEPTH_TEST ); 는 현재는 별 의미가 없다. 다음에 3차원 도형을 다룰 때 설명이 따르게 될것이다.

     

    glutDisplayFunc( display ); 함수는 display() 함수에서 요구한 사항들을 OpenGL Window 에 나타내는 것이다. 다음의 display() 함수를 살펴보면

     

    void  display( void )
    {
          glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

          glFlush();
    }

     

    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); 는 색상 Buffer 와 깊이 Buffer 를 비우고, 마지막에 glFlush();
    함수를 통해 display() 명령들을 화면으로 내보낸다. 이러한 display() 함수의 모든 명령들을 받아 처리하는 glut callback 함수가 glutDisplayFunc(); 이다. 
    여기에서는 아무런 그림이나 도형도 그리지 않고 단지 OpenGL Window 만 열게 하였다.

     

    main() 함수의 마지막 glutMainLoop(); 함수는 위 모든 함수들을 최종적으로 정리, Looping 하여 나타낸다.  다음은 위에서 사용된 함수들에 대한 간단한 설명이다.

     

          • glClearColor();             -   화면 배경 색상 설정
          • glClear();                      -   화면과 Buffer 를 지움
          • glFlush();                      -   Buffer 의 내용을 화면에 뿌려줌
          • glGetString();               -   OpenGL 의 version, 확장목록등의 정보를 알려줌

     

     

    위 프로그램을 실행시키면, Command 창과 함께 OpenGL Window 창이 뜨게 된다. Win32API mode 로 프로그래밍을 하게 되면, Command 창은 뜨지 않게 된다. Win32API mode 에 대한 Programming 은 다음의 Site 에가면 매우 잘 설명이 되어있다. 영어해석에 별 무리가 없다면 다양한 좋은 정보들을 얻을 수 있을것이다.

     

    NeHe Production: http://nehe.gamedev.net/

     

    Win32API 로 구현된 Program 들은 매우 복잡하게 보이나, 단지 keyboard, mouse, 등의 Event Handler 에 대한 부분만이 glut 을 사용할 때와 조금 다르고 다른 부분에 별 차이가 없음을 알게 될것이다.

     

    간단히 Win32API Mode 로 위의 program을 변경하면 다음과 같이 몇 부분만 바꾸면 된다. main() 함수의 처음 부분을

     

    int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
                        LPSTR lpszCmdParam , int nCmdShow )
    {
          // init GLUT and create Window
          // glutInit( &argc, argv );
          // need both double buffering and z buffer
          glutInitDisplayMode( GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH );

              .

              .

              .

     

    그리고 showOpenGL(); 함수는 다음과 같이 변형시키면 된다. 이 부분에 대하여는 아주 쉽게 처리됨을 알 수 있을것이다.

     

    void  showOpenGLInfo( void )
    {
          TCHAR buffer[1024], errmsg[32];

     

          if (glewInit() != GLEW_OK) {
                sprintf( errmsg, "Error: %s\n", glewGetErrorString(glewInit()) );
                MessageBox( GetFocus(), errmsg, "OpenGL Error", MB_OK );
                exit(0);
          }
          sprintf( buffer, "OpenGL Vender: %s\n"

                           "OpenGL Version: %s\n"

                           "GLU Version: %s\n"

                           "GLEW Version: %s\n",

                            glGetString(GL_VENDOR ),
                            glGetString(GL_VERSION),
                            gluGetString(GLU_VERSION),

                            glewGetString(GLEW_VERSION) );
          MessageBox( GetFocus(), buffer, "OpenGL Info", MB_OK );

     

          return;
    }

     

    이상으로 이제 OpenGL 프로그래밍의 기본은 준비되었다. 기본적이 도형을 그리는 부분은 다음에 알아보겠지만 우선 간단한 노란색 2차원 삼각형 그림을 그리기 위해, 위의 display() 함수 내에 다음의 몇 줄을 더해보자.

     

    void  display( void )
    {
          glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

     

          glColor4f( 1.0, 1.0, 0.0, 1.0 ); // yellow color
          glBegin( GL_TRIANGLES );
                glVertex3f( -0.5,-0.5, 0.0 );
                glVertex3f( 0.5,-0.5, 0.0 );
                glVertex3f( 0.0, 0.5, 0.0 );
          glEnd();

     

          glFlush();
    }

     

    이 Program 을 컴파일 한 후 실행시키면 다음과 같은 검은 바탕에 노란 삼각형의 그림이 그려지는 것을 볼 수 있을것이다.

     

      

     

     

     

     

     

    GLUT 상태 정보 검색 함수

     

    다음의 함수

     

    int  glutGet( GLenum state ) 

     

    는 OpenGL 사용시 필요한 정보를 얻는데 자주 사용된다.  state 는 어떤 정보를 검색할 것인지에 대한 symbolic 상수 이다. 다음의  예는;

     

    width  = glutGet( GLUT_SCREEN_WIDTH );
    height = glutGet( GLUT_SCREEN_HEIGHT ); 

    now = glutGet( GLUT_ELAPSED_TIME );

     

    pixel 크기로 screen 의 가로와 세로에 대한 정보를 알려준다.  마지막의 예는 현재의 시간에 대한 정보를 알려주는 예이다.  OpenGL Window를 screen 의 한 가운데에 screen 크기의 절반의 크기로 위치하게 하기위하여는 main() 함수를 다음과 같이 수정하면 된다.

     

    int   main( int argc, char *argv[] )
    {
          // init GLUT and create Window
          glutInit( &argc, argv ); // glut 의 초기화
          glutInitDisplayMode( GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH ); 
          int width = glutGet( GLUT_SCREEN_WIDTH ) / 2;
          int height = glutGet( GLUT_SCREEN_HEIGHT ) / 2;

          glutInitWindowSize( width, height );   // 초기 Window 크기
          glutInitWindowPosition( width/2, height/2 ); // 초기 Window 위치,

          glutCreateWindow( "OpenGL: Open a Simple Window" ); // OpenGL Window Title
          showOpenGLInfo(); // Show general OpenGL Infomations.

             .

             .

          return 0;
    }

     

     

     

     

    Source Code:             01_1 - create_window.zip

     

     

     

    'OpenGL 활용 > 1장 - Basic' 카테고리의 다른 글

    1장 6절 - Mouse Motion Event  (0) 2013.01.22
    1장 5절 - Mouse Event  (0) 2013.01.22
    1장 4절 - Animation by Idling  (0) 2013.01.21
    1장 3절 - Keyboard Event  (0) 2013.01.20
    1장 2절 - Resize OpenGL Window  (0) 2013.01.20
    And
    prev | 1 | next