윈도우 크기 변화에 대응하기

VC 프로젝트 파일을 받아서 실행시켜 보세요. 두 개의 창이 보일거에요. 하나는 콘솔창이고 다른 하나는 OpenGL 창이죠. OpenGL 창을 너비와 맞지 않게 높이를 조절해 보세요. 삼각형이 일그러져서 보이죠? 이것은 우리가 투영값을 제대로 설정하지 않아서 그런 것이랍니다. 기본 투영값은 너비/높이의 비율로 1 이 설정되어 있고 이 비율에 따라서 그림을 그리죠. 그래서 비율이 변하게 되면 투영되는 그림이 일그러지는 것입니다. 그래서, 창의 너비와 높이가 변할 때마다 투영값을 다시 계산해줘야합니다.

GLUT 는 창의 크기가 변할 때 호출되는 함수를 설정할 수 있는 함수를 제공합니다. 즉, 투시값을 계산하는 콜백함수를 등록하는 것입니다. 게다가 이 함수는 창이 생성되어 초기화될 때도 호출되기 때문에 창이 정사각형이 아니어도 그림을 창의 너비와 높이의 비율에 맞춰 예쁘게 그릴 수 있습니다.

GLUT 는 glutReshapeFunc 함수를 사용해서 이 일을 처리합니다.

void glutReshapeFunc(void (*func)(int width, int height));

인자 설명:
func - 창의 크기가 변할 때 투영값을 계산할 함수의 이름입니다.

제일 먼저 해야할 것은 glutReshapeFunc 함수에 전달할 함수를 선언하고 정의하는 것이겠죠. 여기서 만드는 함수는 changeSize 함수로 윈도우 크기를 조절할 때 사용되는 함수입니다. main 함수 내에서 glutReshapeFunc 함수를 호출해서 changeSize 함수를 콜백함수로 추가합니다. :

void main(int argc, char **argv) 
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DEPTH | GLUT_SINGLE | GLUT_RGBA);
    glutInitWindowPosition(100,100);
    glutInitWindowSize(320,320);
    glutCreateWindow("3D Tech- GLUT Tutorial");
    glutDisplayFunc(renderScene);

    //새롭게 추가된 코드
    glutReshapeFunc(changeSize);

    glutMainLoop();
}

자 이제 투영값을 계산하는 함수를 정의해 봅시다. glutReshapeFunc 를 보면 changeSize 함수는 두 개의 인자를 전달 받습니다. 하나는 창의 너비(width)이고 다른 하나는 창의 높이(height) 입니다. 여기서 말하는 창의 너비와 높이는 창의 프레임을 뺀 클라이언트 영역의 크기입니니다.

void changeSize(int w, int h)
{
    //창이 아주 작을 때, 0 으로 나누는 것을 예방합니다.
    if(h == 0)
        h = 1;
    float ratio = 1.0* w / h;

    //좌표계를 수정하기 전에 초기화합니다.
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    //뷰포트를 창의 전체 크기로 설정합니다.
    glViewport(0, 0, w, h);

    //투시값을 설정합니다.
    gluPerspective(45,ratio,1,1000);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(0.0,0.0,5.0, 0.0,0.0,-1.0, 0.0f,1.0f,0.0f);
}

여러개의 함수를 살펴보았는데 다 까먹기 전에 좀 더 깊게 살펴봅시다. 위의 코드를 보면 우선 창의 너비와 높이의 비율을 계산했는데, 여기서 중요한 것은 이 값을 항상 유효한 값으로 만들기 위해서 창의 높이 값이 0 이 안 되도록 만드는 것입니다. 컴퓨터에서 0 으로 나누는 것은 옳은 연산이 아니기 때문입니다.

그리고 현재 행렬을 투영행렬로 설정하는데 이 행렬로 관측 공간을 정의합니다. 그리고 투영행렬을 단위행렬로 초기화하고 나서 뷰포트(화면상의 화상 표시영역)를 glViewport 함수를 사용해서 창의 전체 클라이언트 영역으로 설정했습니다. 뷰포트가 무엇인지 궁금하면 다른 값을 넣어서 실험해보세요. 처음 두 개의 인자는 위쪽, 오른쪽 좌표값이고 나머지 두개는 왼쪽, 아래쪽 좌표값입니다. 이 때 설정하는 좌표값은 화면 좌표값이 아니라 창의 클라이언트 영역 좌표값입니다. 각각의 값을 바꿔서 실험해 보되 너비와 높이의 비율은 widht, height 변수를 이용해서 계산한 값을 사용하세요.

gluPerspective 함수는 OpenGL 의 또 다른 라이브러리입니다. OpenGL 유틸리티 라이브러리 또는 GLU 라고 부릅니다. GLU 는 OpenGL 구현을 도와주는 표준 컴포넌트입니다. gluPerspective 함수는 투영을 만드는데 필요한 값을 인자로 받습니다. 처음 것은 yz 평면의 시야각이고 두번째 것은 뷰포트의 너비와 높이의 비율입니다. 나머지 두 인자는 절단 평면의 near 와 far 를 설정하는 값입니다. 무엇이든지 near 값보다 가깝게 있거나 far 값보다 멀리 있으면 장면에서 잘려져 나갑니다. 이 값을 잘 못 설정하면 아무것도 못 볼 수 있으니 조심하세요!

마지막으로 설정하는 것은 카메라입니다. 우선 현재 행렬을 GL_MODELVIEW 로 설정했는데 모델뷰행렬에 카메라 설정과 모델링 변환을 수행할 수 있습니다. 카메라를 설정하기 전에 항상 모델뷰행렬을 단위행렬로 초기화해야합니다. 이 것은 예전에 사용한 카메라 설정이나 변환 효과가 적용되는 것을 없애는 것이죠. gluLookAt 함수를 사용하면 카메라의 위치와 카메라가 바라보는 방향을 아주 쉽게 설정할 수 있습니다. 카메라를 이렇게 설정하는 것은 원래 세 그룹으로 나뉘는 인자들을 설정해줘야하죠. 각각의 그룹은 세개의 float 형 값을 가집니다. 처음 세가지 값은 카메라의 위치이고 두번째는 카메라가 바라보는 방향이고 나머지 값은 카메라의 위쪽을 정의하는 값입니다. 보통 이 값에는 (0.0, 1.0, 0.0) 을 사용하는데 카메라가 기울지 않았다는 것을 말합니다. 카메라를 기울이고 싶다면 이 값을 조절하면 됩니다. 예를 들어서 모든 것이 뒤집혀서 보이게 할려면 (0.0, -1.0, 0.0) 으로 설정하면 됩니다.

VC 프로젝트 파일 을 받아서 창의 크기를 조절해 보면서 삼각형의 비율이 일정하게 유지되는지 살펴보세요. 그리고 새로 소개한 함수들의 인자를 바꿔가면서 실제 어떤 일이 일어나는 살펴보길 바랍니다.

Last updated