출처: http://soen.kr/lecture/library/opengl/opengl-6.htm

15. 3차원 좌표

OpenGL의 3차원 공간은 다음과 같은 좌표계로 정의되어 있다.

x 축은 오른쪽으로 증가하고 y축은 위쪽으로 증가하며 z축은 사용자 반대쪽으로 증가한다. 클리핑 영역, 즉 좌표의 범위는 x, y, z 모두 -1 ~ 1 사이이다. 원점은 (0, 0, 0)이고 사용자 가까운 쪽의 왼쪽 아래는 (-1, -1, -1)이고 사용자와 먼쪽의 오른쪽 위는 (1, 1, 1)이다.

다음 예제는 3차원 공간안에 피라미드를 그린다.

#include <windows.h>
#include <gl/glut.h>
#include <stdio.h>

void DoDisplay();
void DoKeyboard(unsigned char key, int x, int y);
void DoMenu(int value);

GLfloat xAngle, yAngle, zAngle;
GLboolean bDepthTest = GL_TRUE;
GLboolean bCullFace = GL_FALSE;

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance
                     ,LPSTR lpszCmdParam, int nCmdShow)
{
    glutInitWindowSize(680, 680);
    glutCreateWindow("OpenGL");
    glutDisplayFunc(DoDisplay);
    glutKeyboardFunc(DoKeyboard);
    glutCreateMenu(DoMenu);
    glutAddMenuEntry("Depth Test ON", 1);
    glutAddMenuEntry("Depth Test OFF", 2);
    glutAddMenuEntry("Cull Face ON", 3);
    glutAddMenuEntry("Cull Face OFF", 4);
    glutAttachMenu(GLUT_RIGHT_BUTTON);
    glutMainLoop();
    return 0;
}

void DoKeyboard(unsigned char key, int x, int y)
{
    switch(key)
    {
    case 'a':
        yAngle += 2;
        break;
    case 'd':
        yAngle -= 2;
        break;
    case 'w':
        xAngle += 2;
        break;
    case 's':
        xAngle -= 2;
        break;
    case 'q':
        zAngle += 2;
        break;
    case 'e':
        zAngle -= 2;
        break;
    case 'z':
        xAngle = yAngle = zAngle = 0.0;
        break;

    }

    char info[128];
    sprintf(info, "x=%.1f, y=%.1f, z=%.1f", xAngle, yAngle, zAngle);
    glutSetWindowTitle(info);
    glutPostRedisplay();
}

void DoMenu(int value)
{
    switch(value)
    {
    case 1:
        bDepthTest = GL_TRUE;
        break;
    case 2:
        bDepthTest = GL_FALSE;
        break;
    case 3:
        bCullFace = GL_TRUE;
        break;
    case 4:
        bCullFace = GL_FALSE;
        break;
    }

    glutPostRedisplay();
}

void DoDisplay()
{

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glShadeModel(GL_FLAT);

    if (bDepthTest)
    {
        glEnable(GL_DEPTH_TEST);
    }
    else
    {
        glDisable(GL_DEPTH_TEST);
    }

    if (bCullFace)
    {
        glEnable(GL_CULL_FACE);
    }
    else
    {
        glDisable(GL_CULL_FACE);
    }

    glPushMatrix();
    glRotatef(xAngle, 1.0f, 0.0f, 0.0f);
    glRotatef(yAngle, 0.0f, 1.0f, 0.0f);
    glRotatef(zAngle, 0.0f, 0.0f, 1.0f);

    // 아랫면
    glColor3ub(96, 30, 99);
    glBegin(GL_QUADS);
    glVertex2f(-0.5, 0.5);
    glVertex2f(0.5, 0.5);
    glVertex2f(0.5, -0.5);
    glVertex2f(-0.5, -0.5);
    glEnd();

    // 위쪽 삼각형
    glBegin(GL_TRIANGLE_FAN);
    glColor3f(1,1,1);
    glVertex3f(0.0, 0.0, -0.8);
    // 사용자(나) 쪽으로 가까운 z축의 값 (마이너스)
    glColor3ub(128, 45, 132);
    glVertex2f(0.5, 0.5);
    glVertex2f(-0.5, 0.5);

    // 왼쪽 삼각형
    glColor3ub(148, 58, 153);
    glVertex2f(-0.5, -0.5);

    // 아래쪽 삼각형
    glColor3ub(118, 39, 122);
    glVertex2f(0.5, -0.5);


    // 오른쪽 삼각형
    glColor3ub(158, 55, 163);
    glVertex2f(0.5, 0.5);
    glEnd();

    glPopMatrix();
    glFlush();

}

아래쪽에 깔리는 사각형은 z 좌표를 지정하지 않았으므로 z가 0인 평면에 그려진다. 윗 삼각형의 첫 꼭지점 좌표는 (0, 0, -0.8)로 되어 있다. 밑면의 정중앙에서 사용자쪽으로 0.8만큼 위쪽으로 솟은 정점을 지정했으며 나머지 두 변은 밑면의 우상, 좌상점을 지정했다. 그래서 삼각형이 밑면에서 비스듬히 솟은 모양으로 배치된다.

GL_TRIANGLE_FAN 모드로 그리고 있으므로 나머지 삼각형들은 모두 중앙의 꼭지점을 공유하며 밑면의 각 두 변과 연결하는 삼각형이 된다. 밑면에 바닥 사각형을 놓고 위쪽부터 반시계 방향으로 위쪽, 왼쪽, 아래쪽, 오른쪽 삼각형을 비스듬히 얹어 피라미드 모양을 완성했다. 빨간색 삼각형의 첫 꼭지점인 피라미드 꼭대기 외에는 모두 평면상의 좌표이므로 x, y만 지정하면 된다.

피라미드 예제는 입체를 그리기 위해 깊이 테스트 기능을 사용한다. 깊이 테스트 기능을 사용하려면 glutInitDisplayMode 함수로 디스플레이 모드를 설정할 때 GLUT_DEPTH 플래그를 지정해야 한다. 이 플래그가 있어야 각 픽셀의 깊이값을 저장할 수 있는 깊이 버퍼가 생성된다.

다행히 이 플래그는 디폴트로 선택되어 있으므로 일부러 빼지 않는한 따로 설정하지 않아도 깊이 버퍼는 자동으로 생성된다. 디스플레이 모드에 깊이 버퍼는 디폴트로 선택되어 있지만 깊이 테스트 기능은 디폴트로 꺼져 있다. 그래서 다음 호출문으로 깊이 테스트 기능을 켜야 기능이 동작한다.

  • glEnable(GL_DEPTH_TEST);

어떤 면이 더 위쪽에 있는지 즉, 사용자의 시선과 가까운지를 판별하여 순서에 상관없이 더 위쪽에 있는 면이 보이도록 해야 한다. 나중에 그려지는 도형이라도 사용자 시선보다 더 먼쪽이면 그리지 말아야 한다. 이런 판별을 하려면 화면상의 모든 점에 대해 깊이갚을 버퍼에 따로 저장하고 그릴 때 각 점의 깊이를 비교해야 한다.

2차원 그래픽은 그리는 순서만으로 앞뒤를 분간할 수 있다. 뒤쪽에 있는 물체를 먼저 그리고 앞쪽에 있는 물체를 나중에 그리면 아무 문제가 없다. 예를 들어 참새가 들판을 날아가는 장면이라면 들판을 먼저 그리고 참새를 나중에 그리면 아무 문제가 없다.

그러나 3차원 그래픽은 모든 물체가 입체적이므로 순서만으로는 앞뒤를 정확히 분간하기 어렵다. 손가락에 끼워진 반지의 경우 반지가 손가락을 에워싸고 있으므로 어느 물체가 더 앞쪽인지 명확하지 않다. 두 물체의 순서가 순환적이라 앞뒤 분간을 할 수 없으며 어떤 것을 먼저 그리더라도 일부가 가려질 수밖에 없다.

그래서 모든 화소의 깊이값을 별도의 버퍼에 따로 저장해 두고 매 화소를 그릴 때마다 이 화소가 출력 대상인지 판단해야 한다. 도형의 모든 점에 대해 깊이 정보가 필요하므로 정점의 깊이값이 아니라 화소의 깊이값을 저장해야 한다. 그래서 OpenGL은 별도의 깊이 버퍼를 관리하고 깊이값을 참조하여 물체를 그린다. 깊이 버퍼는 색상 버퍼와는 다른 완전히 분리된 메모리 영역이다. 그래서 화면을 삭제할 때 색상 버퍼외에 깊이 버퍼도 같이 삭제해야 한다. DoDisplay 함수 선두의 glClear문을 보면 다음과 같이 되어 있다.

  • glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

색상 버퍼뿐만 아니라 깊이 버퍼도 같이 지운다. 깊이 버퍼를 초기화하지 않으면 쓰레기값으로 가득차므로 그려져야 할 물체가 화면에 나타나지 않을 것이다. 색상 버퍼를 지우지 않으면 쓰레기 그림이 출력되는 것과 마찬가지이다.

 

16. 와인딩 & 컬링

도형을 구성하는 정점의 순서를 와인딩(Winding)이라고 한다. 정점을 시계 방향으로 나열할 수도 있고 반시계 방향으로 나열할 수도 있다. 방향에 따라 도형의 앞 뒤가 달라진다. 디폴트 와인딩은 반시계 방향으로 정의되어 있으며 관찰자가 보기에 반시계 방향으로 그려진 면이 도형의 앞으로 간주된다.

위 그림에서 반시계 방향으로 그려진 왼쪽 삼각형은 앞면이 보이는 상태이고 시계 방향으로 그려진 오른쪽 삼각형은 뒷면이 보이는 상태이다. 3D 그래픽은 회전이나 시점 변경이 가능해서 어디서 보더라도 앞뒷면이 일관된 방법이 필요한데 그것이 바로 와인딩이다. 와인딩 모드는 다음 함수로 지정한다.

  • void glFrontFace(GLenum mode);

인수로 GL_CW를 주면 시계 방향이 앞면이고 GL_CCW를 주면 반시계 방향이 앞면이다.

그렇다면 앞면, 뒷면이 왜 중요할까? 어차피 정점을 연결해서 채우면 똑같이 그려진다. 하지만 앞 뒤에 각각 다른 색상을 칠한다거나 조명을 비출 때는 앞뒤구분이 중요해진다. 또 뒷면을 생략하는 최적화 기법을 적용할 수 있는데 이럴 때는 어디가 생략 가능한 면인지를 분명히 해야 한다.

불필요한 그리기를 하지 않는 이런 기법을 컬링(Culling)이라고 한다. 그리되 가려져서 안 보이는 것과 아예 그리지 않는 것은 완전히 다르며 속도 차이가 엄청나게 벌어진다.

다음 예제는 와인딩 모드와 컬링을 테스트한다.

 

좌: Cull = OFF, Front = CCW / 우: Cull = ON, Front = CCW

 

Pyramid 예제에도 컬링 기능이 들어 있다. 이 예제의 도형들은 다음과 같은 와인딩으로 그려져 있다.

GL_TRIANGLE_FAN 모드는 항상 반시계 방향을 유지하며 윗변 삼각형 4개는 모두 반시계 방향으로 그려져 있다. 그래서 관찰자가 바라보면 쪽이 앞면이다. 반면 아래쪽의 흰색 밑면은 시계 방향으로 되어 있다. 왜냐하면 관찰자가 바라보는 쪽이 뒷면이고 피라미드를 뒤집었을 때 보이는 면이 앞면이기 때문이다. 다섯면 모두 피라미드 속이 아닌 바깥쪽이 앞면으로 지정되어 있다.  (??)

모든 면의 와인딩이 합리적으로 설정되어 있으므로 이 물체에는 컬링을 적용할 수 있다. 컬링 기능을 켜면 가려진 안쪽 면을 그리지 않으므로 그리는 속도가 훨씬 더 빨라진다. 이 정도 도형으로 속도차를 체감하는 것은 불가능하지만 수만개의 삼각형으로 구성된 복잡한 도형에서는 확실히 속도차가 날 것이다.

컬링 기능을 켜면 깊이 테스트는 생략해도 상관없다. 왜냐하면 피라미드는 완전히 볼록한 물체여서 특정 면이 시야에서 사라지는 경우는 항상 뒷면이 관찰자쪽이기 때문이다.

 

17. 폴리곤 모드

glColor 함수가 지정하는 색상은 정점에 대해 적용되는 것이지 면에 대해 적용되는 것이 아니다. 다각형 하나는 여러 개의 정점으로 구성된다. 각 정점의 색상이 제각각이면 과연 어떤 색상으로 어떻게 채색해야 할까. 다각형 채색 방식을 결정하는 것을 쉐이드 모델이라고 하며 다음 함수로 지정한다.

  • void glShadeModel(GLenum mode);

인수로 GL_FLATGL_SMOOTH 둘 중 하나의 값을 전달한다. GL_FLAT은 대표 정점의 색상으로 다각형 전체를 균일하게 채운다. 어떤 정점의 색을 사용할 것인가는 다각형에 따라 다른데 GL_POLYGON인 경우는 첫 정점의 색상을 사용하고 나머지는 마지막 정점의 색상을 사용한다. 피라미드의 각면은 GL_QUADSGL_TRAINGLE_FAN 모드로 그렸으므로 마지막 정점의 색이 적용되었다.

GL_SMOOTH 모드인 경우는 모든 정점의 색상을 섞어서 사용한다. 각 정점은 지정한 색으로 채색되고 중간 지점은 정점에서 떨어진 거리만큼 부드럽게 섞인다.  쉽게 말해서 그라데이션 처리된다. 다음 함수는 다각형의 폴리곤 모드를 지정한다.

void glPolygonMode(GLenum face, GLenum mode);

  • GL_POINT: 정점만 점으로 그린다. 점 크기는 GL_POINT_SIZE 설정을 따른다.
  • GL_LINE: 정점끼리 선으로만 연결한다. 선 굵기와 스티플 설정을 따른다.
  • GL_FILL: 면을 가득 채운다. 쉐이드 모델을 따른다.

다음 예제는 피라미드를 그리되 팝업 메뉴로 두 기능을 토글해 가며 출력 결과가 어떻게 달라지는지 관찰한다.

#include <windows.h>
#include <gl/glut.h>
#include <stdio.h>

void DoDisplay();
void DoKeyboard(unsigned char key, int x, int y);
void DoMenu(int value);

GLfloat xAngle, yAngle, zAngle;
GLenum PolygonMode = GL_FILL;
GLenum ShadeMode = GL_FLAT;

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance
                     ,LPSTR lpszCmdParam, int nCmdShow){

    glutCreateWindow("OpenGL");
    glutDisplayFunc(DoDisplay);
    glutKeyboardFunc(DoKeyboard);
    glutCreateMenu(DoMenu);
    glutAddMenuEntry("Polygon POINT", 1);
    glutAddMenuEntry("Polygon LINE", 2);
    glutAddMenuEntry("Polygon FILL", 3);
    glutAddMenuEntry("Smooth Shade", 4);
    glutAddMenuEntry("Flat Shade", 5);
    glutAttachMenu(GLUT_RIGHT_BUTTON);
    glutMainLoop();
    return 0;
}

void DoKeyboard(unsigned char key, int x, int y)

{
    // 아랫면 흰 바닥
    glColor3f(1, 1, 1);
    glBegin(GL_QUADS);
    glVertex2f(-0.5, 0.5);
    glVertex2f(0.5, 0.5);
    glVertex2f(0.5, -0.5);
    glVertex2f(-0.5, -0.5);
    glEnd();

    // 위쪽 빨간 변
    glBegin(GL_TRIANGLE_FAN);
    glColor3f(1, 1, 1);
    glVertex3f(0.0, 0.0, -0.8);
    glColor3f(1, 0, 0);
    glVertex2f(0.5, 0.5);
    glVertex2f(-0.5, 0.5);

    // 왼쪽 노란 변
    glColor3f(1, 1, 0);
    glVertex2f(-0.5, -0.5);

    // 아래쪽 초록 변
    glColor3f(0, 1, 0);
    glVertex2f(0.5, -0.5);

    // 오른쪽 파란 변
    glColor3f(0, 0, 1);
    glVertex2f(0.5, 0.5);
    glEnd();

}


void DoMenu(int value)
{

    switch(value)
    {
    case 1:
        PolygonMode = GL_POINT;
        break;
    case 2:
        PolygonMode = GL_LINE;
        break;
    case 3:
        PolygonMode = GL_FILL;
        break;
    case 4:
        ShadeMode = GL_SMOOTH;
        break;
    case 5:
        ShadeMode = GL_FLAT;
        break;
    }

    glutPostRedisplay();
}


void DrawPyramid()
{

    // 아랫면 흰 바닥
    glColor3f(1, 1, 1);
    glBegin(GL_QUADS);
    glVertex2f(-0.5, 0.5);
    glVertex2f(0.5, 0.5);
    glVertex2f(0.5, -0.5);
    glVertex2f(-0.5, -0.5);
    glEnd();

    // 위쪽 빨간 변
    glBegin(GL_TRIANGLE_FAN);
    glColor3f(1, 1, 1);
    glVertex3f(0.0, 0.0, -0.8);
    glColor3f(1, 0, 0);
    glVertex2f(0.5, 0.5);
    glVertex2f(-0.5, 0.5);

    // 왼쪽 노란 변
    glColor3f(1, 1, 0);
    glVertex2f(-0.5, -0.5);

    // 아래쪽 초록 변
    glColor3f(0, 1, 0);
    glVertex2f(0.5, -0.5);

    // 오른쪽 파란 변
    glColor3f(0, 0, 1);
    glVertex2f(0.5, 0.5);
    glEnd();

}

void DoDisplay()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glEnable(GL_DEPTH_TEST);

    glPolygonMode(GL_FRONT_AND_BACK, PolygonMode);
    glShadeModel(ShadeMode);

    glPushMatrix();
    
    glRotatef(xAngle, 1.0f, 0.0f, 0.0f);
    glRotatef(yAngle, 0.0f, 1.0f, 0.0f);
    glRotatef(zAngle, 0.0f, 0.0f, 1.0f);

    DrawPyramid();

    glPopMatrix();

    glFlush();

}

18. 3차원 예제 샘플 호출

GLUT은 실습용 물체를 그리는 기능을 제공하므로 테스트용으로 사용할 물체 정도는 함수 호출 하나로 그릴 수 있다.

다음 함수는 큐브, 즉 입체적인 육면체를 그린다.

  • void glutWireCube(GLdouble size);
  • void glutSolidCube(GLdouble size);

육면체를 그리려면 정점 8개를 배치하고 사각형 6개를 그려야 하지만 이 함수를 호출하면 한면의 길이만 전달함으로써 간단하게 육면체를 그릴 수 있다.

 

다음 함수는 구를 그린다.

  • void glutWireSphere(GLdouble radius, GLint slices, GLint stacks);
  • void glutSolidSphere(GLdouble radius, GLint slices, GLint stacks);

반지름과 가로, 세로 분할 수를 지정하면 구가 그려진다. 분할 수는 구를 몇등분하여 그릴 것인가를 지정하는데 지구본의 위도, 경도선과 비슷하다.

 

다음 함수는 원뿔을 그린다.

  • void glutWireCone(GLdouble base, GLdouble height, GLint slices, GLint stacks);
  • void glutSolidCone(GLdouble base, GLdouble height, GLint slices, GLint stacks);

아랫변 원의 반지름과 높이, 분할수를 전달한다.

 

다음 함수는 토러스를 그린다. 토러스는 환원체라고도 하는데 쉽게 말해서 도너츠를 생각하면 된다.

  • void glutWireTorus(GLdouble innerRadius, GLdouble outerRadius, GLint nsides, GLint rings);
  • void glutSolidTorus(GLdouble innerRadius, GLdouble outerRadius, GLint nsides, GLint rings);

안쪽 반지름, 바깥쪽 반지름, 분할수를 지정한다.

 

다음 함수들은 정다각형을 그린다. 4면체, 8면체, 12면체, 20면체이 등이다. 앞에서 먼저 소개한 6면체도 물론 정다각형이다. 정다면체는 딱 이 다섯 가지밖에 없다. 

  • glutWireTetrahedron
  • glutWireOctahedron
  • glutWireDodecahedron
  • glutWireIcosahedron

 

다음 함수는 다소 복잡한 물체인 주전자를 그린다. 이 주전자는 유타 대학에서 처음 디자인했다고 해서 유타 주전자로도 불리며 3D 그래픽 프로그램의 예제로 종종 사용된다. 인수로 크기만 전달하면 주전자가 그려진다.

  • void glutWireTeapot(GLdouble size);
  • void glutSolidTeapot(GLdouble size);

 

#include <windows.h>
#include <gl/glut.h>
#include <stdio.h>

void DoDisplay();
void DoKeyboard(unsigned char key, int x, int y);

GLfloat xAngle, yAngle, zAngle;

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance
                     ,LPSTR lpszCmdParam, int nCmdShow)
{

    glutCreateWindow("OpenGL");
    glutDisplayFunc(DoDisplay);
    glutKeyboardFunc(DoKeyboard);
    glutMainLoop();
    return 0;
}

void DoKeyboard(unsigned char key, int x, int y)
{
    switch(key)
    {
    case 'a':
        yAngle += 2;
        break;
    case 'd':
        yAngle -= 2;
        break;
    case 'w':
        xAngle += 2;
        break;
    case 's':
        xAngle -= 2;
        break;
    case 'q':
        zAngle += 2;
        break;
    case 'e':
        zAngle -= 2;
        break;
    case 'z':
        xAngle = yAngle = zAngle = 0.0;
        break;
    }

    char info[128];
    sprintf(info, "x=%.1f, y=%.1f, z=%.1f", xAngle, yAngle, zAngle);
    glutSetWindowTitle(info);
    glutPostRedisplay();
}

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

    glClearColor(0.0, 0.0, 0.0, 1.0);

    glPushMatrix();
    glRotatef(xAngle, 1.0f, 0.0f, 0.0f);
    glRotatef(yAngle, 0.0f, 1.0f, 0.0f);
    glRotatef(zAngle, 0.0f, 0.0f, 1.0f);

    // 주전자
    glutWireTeapot(0.3);

    // 정육면체
    glPushMatrix();
    glTranslatef(-0.6, 0.6, 0.0);
    glutWireCube(0.4);
    glPopMatrix();

    // 원뿔
    glPushMatrix();
    glTranslatef(-0.6, -0.6, 0.0);
    glutWireSphere(0.3, 20, 20);
    glPopMatrix();

    // 구체
    glPushMatrix();
    glTranslatef(0.6, 0.6, 0.0);
    glutWireCone(0.3, 0.6, 20, 10);
    glPopMatrix();

    // 도넛
    glPushMatrix();
    glTranslatef(0.6, -0.6, 0.0);
    glutWireTorus(0.1,0.2,20, 20);
    glPopMatrix();

    glPopMatrix();

    glFlush();
}

 

glu 라이브러리도 테스트를 위한 입체 도형을 제공한다. glu는 별도의 설정 객체로 그리는 방법을 다양하게 지정할 수 있다. 설정 객체는 다음 함수로 생성 및 파괴한다. (*: 포인터)

  • GLUquadric* gluNewQuadric();
  • void gluDeleteQuadric(GLUquadric* quad);

 

객체를 생성한 후 다음 함수들로 그리기 속성을 설정한다.

  • void gluQuadricDrawStyle(GLUquadric* quad, GLenum draw);
  • void gluQuadricNormals(GLUquadric* quad, GLenum normal);
  • void gluQuadricOrientation(GLUquadric* quad, GLenum orientation);
  • void gluQuadricTexture(GLUquadric* quad, GLboolean texture);

 

다음 인수로 도형을 어떻게 그릴지를 지정한다.

  • GLU_FILL: 가득 채운다.
  • GLU_LINE: 와이어 프레임으로 그린다.
  • GLU_SILHOUETTE: 폴리곤의 인접면을 제외하고 와이어 프레임으로 그린다.
  • GLU_POINT: 점의 집합으로 그린다.

 

도형을 그리는 모든 함수들은 설정 객체를 첫번째 인수로 받는다. 나머지 인수는 그리는 도형에 대한 인수들이되 GLUT의 그리기 함수들과 거의 비슷하다.

  • void gluSphere(GLUquadric* quad, GLdouble radius, GLint slices, GLint stacks);
  • void gluCylinder(GLUquadric* quad, GLdouble base, GLdouble top, GLdouble height, GLint slices, GLint stacks);
  • void gluDisk(GLUquadric* quad, GLdouble inner, GLdouble outer, GLint slices, GLint loops);

구는 반지름과 분할 수를 지정한다. 실린더는 아랫면과 윗면의 반지를 지정하되 이 둘이 같으면 원기둥이 되고 다르면 원뿔이 된다. 디스크는 안쪽 반지름과 바깥쪽 반지름을 지정하되 안쪽이 0이 아니면 구멍이 뚫린 엽전 모양이 된다.

void DoDisplay()
{
    glClear(GL_COLOR_BUFFER_BIT);

    glPushMatrix();
    glRotatef(xAngle, 1.0f, 0.0f, 0.0f);
    glRotatef(yAngle, 0.0f, 1.0f, 0.0f);
    glRotatef(zAngle, 0.0f, 0.0f, 1.0f);

    GLUquadricObj *pQuad;
    pQuad = gluNewQuadric();
    gluQuadricDrawStyle(pQuad, GLU_LINE);

    // 구체
    gluSphere(pQuad, 0.3, 20, 20);

    // 원통
    glPushMatrix();
    glTranslatef(-0.6, 0.6, 0.0);
    gluCylinder(pQuad, 0.2, 0.2, 0.5, 20, 20);
    glPopMatrix();

    // 원뿔
    glPushMatrix();
    glTranslatef(-0.6, -0.6, 0.0);
    gluCylinder(pQuad, 0.2, 0.0, 0.5, 20, 20);
    glPopMatrix();

    // 가운데가 뚫린 거미줄(?) 
    glPushMatrix();
    glTranslatef(0.6, 0.6, 0.0);
    gluDisk(pQuad, 0.1, 0.3, 10, 10);
    glPopMatrix();

    // 가운데가 안 뚫린 거미줄(?) 
    glPushMatrix();
    glTranslatef(0.6, -0.6, 0.0);
    gluDisk(pQuad, 0.0, 0.3, 10, 10);
    glPopMatrix();

    gluDeleteQuadric(pQuad);
    glPopMatrix();

    glFlush();
}

문의 | 코멘트 또는 yoonbumtae@gmail.com


카테고리: Media Artetc.


0개의 댓글

답글 남기기

Avatar placeholder

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다