05. 3D 도형


소개



OpenGL창 설정, 폴리곤, 쿼드(사각형), 색상, 회전 등을 마스터한 지금 이제는 3D물체를 만들어볼 차례입니다. 저희는 폴리곤과 쿼드를 사용하여 물체들을 만들 것입니다. 이번에도 역시 저번 강좌의 코드를 조금 수정하여 삼각형을 다채로운 색상을 가진 풍부한 피라미드로 바꿔 놓고, 사각형을 육면체로 바꿀 것입니다. 피라미드는 혼합된 색상을 사용할 것이며, 육면체는 각면마다 다른 색상을 사용할 것입니다.

3D에서 물체를 만드는 데는 시간이 오래 걸릴 수도 있습니다. 그러나 그 결과는 그럴만한 가치가 있습니다. 상상력의 한계를 뛰어넘을 수 있으니까요!










본문


자, 지난 번 튜토리얼부터 시작해봅시다. 삼각형과 사각형은 2D지만 3D세계에 있었던 것 기억하시죠? 이제는 이 물체들을 "진정한" 3D물체로 만들어 봅시다. 자세히 말하면 좌우면과 뒤면을 삼각형에 추가하고, 좌우면 및 앞뒷면, 그리고 밑면을 사각형에 추가할 것입니다. 이렇게 하면 삼각형을 피라미드로 사각형을 육면체로 만들 수 있습니다.

저희는 피라미드에 있는 색상들을 혼합하여 부드럽게 색상이 변하는 물체를 만들 것이며, 육면체의 각 면은 다른 색을 가질 것입니다.


int DrawGLScene(GLvoid)                        // 모든 드로잉을 처리하는 부분
{
   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);    // 화면과 깊이버퍼를 비운다
   glLoadIdentity();                    // 뷰를 리셋한다
   glTranslatef(-1.5f,0.0f,-6.0f);                // 화면의 왼쪽 및 안쪽으로 이동

   glRotatef(rtri,0.0f,1.0f,0.0f);                // 피라미드를 Y축 주위로 회전시킴

   glBegin(GL_TRIANGLES);                    // 피라미드 그리기를 시작



몇몇 독자분들은 지난 강좌에서 코드를 가져와 스스로 3D 물체를 만드셨는지도 모르겠습니다. 제가 한동안 궁금해했던 것은 "왜 물체들이 자신만의 축 주위로 회전을 하지 못할까? 이건 마치 화면 전체를 회전시키는 것 같은걸?"이었습니다. 물체가 한 축 주위를 회전하게 만드려면 물체가 그 축을 '''감싸게''' 디자인해야 합니다.
물체의 중심이 X에서 0,Y에서 0,Z에서 0에 놓여져야 하는것을 여러분은 잊지 않으셨겟져!

다음의 코드는 중앙 축 주변에 피라미드를 만들 것입니다. 피라미드의 윗쪽은 중앙으로부터 위쪽의 점이고, 파리미드의 밑면은 중앙으로부터 아래쪽에 있는 점입니다. 위쪽 꼭지점은 정중앙(0)에 위치해 있으며 아래쪽에 있는 점들은 중앙으로부터 왼쪽과 오른쪽에 위치합니다.

저희는 모든 삼각형을 반시계방향으로 그렸습니다. 이는 매우 중요합니다. 자세한 내용은 다른 강좌에서 설명 드리겠습니다. 지금 당장은 물체를 시계방향이나 반시계방향으로 만드는 것이 좋은 습관이라고만 기억해 둡시다. 하지만 특별한 이유가 있지 않는한 두가지 방향을 섞어서 사용하면 안됩니다.

자, 이제 그리기를 시작해봅시다. 저희는 앞면부터 그립니다. 모든 면들이 윗점을 공유하기 때문에 모든 삼각형에서 이 점을 빨강색으로 만들 것입니다. 삼각형의 아래에 있는 두점은 다르게 놓습니다. 앞면은 왼쪽에 녹색, 오른쪽에 파랑색 점으로 하고, 오른쪽면은 왼쪽에 파랑색, 오른쪽에 녹색 점으로 놓습니다. 이렇게 각 면에서 두 아랫점들을 변경함으로써 각 면의 밑점들이 같은 색을 가지게 됩니다.

 
       glColor3f(1.0f,0.0f,0.0f);            // 빨강
       glVertex3f( 0.0f, 1.0f, 0.0f);            // 윗점 (앞면)
       glColor3f(0.0f,1.0f,0.0f);            // 녹색
       glVertex3f(-1.0f,-1.0f, 1.0f);            // 왼쪽점 (앞면)
       glColor3f(0.0f,0.0f,1.0f);            // 파랑
       glVertex3f( 1.0f,-1.0f, 1.0f);            // 오른쪽 점 (앞면)


이제 오른쪽 면을 그려봅시다. 아래쪽 두점이 중앙의 오른쪽에 그려지며 윗점은 x축 중앙, Y축 바로 위 1.0단위에 그려진다는 사실에 주목하십시오. 즉,이 면은 윗부분에서 중심에서부터 아래쪽에서 화면의 오른쪽 아래로 경사면이 됩니다.

이번에는 왼쪽점을 파란 색으로 합니다. 파란 색으로 그리면 앞면의 오른쪽 코너부분에서 같은 색이 되어
한 코너 에서부터 피라미드의 앞면과 오른쪽 면을 향해 파란색이 혼합되어 퍼지게 됩니다.

다른 세 면들이 처음 면과 동일한 glBegin(GL_TRIANGLES)와 glEnd() 사이에 있다는 것에 주목해주십시오. 지금 그리는 모든 물체는 삼각형이기 떄문에 OpenGL이 우리가 찍는 매 세점들이 삼각형의 세 점이라는 것을 알고 있습니다. 일단 세점을 그렸는데 그 뒤에 다른 세점이 따라온다면 OpenGL은 삼각형 하나를 더 그려야 한다고 생각합니다. 세점이 아닌 네 점을 집어넣으면 OpenGL은 처음 세점으로 삼각형 하나를 그린 뒤, 4번째 점이 새 삼각형의 시작이라고 생각할 것입니다. 즉, 이 경우 OpenGL은 사각형을 그리지 않습니다. 따라서 실수로 불필요한 점들을 추가하지 않도록 주의해 주십시오.

 
       glColor3f(1.0f,0.0f,0.0f);            // 빨강
       glVertex3f( 0.0f, 1.0f, 0.0f);            // 윗점 (오른쪽 면)
       glColor3f(0.0f,0.0f,1.0f);            // 파랑
       glVertex3f( 1.0f,-1.0f, 1.0f);            // 왼쪽점 (오른쪽 면)
       glColor3f(0.0f,1.0f,0.0f);            // 녹색
       glVertex3f( 1.0f,-1.0f, -1.0f);            // 오른쪽점 (오른쪽 면)


이제 뒷면 차례입니다. 다시한번 색상을 바꿉니다. 왼쪽면은 이제 다시 녹색입니다. 왜냐하면 오른쪽 면과 공유하는 코너가 녹색이기 때문입니다.

 
       glColor3f(1.0f,0.0f,0.0f);            // 빨강
       glVertex3f( 0.0f, 1.0f, 0.0f);            // 윗점 (뒷면)
       glColor3f(0.0f,1.0f,0.0f);            // 녹색
       glVertex3f( 1.0f,-1.0f, -1.0f);            // 왼쪽점 (뒷면)
       glColor3f(0.0f,0.0f,1.0f);            // 파랑
       glVertex3f(-1.0f,-1.0f, -1.0f);            // 오른쪽점 (뒷면)


마지막으로 왼쪽 면을 그립니다. 마지막으로 한번 더 색상을 바꿉니다. 왼쪽 점은 파랑색이고 뒷면의 오른쪽 점과 혼합됩니다. 오른쪽 점은 녹색이며 앞면의 왼쪽점과 혼합됩니다.

이제 피라미드 그리기를 마쳤습니다. 피라미드는 오직 Y축 주변으로만 회전하기 때문에 밑면을 볼 일이 없습니다. 그래서 피라미드의 밑면을 넣을 필요조차 없습니다. 한번 시도해보고 싶은 독자분들은 사각형(쿼드)를 사용하여 밑면을 추가한후에, X축 회전을 넣으신후에 제대로 작동하는지 살펴보십시요. 이때 사각형의 각 모서리에 사용하는 색상이 피라미드의 네 면에서 사용한 색상과 일치하는지도 확인해주세여.
 
       glColor3f(1.0f,0.0f,0.0f);            // 빨강
       glVertex3f( 0.0f, 1.0f, 0.0f);            // 윗점 (왼쪽면)
       glColor3f(0.0f,0.0f,1.0f);            // 파랑
       glVertex3f(-1.0f,-1.0f,-1.0f);            // 왼쪽점 (왼쪽면)
       glColor3f(0.0f,1.0f,0.0f);            // 녹색
       glVertex3f(-1.0f,-1.0f, 1.0f);            // 오른쪽점(왼쪽면)
   glEnd();                        // 피라미드 그리기를 마침
  
이제 육면체를 그릴 것입니다. 이것은 6개의 사각형으로 구성됩니다. 모든 쿼드들은 반시계방향으로 그려집니다. 즉, 첫번째 점은 우상점, 두번째 점은 좌상점, 세번째 점은 좌하점, 그리고 마지막 점은 우하점입니다. 뒷면을 그리는 방법이 시계방향처럼 보일 수도 있습니다. 하지만 육면체의 뒤쪽에서 이것을 바라본다면 화면의 왼쪽이 실제는 사각형의 오른쪽이고, 화면의 오른쪽이 실제는 사각형의 왼쪽이라는 사실을 기억합시다.

이 강좌에서는 사각형을 좀더 화면 안쪽으로 이동시킵니다. 이렇게 하면 육면체의 크기가 피라미드의 크기와 비슷해 보일 것입니다. 만약 육면체를 6단위 만큼만 화면 안쪽으로 이동시킨다면 이것이 피라미드보다 훨씬 커보이며 일부분이 화면 밖으로 삐져나갈 것입니다. 이 설정을 자유롭게 변경하면서 화면 깊이에 따른 육면체의 크기를 직접 확인해보시는 것도 좋은 방법일 것입니다. 이런 일이 생기는 이유는 원근감(Perspective) 모드이기 때문입니다. 멀리 있는 물체는 당연히 작게 보이는 게 정상이죠.  ^^ 

 
   glLoadIdentity();
   glTranslatef(1.5f,0.0f,-7.0f);                // 오른쪽과 화면 안쪽으로 이동

   glRotatef(rquad,1.0f,1.0f,1.0f);              // X, Y, Z상에서 육면체를 회전

   glBegin(GL_QUADS);                            // 육면체를 그리기 시작함


자, 그럼 육면체의 윗면부터 그려봅시다. 육면체의 중앙에서 1단위 만큼 위로 이동합니다. Y축은 언제나 1인 것 보이시죠? 이제 우리는 Z평면 상에(즉 화면 안쪽에) 사각형 하나를 그립니다. 육면체 윗면의 우상점을 그리는 것이 시작입니다. 우상점은 오른쪽으로 1단위 화면안쪽으로 1단위에 위치할 것입니다. 두번째 점은 왼쪽으로 1단위 화면안쪽으로 1단위에 위치합니다. 이제 사각형의 밑점들을 관찰자 쪽을 향하게 그릴 차례입니다. 화면안쪽으로 들어가는 대신 화면 쪽으로 1단위 만큼 이동시켜주면 됩니다. 간단하죠?


       glColor3f(0.0f,1.0f,0.0f);            // 색상을 녹색으로 지정
       glVertex3f( 1.0f, 1.0f,-1.0f);            // 우상점 (윗면)
       glVertex3f(-1.0f, 1.0f,-1.0f);            // 좌상점 (윗면)
       glVertex3f(-1.0f, 1.0f, 1.0f);            // 좌하점 (윗면)
       glVertex3f( 1.0f, 1.0f, 1.0f);            // 우하점 (윗면)

 
밑면을 그리는 방법은 육면체의 중앙에서 아래로 1단위에 그리는 것만 빼면 윗면을 그리는 것과 완전히 동일합니다. Y축이 언제나 -1이라는 것 보이시죠? 아래쪽에서 육면체의 밑면을 바라보면 오른쪽 위의 코너가 관찰자에게 가장 가까운 코너일 것입니다. 따라서 멀리 있는 점을 먼저 그리는 대신에 관찰자에게 가까운 점부터 먼저 그려봅시다. 그 다음은 관찰자에게 가까운 왼쪽점을 그린 뒤 화면 안쪽으로 들어가 두 밑점을 그립니다.

폴리곤을 그리는 순서(반시계 또는 시계방향)가 상관없다면 윗면 사각형의 코드를 그대로 가져다 붙인 뒤 Y축을 -1로 변경해도 상관이 없을 것입니다. 그러나 사각형을 그리는 순서를 무시하면 텍스처 매핑같은 효과를 사용할 때 아주 이상한 결과를 보게 될것입니다.


       glColor3f(1.0f,0.5f,0.0f);            // 색상을 오렌지로 지정
       glVertex3f( 1.0f,-1.0f, 1.0f);            // 우상점 (밑면)
       glVertex3f(-1.0f,-1.0f, 1.0f);            // 좌상점 (밑면)
       glVertex3f(-1.0f,-1.0f,-1.0f);            // 좌하점 (밑면)
       glVertex3f( 1.0f,-1.0f,-1.0f);            // 우하점 (밑면)


이제 육면체의 앞면을 그릴 차례입니다. 화면쪽으로 1단위 중앙으로부터 1단위 떨어진 곳에 앞면을 그립니다. Z축은 언제나 1입니다. 피라미드에서는 Z축이 언제나 1이지는 않았습니다. 윗점의 Z축은 0이었습니다. 아래 코드에서 Z축을 0으로 변경하면 여러분이 변경하신 코너가 화면쪽으로 경사를 이룰 것입니다. 하지만 이것이 지금 우리가 원하는 것은 아니죠? ^^

 
       glColor3f(1.0f,0.0f,0.0f);            // 색상을 빨강으로 지정
       glVertex3f( 1.0f, 1.0f, 1.0f);            // 우상점 (앞면)
       glVertex3f(-1.0f, 1.0f, 1.0f);            // 좌상점 (앞면)
       glVertex3f(-1.0f,-1.0f, 1.0f);            // 좌하점 (앞면)
       glVertex3f( 1.0f,-1.0f, 1.0f);            // 우하점 (앞면)

뒷면은 화면속으로 좀더 깊이 들어간 것만 제외하면 앞면과 동일한 사각형입니다. 모든 점의 Z좌표가 음수 값이라는 것 보이시죠?

       glColor3f(1.0f,1.0f,0.0f);            // 색상을 노랑으로 지정
       glVertex3f( 1.0f,-1.0f,-1.0f);            // 좌하점 (뒷면)
       glVertex3f(-1.0f,-1.0f,-1.0f);            // 우하점 (뒷면)
       glVertex3f(-1.0f, 1.0f,-1.0f);            // 우상점 (뒷면)
       glVertex3f( 1.0f, 1.0f,-1.0f);            // 좌상점 (뒷면)

이제 2개의 사각형만 더 그리면 끝입니다. 보통과 마찬가지로 한 축의 값이 모든 네 점에서 동일하단 것을 보실 수 있습니다. 이 경우에는 X축이 언제나 -1입니다. 지금 그리는 것이 왼쪽 면이기 때문에 중앙에서 왼쪽방향에 점들을 그리기 때문이죠.

 
       glColor3f(0.0f,0.0f,1.0f);            // 색상을 파랑으로 지정
       glVertex3f(-1.0f, 1.0f, 1.0f);            // 우상점 (왼쪽면)
       glVertex3f(-1.0f, 1.0f,-1.0f);            // 좌상점 (왼쪽면)
       glVertex3f(-1.0f,-1.0f,-1.0f);            // 좌하점 (왼쪽면)
       glVertex3f(-1.0f,-1.0f, 1.0f);            // 우하점 (왼쪽면)

자, 드디어 육면체를 마무리하는 마지막 면입니다. X축은 언제나 1이고 반시계방향으로 그립니다. 뭐 필요에 따라서는 이 면을 그리지 말고, 상자로 만들어버려도 됩니다. ^^;

아니면 왠지 모험을 해보고 싶으신 분들은 육면체에 있는 각 점의 색상을 변경하여 피라미드에서 한 것과 마찬가지 방법으로 혼합을 시도해봐도 됩니다. 제 웹페이지에서 Evil's first GL demo를 다운받으시면 색상혼합을 사용하는 육면체의 예를 보실 수 있습니다. 이것을 실행하고 TAB키를 눌러보십시오. 색상이 모든 면으로 퍼져나가는 아릅답게 채색된 육면체를 보실 수 있을 것입니다.

       glColor3f(1.0f,0.0f,1.0f);            // 색상을 보라색으로 지정
       glVertex3f( 1.0f, 1.0f,-1.0f);            // 우상점 (오른면)
       glVertex3f( 1.0f, 1.0f, 1.0f);            // 좌상점 (오른면)
       glVertex3f( 1.0f,-1.0f, 1.0f);            // 좌하점 (오른면)
       glVertex3f( 1.0f,-1.0f,-1.0f);            // 우하점 (오른면)
   glEnd();                        // 쿼드 그리기를 마침

   rtri+=0.2f;                        // 삼각형의 회전 변수를 증가
   rquad-=0.15f;                        // 사각형의 회전값을 감소
   return TRUE;                        // 계속 진행
}


자, 이 강좌도 이렇게 끝났습니다. 이 강좌를 꼼꼼히 읽으신 독자분들은 3D공간에서 물체를 만드는 법을 보다 잘 이해하시게 되었을 것입니다. OpenGL 화면을 무지하게 큰 모눈종이라고 생각해보십시오. 물론 그 뒤에 여러 곂의 투명한 레이어들이 존재한다고 보면 더욱 좋을 것입니다. 즉, 수많은 점들로 구성된 거대한 육면체란 말이지요. 어떤 점들은 좌우로, 어떤 점들은 상하로 움직일 것이며 어떤 점들은 육면체의 앞뒤로 이동할 것입니다. 화면안쪽의 깊이를 머리속에서 그려볼 수 있다면 새로운 3D물체를 설계하는 데 아무 문제점이 없을 것입니다.

설사 3D 공간을 이해하기 힘드신 분들이 계시더라도 크게 걱정하지 마십시요. 곧바로 이 개념을 이해하기가 어려울 수도 있습니다. 육면체와 같은 물체는 학습하기에 좋은 예입니다. 화면 안쪽으로 좀더 깊이 이동하는 것만 빼면 뒷면이 앞면과 동일하기 때문이죠. 이 코드를 이리저리 가지고 놀아보심시오. 만약 그래도 이해가 안되신다면 저에게 이메일을 보내주세요. 여러분의 질문에 성심성의껏 답변을 드리겠습니다.

소스코드 다운로드

이 강좌의 소스코드를 다운받으실 수 있습니다. 자신의 환경에 맞는 파일을 받아 사용하세요.







원문 정보

  • 저자: Jeff Molofee (NeHe)
  • 원문보기: Lesson 05

번역문 정보

  • 초벌번역: 포프
  • 재벌번역: 이스
  • 감수: 이스

현재 상태

  • 초벌번역시작 (2005년 8월 19일)
  • 초벌번역완료 (2005년 8월 20일)
  • 재벌번역시작 (2005년 8월 22일)
  • 재벌번역 및 감수 완료 (2005년 8월 23일)

Comments