OpenGL 활용/1장 - Basic

1장 2절 - Resize OpenGL Window

BeH 2013. 1. 20. 02:36

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