250 likes | 311 Views
Learn how to implement input and interaction in OpenGL with callbacks for viewport, ortho projection, reshape, keyboard, and special key handling. Detailed examples provided.
E N D
Implement of Input and Interaction Hanyang University
Objective • Viewport and Ortho • Callback Programming • Reshape Callback • Keyboard Callback • SpecialKey Callback • Mouse Callback • Menu Callback
Viewport Viewport and ortho • glViewport • 윈도우 상에서 그림이 그려질 영역을 설정한다. • glViewport(GLintx, GLinty, GLsizeiwidth, GLsizeiheight); • x : 영역의 좌 하단 x 좌표 • y : 영역의 우 하단 y 좌표 • width : 영역의 너비 • height : 영역의 높이 • EX ) … glutInitWindowSize(400, 300); glViewport(100, 80, 160, 100); … 400 (window width) 300 (window height) height = 100 y = 80 width = 160 원점 x = 100
glOrtho • 직교투영(PROJECTION) 함수 • 3차원의 OpenGL 공간을 2차원의 윈도우에 어떻게 투영할 것인가? • 가시부피 설정 • glOrtho( GLdoubleleft, GLdoubleright, // x축 범위 GLdoublebottom, GLdoubletop, // y축 범위 GLdoublenear, GLdoublefar // z축 범위 ); • Default 설정 • glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0); (right, top, far) (left, bottom, near) view
Example source #include <gl/glut.h> voidMyDisplay() { glClear(GL_COLOR_BUFFER_BIT); glViewport(100, 100, 200, 200); glBegin(GL_QUADS); //그리기 색 (Red, Green, Blue) (적색) glColor3f(1.0, 0.0, 0.0); glVertex3f(0, 0, 0.0); glVertex3f(640, 0, 0.0); glVertex3f(640, 480, 0.0); glVertex3f(0, 480, 0.0); //그리기 색 (Red, Green, Blue) (회색) glColor3f(0.5, 0.5, 0.5); glVertex3f(160, 120, 0.0); glVertex3f(480, 120, 0.0); glVertex3f(480, 360, 0.0); glVertex3f(160, 360, 0.0); glEnd(); glFlush(); } intmain(int argc, char** argv) { glutInitDisplayMode(GLUT_RGB); glutInitWindowSize(640, 480); //윈도우창 크기 설정 (width, height) glutInitWindowPosition(0, 0); //윈도창의 시작 위치 (x, y) glutCreateWindow("OpenGL Drawing Example"); //윈도우 바탕 색 (Red, Green, Blue, Alpha) (흰색) glClearColor(1.0, 1.0, 1.0, 1.0); // Ortho 설정을 위해서는 다음 두 함수가 선행 되어져야 함. glMatrixMode(GL_PROJECTION); //투영좌표계설정 glLoadIdentity(); //좌표계초기화 glOrtho(0.0, 640.0, 0.0, 480.0, -1.0, 1.0); glutDisplayFunc(MyDisplay); glutMainLoop(); return 0; }
Reshape Callback • 윈도우의 크기나 모양이 바뀔 때 GLUT가 호출하는콜백함수를 등록 • voidglutReshapeFunc(void(*func)(intwidth, intheight)); • width : 윈도우의 새로운 너비 • height : 윈도우의 새로운 높이
Example Source #include <gl/glut.h> voidMyDisplay() { glClear(GL_COLOR_BUFFER_BIT); 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(); } voidMyReshapde(intNewWidth, intNewHeight) { glViewport(0, 0, NewWidth, NewHeight); //뷰포트 크기를 변경된 윈도우 크기와 일치 시킨다. GLfloatWidthFactor = (GLfloat)NewWidth / (GLfloat)300; GLfloatHeightFactor = (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); } intmain(intargc, char** argv) { glutInitWindowSize(300, 300); glutCreateWindow("OpenGL Drawing Example"); glClearColor(1.0, 1.0, 1.0, 1.0); glutDisplayFunc(MyDisplay); glutReshapeFunc(MyReshapde); glutMainLoop(); return 0; }
Keyboard Callback • 키보드 입력이 일어날 때마다 GLUT가 호출하는 콜백함수를 등록 • voidglutKeyboardFunc(void(*func)(unsigned charkey, intx, inty)); • key : 키보드의 눌려진 키 • x : 마우스의 x 좌표 • y : 마우스의 y 좌표
Example Source #include <gl/glut.h> voidMyDisplay() { glClear(GL_COLOR_BUFFER_BIT); 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(); } voidMyKeyboard(unsigned charKeyPressed, intX, intY) { switch(KeyPressed) { case 'Q' : exit(0); break; case 'q' : exit(0); break; case 27 :exit(0); break; // ESC키 } } intmain(intargc, char** argv) { glutInitWindowSize(300, 300); glutCreateWindow("OpenGL Drawing Example"); glClearColor(1.0, 1.0, 1.0, 1.0); glutDisplayFunc(MyDisplay); glutKeyboardFunc(MyKeyboard); glutMainLoop(); return 0; }
SpecialKey Callback • 특수키 입력이 일어날 때마다 GLUT가 호출하는 콜백함수를 등록 • 기능키(F1~F12), 방향키, insert, home, end, page up, page down • voidglutSpecialFunc(void(*func)(intkey, intx, inty)); • key : 키보드의 눌려진 특수키 • x : 마우스의 x 좌표 • y : 마우스의 y 좌표 • 사용법은 keyboard callback과 비슷함.
SpecialKey Callback • 기능키 값 • GLUT_KEY_F1 ~ GLUT_KEY_F12 • 방향키 값 • GLUT_KEY_LEFT • GLUT_KEY_UP • GLUT_KEY_RIGHT • GLUT_KEY_DOWN • 그 외 • GLUT_KEY_PAGE_UP • GLUT_KEY_PAGE_DOWN • GLUT_KEY_HOME • GLUT_KEY_END • GLUT_KEY_INSERT
Mouse Callback(click) • 마우스 이벤트가 발생할 때마다 GLUT가 호출하는 마우스 클릭 콜백 함수를 등록 • voidglutMouseFunc(void(*func)(intbutton, intstate, intx, inty)); • button : 버튼의 종류를 뜻하는 상수값 • 버튼의 종류 : GLUT_LEFT_BUTTON GLUT_RIGHT_BUTTON GLUT_MIDDLE_BUTTON • State : 해당 버튼이 눌러진 상태인지 아닌지를 알려주는 상수값 • 버튼의 상태 : GLUT_DOWN, GLUT_UP • x : 마우스의 x좌표 • y : 마우스의 y좌표
Mouse Callback(click) • 마우스 클릭 콜백 함수 등록
Mouse Callback(motion) • 버튼을 누른 상태에서 마우스를 움직일 때 호출되는 마우스 움직임 콜백 함수를 등록 • voidglutMotionFunc(void(*func)(intx, inty)); • x : 마우스의 x 좌표 • y : 마우스의 y 좌표
Example Source #include <gl/glut.h> GLintTopLeftX, TopLeftY, BottomRightX, BottomRightY; voidMyDisplay() { glViewport(0, 0, 300, 300); glClear(GL_COLOR_BUFFER_BIT); glColor3f(0.5, 0.5, 0.5); glBegin(GL_POLYGON); glVertex3f(TopLeftX / 300.0, (300 - TopLeftY) / 300.0, 0.0); glVertex3f(TopLeftX / 300.0, (300 - BottomRightY) / 300.0, 0.0); glVertex3f(BottomRightX / 300.0, (300 - BottomRightY) / 300.0, 0.0); glVertex3f(BottomRightX / 300.0, (300 - TopLeftY) / 300.0, 0.0); glEnd(); glFlush(); } 마우스 왼클릭 후 드래그한 영역에 사각형을 그리는 예제
voidMyMouseClick(GLintButton, GLintState, GLintX, GLintY) { if(Button == GLUT_LEFT_BUTTON && State == GLUT_DOWN) { TopLeftX = X; TopLeftY = Y; } } voidMyMouseMove(GLintX, GLintY) { BottomRightX = X; BottomRightY = Y; glutPostRedisplay();// 그림을 새로 그려줌 } intmain(intargc, char** argv) { glutInitWindowSize(300, 300); glutCreateWindow("OpenGL Drawing Example"); glClearColor(1.0, 1.0, 1.0, 1.0); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0); glutDisplayFunc(MyDisplay); glutMouseFunc(MyMouseClick); glutMotionFunc(MyMouseMove); glutMainLoop(); return 0; }
glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0); => => <= 좌표변환 필요 : Window 좌표계를 OpenGL좌표계로 매핑시킨다. 윈도우 x좌표에서 OpenGL x좌표로 변환 = 윈도우 X좌표 / 300 윈도우 y좌표에서 OpenGL y좌표로 변환 = (300 - 윈도우 Y좌표) / 300 v1x = TopLeftX / 300; v1y = (300 - TopLeftY) / 300; v2x = TopLeftX / 300; v2y = (300 - BottomRightY) / 300; v3x = BottomRightX / 300; v3y = (300 - BottomRightY) / 300; v4x = BottomRightX / 300; v4y = (300 - TopLeftY) / 300;
Menu Callback • 메뉴 선택시 호출되는 메뉴 콜백 함수를 등록하는 함수 - intglutCreateMenu(void(*func)(intvalue)); • 리턴값 : 해당 메뉴의 고유 아이디값 • value : 엔트리 아이디 값
Menu Callback • Id에 해당하는 메뉴를 이용한다. - intglutSetMenu(intid) • id : glutCreateMenu()에 리턴되는 값
Menu Callback • 메뉴 항목을 추가한다. - intglutAddMenuEntry(char *name, intvalue); • name : 항목의 이름 • value : 해당 항목이 선택될 때 메뉴 콜백함수에게 전달되는 정수값
Menu Callback • 지정한 마우스 버튼에 메뉴가 적용된다. - intglutAttachMenu(intbutton); • button : 하나 3개 상수값중 하나를 선택한다. GLUT_LEFT_BUTTON : 마우스 왼쪽 버튼 GLUT_RIGHT_BUTTON : 마우스 오른쪽 버튼 GLUT_MIDDLE_BUTTON : 마우스 가운데 버튼
Menu Callback • 서브 메뉴가 있는 메뉴를 추가한다 - intglutAddSubMenu(char *name, intmenu); • name : 서브 메뉴 항목의 이름 • menu : glutCreateMenu()에 의해 해당 서브메뉴를 만들 때 리턴된 메뉴 아이디 값
Example Source #include <gl/glut.h> GLbooleanIsSphere = true; GLbooleanIsSmall = true; voidMyDisplay() { glClear(GL_COLOR_BUFFER_BIT); glColor3f(0.5, 0.5, 0.5); if((IsSphere) && (IsSmall)) glutWireSphere(0.2, 15, 15); // 작은 Wire(선으로 이루어진) Sphere(구(球)) else if((IsSphere) && (!IsSmall)) glutWireSphere(0.4, 15, 15); // 큰 Sphere else if((!IsSphere) && (IsSmall)) glutWireTorus(0.1, 0.3, 40, 20); // 작은 Wire Torus(도넛형 고리) else glutWireTorus(0.2, 0.5, 40, 20); // 큰 Torus glFlush(); } voidMyMainMenu(intentryID) { if(entryID == 1) IsSphere = true; // Draw Sphere 선택 else if(entryID == 2) IsSphere = false; // Draw Torus 선택 else if(entryID == 3) exit(0); // Exit 선택 glutPostRedisplay(); }
voidMySubMenu(intentryID) { if(entryID == 1) IsSmall = true; //Small One선택 elseif(entryID == 2) IsSmall = false; //Big One선택 glutPostRedisplay(); } intmain(intargc, char** argv) { glutInitWindowSize(300, 300); glutCreateWindow("OpenGL Drawing Example"); glClearColor(1.0, 1.0, 1.0, 1.0); GLintMySubMenuID = glutCreateMenu(MySubMenu); //서브 메뉴 등록 glutAddMenuEntry("Small One", 1); glutAddMenuEntry("Big One", 2); GLintMyMainMenuID = glutCreateMenu(MyMainMenu); //메인 메뉴 등록 glutAddMenuEntry("Draw Sphere", 1); glutAddMenuEntry("Draw Torus", 2); glutAddSubMenu("Change Size", MySubMenuID); glutAddMenuEntry("Exit", 3); glutAttachMenu(GLUT_RIGHT_BUTTON); glutDisplayFunc(MyDisplay); glutMainLoop(); return 0; }