Quadrics가 무엇인지 부터 알아야 하겠다. Quadrics은 공간상에 기하학적인 모양을 생성하는 것이다. 여기서 말하는 기하학적 모양이란 원뿔, 원통, 원판, 구 등을 말한다. 즉 Quadrics를 사용하여 쉽고 간단하게 위에서 언급한 물체를 생성할 수 있다. 그렇다면 이제 Quadrics를 사용하여 물체를 만들고 시연해보자 !!
먼저 Quadrics를 이용하여 물체를 만들기 전에 Quadrics를 생성하여야 한다. Quadrics는 속성을 가지고 있는데, 그 속성이란 그리고자 하는 것, 그리고자 하는 것의 위치(원점)과 값(반지름 등등), 광원 모드, 텍스쳐 모드, 그리고 그리는 도중에 에러가 발생할 경우 호출할 CallBack 함수들을 말한다. Quadrics를 생성하는 방법은 쉽다. 제공되는 Factory(생성) 함수가 있으니 말이다.
GLUquadricObj *obj; obj = gluNewQuadric();
생성은 위의 코드가 전부이다. 간단하다. 나중에 생성된 Quadric객체의 인스턴스 변수인 obj를 이용하여 물체를 그리는데 사용되는 함수는 gluCylinder, gluDisk, gluSphere가 있고 미래에 더 추가될 것이다. 이 함수들은 첫번째 인자로 Quadric 객체를 요구하고 각 함수에 따라 실린더 모양을 그릴것인지 디스크 모양을 그릴것인지 구 모양을 그릴 것인지를 지정하는 것이다. 그렇다면 정작 그릴 물체에 대한 속성은 어떻게 설정하는 것인가? 예를 들어서 물체를 Wire Frame 형태로 그릴것인지 Solid 형태로 그릴것인지의 결정은 어떻게 하는가? 또한 Solid 형태로 그린다면 물체의 면을 Flat형태로 그릴것인지 Smooth하게 그릴것인지의 결정은 어떻게 하는가? 법선벡터의 방향을 바깓쪽으로 할것인지 안쪽으로 할것인지의 결정은 어떻게 하는가? 그리고 나중에 Quadric로 생성한 객체에 대해 텍스쳐 맵핑을 할경우 텍스쳐 맵 좌표를 자동으로 생성시키게 할것인가 아니면 않할것인가의 지정은 어떻게 하는가? 이 많은 질문에 대한 답은 아래와 같다.
일단 Quadric 객체가 생성되면 다음의 함수를 통해서 그 속성을 설정할수있다.
1. void gluQuadricDrawStyle(GLUquadricObj *obj, GLenum drawStyle)
이 함수의 첫번째인자는 속성을 설정할 Quadric에 대한 인스턴스 변수에 대한 포인터가 오며 두번째 변수에 올수있는 값은 GLU_FILL, GLU_LINE, GLU_SILHOUETTE, GLU_POINT가 온다. Wire Frame 형태를 원한다면 GLU_LINE가 필요하고 Soild 형태를 원한다면 GUL_FILL이 그리고 단지 점만으로 그리기를 원한다면 GLU_POINT가 온다. GLU_SILHOUETTE는 선으로 외부 모서리만을 그리게 된다.
2. void gluQuadricNormals(GLUquadricObj *obj, GLenum normals)
위의 함수는 법선벡터를 제어하는데 사용되는데 법선 벡터에의해서 빛에 대한 영향이 결정된다는 것은 지난 “빛”에 대한 장에서 충분히 설명했다. 이 함수의 첫번째 인자는 역시 Quadric의 인스턴스 변수에 대한 포인터를 갖고 두번째 인자에 올수있는 인자의 값에는 GLU_NONE, GLU_FLAT, GLU_SMOOTH가 온다. GLU_NONE는 법선벡터를 생성하지 않는데 이렇게 되면 빛에 대해서 아무런 효과를 얻을 수 없다. GLU_FLAT는 면이 깍인것처럼 보이도록 법선벡터를 생성하고 GL_SMOOTH는 면이 부드럽게 보이도록 즉, 물체의 모서리를 부드럽게 보이게 법선 벡터를 생성한다.
3. void gluQuadricOrientation(GLUquadricObj *obj, GLenum orientation)
이 함수는 법선벡터의 방향을 지정하기 위해 사용된다. 첫번째 인자는 Quadric의 인스턴스 변수에 대한 포인터를 갖고 두번째 인자가 갖을 수 있는 값에는 GLU_OUTSIDE와 GLU_INSIDE가 온다. GLU_OUTSIDE는 법선벡터를 물체에 대해서 바깓쪽으로 법선벡터의 방향을 지정하고 GLU_INSIDE는 법선벡터를 물체에 대해서 안쪽으로 방향을 지정하도록 생성한다.
4. void gluQuadricTexture(GLUquadricObj *obj, GLboolean textureCoords)
이 함수는 텍스쳐 맵핑 좌표를 생성할 것인지 않할 것인지를 지정하는 것이다. 첫번째 인자는 Quadric의 인스턴스 변수에 대한 포인터를 갖고 두번째 인자가 갖을 수 있는 값에는 GL_TRUE와 GL_FALSE이다. GL_TRUE로 할경우 텍스쳐 맵핑 좌표를 생성하며 GL_FALSE는 텍스쳐 맵핑 좌표를 생성하지 않는다.
자 이렇게 해서 Quadric에 대한 속성을 설정하는 함수에 대한 소개를 마치고 이제 본격적으로 우리가 필요로하는 물체를 그려보는 것에 대해서 알아보자!!
사용할 기본 소스는 1장의 소스에서 시작한다.
먼저 Quadric 객체를 생성하기 위한 변수를 하나 선언하자. 코드 전체에서 이 변수를 참조하므로 전역 변수를 선언하는 곳에 선언한다.
GLUquadricObj *obj;
이제 Quadric를 생성해야 한다. OpenGL을 초기화 시키는 부분인 InitGL 함수부에서 끝부분쯤에 다음의 코드를 추가한다.
obj = gluNewQuadric(); // <1> gluQuadricDrawStyle(obj, GLU_FILL); // <2> gluQuadricNormals(obj, GLU_SMOOTH); // <3> gluQuadricOrientation(obj, GLU_OUTSIDE); // <4> gluQuadricTexture(obj, GL_FALSE); // <5> glEnable(GL_LIGHTING); // <6> glEnable(GL_LIGHT0); // <7> glEnable(GL_COLOR_MATERIAL); // <8>
<1>번 코드는 실제적으로 Quadric 객체를 생성시키는 코드이다.
<2>번 코드는 Solid 형태로 물체를 그린다는 것이고 <3>번은 면에 대해서 부드럽게 그린다는 것이고 <4>번은 법선벡터의 방향을 물체에 대해서 바깓쪽으로 향하도록 법선벡터를 생성하라는 의미이다. <5>번은 텍스쳐 맵을 적용하지 않을 것으므로 텍스쳐 맵핑 좌표를 생성하지 말라는 의미이다.
<5>~<8>번은 빛을 활성화시키고 칼라 추적 기능을 이용해서 물체의 재질을 설정하라고 지시한다. 참고로 LIGHT0는 별도로 설정하지 않아도 기본적으로 그래픽 카드에서 값이 설정되어 있는 빛이다. 필자의 그래픽 카드(G400)에서는 휼룡하게 작동했다.
자! 이렇게 해서 Quadric 객체를 생성했고 그 속성을 설정했으며 나머지 빛과 재질에 대한 설정 또한 끝냈다.
그렇다면 무언가를 생성했으니 나중에 필요치 않으면 메모리에서 제거해야 하는 것은 프로그래머에 대한 불문율이다. Quadric 객체를 제거하는 방법은 무언인가? 실제적으로 제거하는 코드의 위치는 WinMain 함수의 끝부분쯤에 위치한다. 아래와 같다.
. . . gluDeleteQuadric(obj); // 추가 코드 // Shutdown KillGLWindow(); // Kill The Window return (msg.wParam); // Exit The Program }
이제 실제적으로 Quadirc객체를 이용하여 물체를 그리는 작업만 남았다. 그리는 작업은 DrawGLScene 함수에 위치한다. 다음은 그 함수에 대한 코드 전체이다.
int DrawGLScene(GLvoid) { static GLfloat rot = 0.0f; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); glTranslatef(0.0f, 0.0f, -15.0f); glPushMatrix(); glTranslatef(-5.0f, 0.0f, 0.0f); glRotatef(rot, 1.0f, 1.0f, 1.0f); glTranslatef(0.0f, 0.0f, -2.0f); glColor3f(0.6f, 0.6f, 1.0f); gluCylinder(obj, 1.0f, 1.0f, 4.0f, 16, 4); //<1> glPopMatrix(); glPushMatrix(); glTranslatef(0.0f, 0.0f, 0.0f); glRotatef(rot, 1.0f, 1.0f, 1.0f); glColor3f(0.6f, 0.6f, 1.0f); glColor3f(1.0f, 0.6f, 0.6f); gluDisk(obj, 0.2f, 1.6f, 16, 4); //<2> glPopMatrix(); glPushMatrix(); glTranslatef(5.0f, 0.0f, 0.0f); glRotatef(rot, 1.0f, 1.0f, 1.0f); glColor3f(0.6f, 0.6f, 1.0f); glColor3f(0.6f, 1.0f, 0.6f); gluSphere(obj, 1.5f, 24, 24); //<3> glPopMatrix(); rot += 1.0f; if(rot > 359.0f) rot = 1.0f; return TRUE; }
새롭게 추가된 코드는 노란색으로 나타냈다. 실제 중요한 Quadric 객체를 그리는 코드에 대해서만 설명하도록 한다. 나머지 부분은 지난장에서 이미 다루었던 내용이므로 해당 장들을 참고하기 바란다.
<1>번 코드에서는 gluCylinder 함수를 사용했는데 첫번째 인자는 Quadric의 인스턴스 변수에 대한 포인터가 온다. 두번째 인자는 실린더의 밑부분의 반지름 크기이고 세번째는 실린더의 윗부분의 반지름 크기이다. 네번째는 실린더의 길이를 지정하는 것이고 다섯번째는 Slice의 수를 여섯번째는 Stack의 수를 나타낸다. Slice를 높일수록 실린더의 모양이 보다 부드러워진다. WireFrame 모드로 설정해서 그려본다면 분명하게 그 내용을 파악할수있다. 실린더의 윗부분과 아랫부분은 뚫려있다.
<2>번 코드는 gluDisk를 사용하는데 첫번째 인자는 Quadric의 인스턴스 변수에 대한 포인터가 온다. 두번째는 디스크의 안쪽 뚤린 원에 대한 반지름이고 세번째는 디스크의 바깓쪽에 대한 반지름이다. 네번째는 Slice의 갯수이고 다섯번째는 loop의 갯수이다.
<3>번 코드는 gluSphere인데 첫번째 인자는 Quadric의 인스턴스 변수에 대한 포인터가 온다. 두번째는 구의 반지름값이고 세번째는 slice의 갯수이고 네번째는 stacks의 갯수가 온다.
자, 이제 실행하는 것만 남았다. 아래는 그 실행 결과이다