728x90
반응형

OpenGL 콜백 프로그래밍



저번 포스팅에서는 윈도우 뷰포트 설정을 살펴보았다. 윈도우 뷰포트 설정을 하지 않으면 자동으로 뷰포트 설정이 되는데, 사용자가 창 위치를 변경한다던지, 창 크기를 늘리는 등의 행위를 했을 때 동적으로 반응하는 콜백함수가 있어야 물체가 왜곡되지 않는다.


오늘 포스팅에서는 이러한 사용자의 행위에 대해 동적으로 반응하는 콜백 프로그래밍을 다루려고 한다.


프로그래머는 리세이프 콜백(Reshape Callback) 함수를 통해 이러한 이벤트에 어떻게 대응할 것인지를 원하는 대로 명시할 수 있다. 리셰이프 이벤트를 등록하기 위한 콜백 함수 프로토타입은 다음과 같다.


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

다소 복잡해 보일 수 있지만 괄호 안의 함수 포인터는 함수명 자체를 뜻한다. 예를 들어서 콜백함수가 MyReshape 일 경우 glutReshapeFunc(MyReshape)라고 선언해주면 된다 리셰이프 이벤트 발생 시 GLUT는 괄호 안의 파라미터를 통해 변경된 윈도우 폭과 높이를 콜백함수에게 넘겨준다.


윈도우 크기 조절에 따른 왜곡을 방지하려면 glOrtho()함수를 이용해야한다.


glMatrixMode(GL_PROJECTION); // 
	glLoadIdentity();
	glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);

오픈지엘에서의 모든 변환 작업은 행렬의 곱셈으로 계산된다는 사실을 다 알고있을 것이다. glMatrixMode()는 투상 행렬(GL_PROJECTION)을 변환대상으로 설정하라는 명령이며, glLoadIdentity()는 이 행렬에 일단 항등 행렬을 실으라는 명령이다.


glOrtho() 함수를 실행하기 위해서는 이 두가지 명령이 선행되어야한다. 이 함수는 평행 투상의 일종으로 육면체 형태의 가시부피를 설정함으로써 정의된다. 


여기서 가시부피란 '화면에 보이고자 하는 물체의 범위'를 뜻한다. 따라서 지정된 가시 부피 밖의 물체는 보이지 않게 된다. 이러한 가시부피를 정의하기 위한 glOrtho() 함수는 다음과 같이 정의된다.


void glOrtho(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far);


괄호 안의 파라미터는 순서대로 가시 부피의 좌, 우, 상, 하, 전, 후 면의 위치를 나타낸다. 3차원에서의 사각형을 생각했을 때 상하좌우는 네모칸에서의 영역을 표시하며,  전, 후면은 3차원 입체 영상에서 가장 가까운 면의 전방 절단면, 후방 절단면을 뜻한다. (이 좌표는 전면의 z값 보다 후면의 z값이 더 크다)


투상면의 종횡비와 뷰 포트의 종횡비는 직결되어있다. 예시를 들어 살펴보자면


OpenGL 사각형그리기 예제2 에서 살펴본 

glViewport(0,0,300,150);, glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0); 은 아래와 같은 그림으로 왜곡된 모습을 갖추고 있으나




종횡비에 맞게끔 glOrtho(-2.0, 2.0, -1.0, 1.0, -1.0, 1.0) 를 설정해주면 아래와 같이 왜곡되지 않는 모습을 보이게 된다.





리셰이프 콜백함수를 등록한 코드


#include <GL/glut.h>
#include <GL/GL.h>
#include <GL/GLU.h>

void MyDisplay(){
	glClear(GL_COLOR_BUFFER_BIT); // GL상태변수 설정, 프레임 버퍼를 초기화
									// 초기화 될 색은 glutClearColor에서 사용된 색
	glColor3f(0.5, 0.5, 0.5); // 회색으로 설정
	glBegin(GL_POLYGON); // 입력요소 기본정의
	glVertex3f(-0.5, -0.5, 0.0);
	glVertex3f(0.5, -0.5, 0.0);
	glVertex3f(0.5, 0.5, 0.0);
	glVertex3f(-0.5, 0.5, 0.0);
	glEnd();
	glFlush();
}
void MyReshape(int NewWidth, int NewHeight){
	glViewport(0, 0, NewWidth, NewHeight);
	GLfloat WidthFactor = (GLfloat)NewWidth / (GLfloat)300;
	GLfloat HeightFactor = (GLfloat)NewHeight / (GLfloat)300;
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(-1.0*WidthFactor, 1.0*WidthFactor, -1.0*HeightFactor, 1.0*HeightFactor, -1.0, 1.0);

}
int main(int argc, char** argv){
	glutInit(&argc, argv); // GLUT 윈도우 함수
	glutInitDisplayMode(GLUT_RGB); // 윈도우 의 기본컬러모드를 RGB모드로 설정
	glutInitWindowSize(300, 300); // 윈도우 사이즈 설정
	glutInitWindowPosition(0, 0); // 윈도우 창 위치 설정
	glutCreateWindow("OpenGL example");
	glClearColor(1.0, 1.0, 1.0, 1.0); // GL 상태변수 설정, 마지막 알파값은 1이면 불투명 0이면 투명 
	
	glutDisplayFunc(MyDisplay);
	glutReshapeFunc(MyReshape); // 리셰이프콜백함수 호출
	
	glutMainLoop(); // 이벤트 루프 진입
	return 0;
}


리셰이프 콜백함수를 등록한 후 결과화면은 창크기를 늘리거나 줄여도 같은 비율을 유지하며 회색 사각형을 띄워주는 결과를 보인다.





728x90
반응형