선 택 과 피 드 백
선택과 피드백 “선 택 모 드 ” “ 피 드 백 모 드 ” 선택모드와 피드백모드에서는 드로잉정보를 프레임버퍼가 아닌 응용프로그램으로 반환 스크린에는 아무런 변화가 없음 컬러버퍼, 깊이버퍼, 스텐실버퍼, 누적버퍼 등에 아무런 영향을 미치지 않는다. 2009-2학기 가상현실
선택 모드 선택 모드 상태에서는 화면을 다시 그려줄 수 없다. 선택 모드를 빠져 나올 때 OpenGL은 관측 공간을 교차하는 프리미티브 리스트를 반환 관측 공간은 현재 모델 뷰와 투영 행렬 및 부가적인 클리핑 평면으로 정의 각각의 관측 공간을 교차하는 프리미티브들은 선택 히트(hit)를 만들어낸다. 프리미티브 리스트는 정수형 값으로 된 네임과 현재 네임 스택의 내용과 일치하는 히트 레코드로 구성된 배열을 반환 반환된 네임 리스트를 통해 사용자가 화면상에서 어떠한 프리미티브를 선택했는지 결정할 수 있다. OpenGL은 선택 메커니즘 외에 그림을 뷰포트의 작은 영역에만 그리도록 제한하여 선택을 간단히 처리할 수 있는 유틸리티 제공 2009-2학기 가상현실
선 택 모 드 기 본 순 서 선택 메커니즘을 사용하기 위해서는 다음과 같은 단계를 밟아야 함 glSelectBuffer()에서 히트 레코드를 반환할 때 사용할 배열을 설정 glRenderMode()에 GL_SELECT를 입력해서 선택 모드로 들어감 glInitNames()와 glPushName()을 이용, 네임 스택을 초기화 선택모드에서 사용할 관측 공간을 정의 glPushMatrix()와 glPopMatrix()로 변환상태를 저장한 후 나중에 되돌려 받음. 중요한 프리미티브에 적절한 네임을 부여하기 위해서 프리미티브를 그리는 커맨드와 네임 스택을 관리하는 커맨드를 번갈아 실행 선택 모드에서 빠져나간 뒤, 반환된 히트 레코드를 처리 2009-2학기 가상현실
void glSelectBuffer(GLsizei size, GLuint *buffer); 반환된 선택 데이터를 저장할 배열을 설정 buffer 인자는 데이터가 저장될 unsigned int형 배열에 대한 포인터를 지정 size는 배열에 저장될 수 있는 값의 최대 숫자를 지정 void glRenderMode(GLenum mode); 응용프로그램이 렌더링 모드에 있는지, 선택 모드에 있는지, 피드백 모드에 있는지를 제어 mode 인자는 GL_RENDER(기본값)나 GL_SELECT, GLFEEDBACK 중에 하나의 값으로 지정 glGetIntegerv(GL_RENDER_MODE)호 현재 모드 확인 2009-2학기 가상현실
네임 스택 만들기 네임 스택은 반환되는 선택 정보의 토대가 된다. 네임스택을 만들기 위해서는 먼저 스택을 단순히 클리어 해주는 glInitNames()함수를 이용해서 스택을 초기화 드로잉 커맨드를 호출할 대마다 이에 대한 정수형 네임을 추가 void glInitNames(void) 스택을 클리어해서 네임 스택을 비우는 일을 함 void glPushName(GLUint name); Name 인자로 지정된 네임을 네임 스택에 넣어준다. 스택이 꽉 찬 상태에서 네임을 추가하면 GL_STACK_OVERFLOW 발생 네임스택의 깊이는 glGetIntegerv(GL_NAME_STACK_DEPTH)로 확인 2009-2학기 가상현실
void glPopName(void); 네임 스택에서 네임 하나를 꺼낸다. 스택이 비어 있는 상태에서 네임을 꺼내려고 시도하면 GL_STACK_UNDERFLOW 에러가 발생 void glLoadName(GLUint name); 이 함수는 네임 스택의 top에 저장된 이름을 name 인자로 지정한 이름으로 바꾼다. 스택이 비어 있을 때 이 함수를 호출하면 GL_INVALID_OPERATION이라는 에러 발생 2009-2학기 가상현실
예제 13-1 네임스택 만들기 glInitNames(); glPushName(0); glPushMatrix(): /* 현재 변환 상태를 저장한다. */ /* 원하는 뷰잉 볼륨을 여기서 만들어준다 */ .. glLoadName(1); drawSomeObject(); glLoadName(2); drawAnotherObject(); glLoadName(3); drawYetAnotherObject(): drawJustOneMoreObject(); glPopMatrix(); /* 이전 변환 상태를 다시 읽어온다. */ 2009-2학기 가상현실
히트 레코드 선택 모드에서 관측 공간을 교차하는 프리미티브는 선택 히트를 발생 스택을 조작했거나, glRenderMode()함수가 호출된 뒤, 네임 스택 조작 커맨드나 glRenderMode()가 호출되면 OpenGL은 선택 배열에 히트 레코드를 기록한다. 히트 레코드는 glRenderMode()가 호출되기 전까지 배열에 저장되지 않는다. 모든 히트 기록은 다음과 같은 4가지 요소로 구성되며, 다음과 같은 순서로 저장 히트가 발생했을 때 네임 스택에 저장된 네임의 수 마지막으로 저장된 히트 이후에 발생하는 관측 공간을 가로지르는 프리미티브에 대한 모든 정점의 z좌표의 최대, 최소값 히트가 발생했을 때 네임 스택에 있던 내용들(bottom 부터 시작) 2009-2학기 가상현실
예제 13-2 선택 모드: select.c #include <GL/glut.h> #include <stdlib.h> #include <stdio.h> void drawTriangle (GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2, GLfloat x3, GLfloat y3, GLfloat z) { glBegin (GL_TRIANGLES); glVertex3f (x1, y1, z); glVertex3f (x2, y2, z); glVertex3f (x3, y3, z); glEnd (); } 2009-2학기 가상현실
void drawViewVolume (GLfloat x1, GLfloat x2, GLfloat y1, GLfloat y2, GLfloat z1, GLfloat z2){ glColor3f (1.0, 1.0, 1.0); glBegin (GL_LINE_LOOP); glVertex3f (x1, y1, -z1); glVertex3f (x2, y1, -z1); glVertex3f (x2, y2, -z1); glVertex3f (x1, y2, -z1); glEnd (); glVertex3f (x1, y1, -z2); glVertex3f (x2, y1, -z2); glVertex3f (x2, y2, -z2); glVertex3f (x1, y2, -z2); 2009-2학기 가상현실
glBegin (GL_LINES); /* 4 lines */ glVertex3f (x1, y1, -z1); glEnd (); } 2009-2학기 가상현실
glMatrixMode (GL_PROJECTION); glLoadIdentity (); void drawScene (void) { glMatrixMode (GL_PROJECTION); glLoadIdentity (); gluPerspective (40.0, 4.0/3.0, 1.0, 100.0); glMatrixMode (GL_MODELVIEW); gluLookAt (7.5, 7.5, 12.5, 2.5, 2.5, -5.0, 0.0, 1.0, 0.0); glColor3f (0.0, 1.0, 0.0); /* green triangle */ drawTriangle (2.0, 2.0, 3.0, 2.0, 2.5, 3.0, -5.0); glColor3f (1.0, 0.0, 0.0); /* red triangle */ drawTriangle (2.0, 7.0, 3.0, 7.0, 2.5, 8.0, -5.0); glColor3f (1.0, 1.0, 0.0); /* yellow triangles */ 2009-2학기 가상현실
void processHits (GLint hits, GLuint buffer[]) { unsigned int i, j; drawTriangle (2.0, 2.0, 3.0, 2.0, 2.5, 3.0, -1.0); drawTriangle (2.0, 2.0, 3.0, 2.0, 2.5, 3.0, -9.0); drawViewVolume (0.0, 5.0, 0.0, 5.0, 0.0, 10.0); } void processHits (GLint hits, GLuint buffer[]) { unsigned int i, j; GLuint names, *ptr; printf ("hits = %d\n", hits); ptr = (GLuint *) buffer; 2009-2학기 가상현실
for (i = 0; i < hits; i++) { /* for each hit */ names = *ptr; printf (" number of names for hit = %d\n", names); ptr++; printf(" z1 is %g;", (float) *ptr/0x7fffffff); ptr++; printf(" z2 is %g\n", (float) *ptr/0x7fffffff); ptr++; printf (" the name is "); for (j = 0; j < names; j++) { /* for each name */ printf ("%d ", *ptr); ptr++; } printf ("\n"); 2009-2학기 가상현실
void selectObjects(void) { GLuint selectBuf[BUFSIZE]; GLint hits; #define BUFSIZE 512 void selectObjects(void) { GLuint selectBuf[BUFSIZE]; GLint hits; glSelectBuffer (BUFSIZE, selectBuf); (void) glRenderMode (GL_SELECT); glInitNames(); glPushName(0); glPushMatrix (); glMatrixMode (GL_PROJECTION); glLoadIdentity (); glOrtho (0.0, 5.0, 0.0, 5.0, 0.0, 10.0); 2009-2학기 가상현실
glMatrixMode (GL_MODELVIEW); glLoadIdentity (); glLoadName(1); drawTriangle (2.0, 2.0, 3.0, 2.0, 2.5, 3.0, -5.0); glLoadName(2); drawTriangle (2.0, 7.0, 3.0, 7.0, 2.5, 8.0, -5.0); glLoadName(3); drawTriangle (2.0, 2.0, 3.0, 2.0, 2.5, 3.0, -1.0); drawTriangle (2.0, 2.0, 3.0, 2.0, 2.5, 3.0, -9.0); glPopMatrix (); glFlush (); hits = glRenderMode (GL_RENDER); processHits (hits, selectBuf); } 2009-2학기 가상현실
glEnable(GL_DEPTH_TEST); glShadeModel(GL_FLAT); } void display(void) void init (void) { glEnable(GL_DEPTH_TEST); glShadeModel(GL_FLAT); } void display(void) glClearColor (0.0, 0.0, 0.0, 0.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); drawScene (); selectObjects (); glFlush(); 2009-2학기 가상현실
void keyboard(unsigned char key, int x, int y) { switch (key) { case 27: exit(0); break; } 2009-2학기 가상현실
int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize (200, 200); glutInitWindowPosition (100, 100); glutCreateWindow (argv[0]); init(); glutDisplayFunc(display); glutKeyboardFunc(keyboard); glutMainLoop(); return 0; } 2009-2학기 가상현실
피킹 물체가 피킹되었는지 검사하기 위해서는 커서 부근과 같은 뷰포트의 작은 영역에 그리기를 제한하기 위해 피킹 행렬과 투영행렬을 만들어야 함 그 다음 마우스 버튼과 클릭과 같은 특정 형태의 입력을 받을 수 있도록 선택 모드를 초기화 특수한 피킹 행렬을 사용하면 커서 근처에 그려진 물체는 선택 히트를 발생시키게 된다. 피킹하는 동안 어떤 물체가 커서 근처에 그려져 있는지를 결정할 수 있다. 2009-2학기 가상현실
피킹은 다음과 같은 차이점을 제외하면 일반적인 선택 모드와 거의 같다 피킹은 다음과 같은 차이점을 제외하면 일반적인 선택 모드와 거의 같다 현재 투영 행렬과 피킹 행렬을 곱하기 위해서 gluPickMatrix()라는 루틴 사용. gluPerspective()나 glOrtho()와 같은 표준 투영 행렬을 곱하기 전에 호출 다음의 순서로 작업 진행 glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); gluPickMatrix(…); gluPerspective, glOrtho, gluOrtho2D, or glFrustum // 피킹할 장면을 그리고 피킹을 수행 glPopMatrix(); 2009-2학기 가상현실
뷰포트의 작은 영역에 그리기를 제한하기 위해 투영 행렬을 만듬 이를 현재 행렬 스택에 있는 행렬에 곱한다. void gluPickMatrix(GLdouble x, GLdouble y, GLdouble width, GLdouble height, GLint viewport[4]); 뷰포트의 작은 영역에 그리기를 제한하기 위해 투영 행렬을 만듬 이를 현재 행렬 스택에 있는 행렬에 곱한다. 피킹된 지역의 중심은 (x, y)로 나타내는데 이 좌표는 커서의 위치와 같다. width, height는 스크린 좌표계에서 피킹된 지역의 크기를 결정한다. 피킹 장치의 민감도. viewport[]는 현재 뷰포트의 경계를 뜻함. 다음으로 알아낼 수 있다 glGetIntegerv(GL_VIEWPORT, GLint *viewport); 2009-2학기 가상현실
예제 13-3 피킹 예제: picksquare.c #include <GL/glut.h> #include <stdlib.h> #include <stdio.h> int board[3][3]; void init(void) { int i, j; for (i = 0; i < 3; i++) for (j = 0; j < 3; j ++) board[i][j] = 0; glClearColor (0.0, 0.0, 0.0, 0.0); } 2009-2학기 가상현실
void drawSquares(GLenum mode){ GLuint i, j; for (i = 0; i < 3; i++) { if (mode == GL_SELECT) glLoadName (i); for (j = 0; j < 3; j ++) { glPushName (j); glColor3f ((GLfloat) i/3.0, (GLfloat) j/3.0, (GLfloat) board[i][j]/3.0); glRecti (i, j, i+1, j+1); glPopName (); } } 2009-2학기 가상현실
void processHits (GLint hits, GLuint buffer[]) { unsigned int i, j; GLuint ii, jj, names, *ptr; printf ("hits = %d\n", hits); ptr = (GLuint *) buffer; for (i = 0; i < hits; i++) { /* for each hit */ names = *ptr; printf (" number of names for this hit = %d\n", names); ptr++; printf(" z1 is %g;", (float) *ptr/0x7fffffff); ptr++; printf(" z2 is %g\n", (float) *ptr/0x7fffffff); ptr++; printf (" names are "); 2009-2학기 가상현실
for (j = 0; j < names; j++) { /* for each name */ printf ("%d ", *ptr); if (j == 0) /* set row and column */ ii = *ptr; else if (j == 1) jj = *ptr; ptr++; } printf ("\n"); board[ii][jj] = (board[ii][jj] + 1) % 3; 2009-2학기 가상현실
void pickSquares(int button, int state, int x, int y) { #define BUFSIZE 512 void pickSquares(int button, int state, int x, int y) { GLuint selectBuf[BUFSIZE]; GLint hits; GLint viewport[4]; if (button != GLUT_LEFT_BUTTON || state != GLUT_DOWN) return; glGetIntegerv (GL_VIEWPORT, viewport); glSelectBuffer (BUFSIZE, selectBuf); (void) glRenderMode (GL_SELECT); 2009-2학기 가상현실
glMatrixMode (GL_PROJECTION); glPushMatrix (); glLoadIdentity (); glInitNames(); glPushName(0); glMatrixMode (GL_PROJECTION); glPushMatrix (); glLoadIdentity (); gluPickMatrix ((GLdouble) x, (GLdouble) (viewport[3] - y), 5.0, 5.0, viewport); gluOrtho2D (0.0, 3.0, 0.0, 3.0); drawSquares (GL_SELECT); glPopMatrix (); glFlush (); 2009-2학기 가상현실
hits = glRenderMode (GL_RENDER); processHits (hits, selectBuf); glutPostRedisplay(); } void display(void) { glClear(GL_COLOR_BUFFER_BIT); drawSquares (GL_RENDER); glFlush(); 2009-2학기 가상현실
void reshape(int w, int h){ glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D (0.0, 3.0, 0.0, 3.0); glMatrixMode(GL_MODELVIEW); } void keyboard(unsigned char key, int x, int y){ switch (key) { case 27: exit(0); break; 2009-2학기 가상현실
int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB); glutInitWindowSize (100, 100); glutInitWindowPosition (100, 100); glutCreateWindow (argv[0]); init (); glutReshapeFunc (reshape); glutDisplayFunc(display); glutMouseFunc (pickSquares); glutKeyboardFunc (keyboard); glutMainLoop(); return 0; } 2009-2학기 가상현실
2009-2학기 가상현실
다중 네임은 장면에서 계층화된 모델의 일부를 선택할 때도 사용할 수 있다. 다중 네임과 계층화 된 모델을 이용한 피킹 다중 네임은 장면에서 계층화된 모델의 일부를 선택할 때도 사용할 수 있다. 예를 들어 일렬로 놓여 있는 자동차를 렌더링 하는 경우 사용자가 3번째 자동차의 왼쪽 앞바퀴의 3번째 볼트를 마우스로 찍어서 움직일 수 있게 하고 싶은 경우 이때 어떤 차인지, 어떤 바퀴인지, 어떤 볼트인지에 대해서 계층들의 각 레벨을 구별하기 위해서 서로 다른 이름을 사용해야 한다 2009-2학기 가상현실
피킹과 깊이값 예제 13 – 6(pickdepth.c)은 어떤 물체가 뽑혔는지 결정하기 위해서 깊이값을 사용하는 방법을 보여줌 깊이값을 이용한 피킹 [ 13 – 6 ] #include <GL/glut.h> #include <stdlib.h> #include <stdio.h> void init(void){ glClearColor(0.0, 0.0, 0.0, 0.0); glEnable(GL_DEPTH_TEST); glShadeModel(GL_FLAT); glDepthRange(0.0, 1.0); /* The default z mapping */ } 2009-2학기 가상현실
void drawRects(GLenum mode) { if (mode == GL_SELECT) glLoadName(1); glBegin(GL_QUADS); glColor3f(1.0, 1.0, 0.0); glVertex3i(2, 0, 0); glVertex3i(2, 6, 0); glVertex3i(6, 6, 0); glVertex3i(6, 0, 0); glEnd(); glLoadName(2); 2009-2학기 가상현실
glColor3f(0.0, 1.0, 1.0); glVertex3i(3, 2, -1); glVertex3i(3, 8, -1); glEnd(); if (mode == GL_SELECT) glLoadName(3); glBegin(GL_QUADS); glColor3f(1.0, 0.0, 1.0); glVertex3i(0, 2, -2); glVertex3i(0, 7, -2); glVertex3i(5, 7, -2); glVertex3i(5, 2, -2); } 2009-2학기 가상현실
void processHits(GLint hits, GLuint buffer[]) { unsigned int i, j; GLuint names, *ptr; printf("hits = %d\n", hits); ptr = (GLuint *) buffer; for (i = 0; i < hits; i++) { /* for each hit */ names = *ptr; printf(" number of names for hit = %d\n", names); ptr++; printf(" z1 is %g;", (float) *ptr/0x7fffffff); ptr++; printf(" z2 is %g\n", (float) *ptr/0x7fffffff); ptr++; printf(" the name is "); 2009-2학기 가상현실
for (j = 0; j < names; j++) { /* for each name */ printf("%d ", *ptr); ptr++; } printf("\n"); #define BUFSIZE 512 void pickRects(int button, int state, int x, int y) { GLuint selectBuf[BUFSIZE]; GLint hits; GLint viewport[4]; if (button != GLUT_LEFT_BUTTON || state != GLUT_DOWN) return; 2009-2학기 가상현실
glGetIntegerv(GL_VIEWPORT, viewport); glSelectBuffer(BUFSIZE, selectBuf); (void) glRenderMode(GL_SELECT); glInitNames(); glPushName(0); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); gluPickMatrix((GLdouble) x, (GLdouble) (viewport[3] - y), 5.0, 5.0, viewport); 2009-2학기 가상현실
drawRects(GL_SELECT); glPopMatrix(); glFlush(); glOrtho(0.0, 8.0, 0.0, 8.0, -0.5, 2.5); drawRects(GL_SELECT); glPopMatrix(); glFlush(); hits = glRenderMode(GL_RENDER); processHits(hits, selectBuf); } void display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); drawRects(GL_RENDER); 2009-2학기 가상현실
void reshape(int w, int h){ glViewport(0, 0, (GLsizei) w, (GLsizei) h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0.0, 8.0, 0.0, 8.0, -0.5, 2.5); glMatrixMode(GL_MODELVIEW); } void keyboard(unsigned char key, int x, int y) { switch (key) { case 27: exit(0); break; } 2009-2학기 가상현실
int main(int argc, char **argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize (200, 200); glutInitWindowPosition (100, 100); glutCreateWindow(argv[0]); init(); glutReshapeFunc(reshape); glutDisplayFunc(display); glutMouseFunc(pickRects); glutKeyboardFunc(keyboard); glutMainLoop(); return 0; } 2009-2학기 가상현실
2009-2학기 가상현실
2차원 물체와 바운딩하고 있는 박스를 더 쉽고 빠르게 찾기 위하여 박스들을 계층화된 데이터구조로 구성하는 경우가 있다. 선택을 사용하는 프로그램을 만들기 위한 힌트 2차원 물체와 바운딩하고 있는 박스를 더 쉽고 빠르게 찾기 위하여 박스들을 계층화된 데이터구조로 구성하는 경우가 있다. 히트는 오직 기하학적 물체에서만 발생하기 대문에 문자 피킹 메소드를 따로 만들어야 하는 경우 이 경우 현재 래스터 위치를 설정하는 기하학적 명령을 이용 문자의 하단 좌측 모서리와 같은 문자를 피킹하기 위해 포인트를 만들어낼 수 있다. OpenGL의 피킹를 사용할 경우에는 선택 모드와 기본 그리기 모드에서 물체의 리스트를 그리기 쉽도록 프로그램과 데이터구조를 구성해야 한다. 2009-2학기 가상현실
아이템이 선택되었는지, 아닌지 나타내기 위해 각각의 아이템 당 하나의 비트를 저장하는 방법을 사용 사용자가 복합적인 물체를 선택하는 경우 아이템이 선택되었는지, 아닌지 나타내기 위해 각각의 아이템 당 하나의 비트를 저장하는 방법을 사용 선택된 아이템을 찾기 위해서 아이템 리스트 전체를 뒤져야 하기 때문에 아이템을 가리키는 리스트를 사용해서 검색 속도를 높임 아이템별로 선택 비트를 관리하면 선택된 아이템들만 다르게 그리는 것이 가능 2009-2학기 가상현실
선택의 사용자 인터페이스는 기본적으로 다음 기능을 제공해야 함 아이템 선택 가능 여러 아이템들을 한 번에 선택하게 해주는 기능 이미 선택된 아이템들에 하나의 아이템을 추가하는 기능 한 번에 여러 아이템을 선택해서 이미 선택된 아이템들에 추가하는 기능 선택 아이템들 중, 특정 아이템을 선택, 취소할 수 있는 기능 오버래핑된 아이템들의 그룹 중에서 하나의 아이템들만을 선택할 수 있는 기능 2009-2학기 가상현실
2차원 그리기 프로그램에서 이 요구 사항들을 구현하는 방법은 다음과 같다. 모든 선택은 물체를 마우스 커서로 가리킨 후에 마우스 왼쪽 버튼을 누름으로써 이루어짐 아이템 위에서 클릭하는 것은 아이템을 선택하거나, 선택된 아이템을 선택해제 하는 역할을 한다. 아이템이 없는 곳에서 마우스 버튼을 누른 채로 마우스를 끌면 화면에 화면 정렬을 위한 직사각형이 그려짐 <shift>키가 눌려진 상태에서 사용자가 아직 선택되지 않은 채로 남아있는 아이템을 클릭했을 경우 클릭한 아이템이 선택 리스트에 포함되어야 함 2009-2학기 가상현실
만약 <shift>키가 눌려진 상태에서 일괄 선택이 이루어졌을 경우, 일관선택된 아이템들을 선택 리스트에 포함 아이템들이 많이 어지럽혀진 영역에서는 아이템을 일괄 선택하는 것이 힘들다. 이러한 문제를 해결하기 위해 <alt>키를 이용해서 강제적으로 일괄 선택 모드로 돌아가게 함 이 동작을 수행중에 <shift>가 눌러졌다면 일괄 선택된 아이템들이 이미 선택되어 있던 아이템에 추가 마지막으로 사용자가 복합적인 아이템 위에서 클릭하는 경우, 이 경우에도 선택되는 아이템은 하나여야 한다. 만일 커서가 움직이지 않고 사용자가 같은 장소를 클릭하면 다음 아이템을 선택한다 2009-2학기 가상현실
피 드 백 모 드 선택모드와 피드백 모드의 공통점 각 모드에 들어가면 픽셀을 만들어 내지 않고 화면이 정지해 있음 각 모드에 들어가면 픽셀을 만들어 내지 않고 화면이 정지해 있음 선택모드와 피드백 모드의 결정적인 차이점 돌려받는 정보 선택 모드: 할당된 이름이 정수형의 배열로 반환 피드백 모드 : 변화된 프리미티브에 대한 정보가 부동 소수점 형의 배열로 반환 2009-2학기 가상현실
피드백 배열로 반환되는 데이터들은 토큰으로 구성되어 있는데, 이 토큰은 어떤 종류의 프리미티브(점, 선, 폴리곤, 이미지, 비트맵 등)가 처리되었고, 변환되었으며 이 프리미티브에 속한 정점과 컬러나 또 다른 데이터들로 무엇이 있는지를 설명 반환되는 값들은 라이팅과 뷰잉 처리가 끝난 값들이다. 피드백 모드는 glRenderMode(GL_FEEDBACK)을 이용하여 초기화된다. 2009-2학기 가상현실
피드백 모드에 들어가는 방법과 빠져나오는 방법 피드백 정보를 담기 위한 배열을 설정하기 위해 glFeedbackBuffer()를 호출 glRenderMode()에 GL_FEEDBACK 인자를 전달시켜서 호출하면 피드백 모드로 들어감 프리미티브를 그리는 단계이다. 이단계에서는 그리기 명령이 진행되는 동안 이후의 파싱을 돕기 위해 glPassThrough()함수를 이용해서 반환된 피드백 데이터에 마커를 삽입 가능 glRenderMode()에 GL_RENDER인자를 전달해서 호출하면 일반 그리기 모드로 빠져나간다. 마지막으로 피드백 배열에 있는 값을 파싱 2009-2학기 가상현실
void glFeedbackBuffer(GLsizei size, GLenum type, GLfloat *buffer); 피드백 데이터를 위해 버퍼를 만들어주는 함수로, 피드백 모드에 들어가기 전에 호출되어야 함 buffer는 데이터가 저장되어 있는 배열을 가리키는 포인터 size 매개변수는 배열에 저장될 수 있는 값들의 최대 개수 type은 피드백 배열에 있는 각 정점에 대해서 피드백된 정보 설명 2009-2학기 가상현실
glFeedbackBuffer()의 type값들 k 가 1이면 컬러인덱스 모드, 4이면 RGBA 모드 Type argument Coordinate Color Texture Total values GL_2D x, y - 2 GL_3D x, y, z 3 GL_3D_COLOR k 3 + k GL_3D_COLOR_TEXTURE 4 7 + k GL_4D_COLOR_TEXTURE x, y, z , w 8 + k 2009-2학기 가상현실
피드백 배열 피드백 모드에서 래스터화될 각 프리미티브는 피드백 배열에 복사해 놓았던 값이 들어 있는 블록을 만들어 냄 값의 개수는 위의 표에 나와있는 것처럼 type인자에 따라 결정 피드백값의 블록은 프리미티브의 타입을 알려주는 코드로 시작 그 뒤쪽에 프리미티브의 정점이나 관련 데이터들에 대한 정보가 들어있다. 2009-2학기 가상현실
피드백 배열 구문 프리미티브 타입 코드 관련 데이터 점 GL_POINT_TOKEN 정점 선 GL_LINE_TOKEN 혹은 GL_LINE_RESET_TOKEN 정점 정점 폴리곤 GL_POLYGON_TOKEN N 정점 정점…정점 비트맵 GL_BITMAP_TOKEN 픽셀 사각형 GL_DRAW_PIXEL_TOKEN 혹은 GL_COPY_PIXEL_TOKEN 패스-스루 GL_PASS_THROUGH_TOKEN 부동 소수형 숫자 2009-2학기 가상현실
피드백은 glPolygonMode()에 의해서 변환이나 라이팅, 폴리곤 컬링, 폴리곤 해석이 일어난 후에 발생한다. 피드백 모드에서 마커 사용하기 피드백은 glPolygonMode()에 의해서 변환이나 라이팅, 폴리곤 컬링, 폴리곤 해석이 일어난 후에 발생한다. 또한, 3개 이상의 변으로 이루어진 폴리곤이 삼각형으로 쪼개진 후에도 피드백이 발생한다. 피드백 데이터를 받았을 때 이 데이터들 사이에서 필요한 프리미티브를 찾아내는 것이 쉽지 않다. 마커를 넣으면 반환된 피드백 데이터들을 각기 다른 프리미티브들로 쉽게 구분 가능 2009-2학기 가상현실
void glPassThrough(GLfloat token); 피드백 모드에서 호출되었을 경우 피드백 배열에 들어가는 일련의 값들 사이에 마커를 넣어줌 이 마커는 GL_PASS_THROUGH_TOKEN 이라는 코드로 구성되어 있으며 이 코드에는 token 인자로 넘어가는 부동소수점 값이 따라 붙는다. glBegin()과 glEnd() 사이에서 호출되면 GL_INVALID_OPERATION 에러 발생 2009-2학기 가상현실
예제 13-7 피드백 모드 예제: feedback.c #include <GL/glut.h> #include <stdlib.h> #include <stdio.h> void init(void) { glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); } 2009-2학기 가상현실
void drawGeometry (GLenum mode) { glBegin (GL_LINE_STRIP); glNormal3f (0.0, 0.0, 1.0); glVertex3f (30.0, 30.0, 0.0); glVertex3f (50.0, 60.0, 0.0); glVertex3f (70.0, 40.0, 0.0); glEnd (); if (mode == GL_FEEDBACK) glPassThrough (1.0); glBegin (GL_POINTS); glVertex3f (-100.0, -100.0, -100.0); 2009-2학기 가상현실
if (mode == GL_FEEDBACK) glPassThrough (2.0); glBegin (GL_POINTS); glNormal3f (0.0, 0.0, 1.0); glVertex3f (50.0, 50.0, 0.0); glEnd (); } void print3DcolorVertex (GLint size, GLint *count, GLfloat *buffer) { int i; 2009-2학기 가상현실
printf ("%4.2f ", buffer[size-(*count)]); *count = *count - 1; } for (i = 0; i < 7; i++) { printf ("%4.2f ", buffer[size-(*count)]); *count = *count - 1; } printf ("\n"); void printBuffer(GLint size, GLfloat *buffer) { GLint count; GLfloat token; 2009-2학기 가상현실
token = buffer[size-count]; count--; count = size; while (count) { token = buffer[size-count]; count--; if (token == GL_PASS_THROUGH_TOKEN) { printf ("GL_PASS_THROUGH_TOKEN\n"); printf (" %4.2f\n", buffer[size-count]); count--; } else if (token == GL_POINT_TOKEN) { printf ("GL_POINT_TOKEN\n"); print3DcolorVertex (size, &count, buffer); 2009-2학기 가상현실
else if (token == GL_LINE_TOKEN) { printf ("GL_LINE_TOKEN\n"); print3DcolorVertex (size, &count, buffer); } else if (token == GL_LINE_RESET_TOKEN) { printf ("GL_LINE_RESET_TOKEN\n"); 2009-2학기 가상현실
GLfloat feedBuffer[1024]; GLint size; glMatrixMode (GL_PROJECTION); void display(void) { GLfloat feedBuffer[1024]; GLint size; glMatrixMode (GL_PROJECTION); glLoadIdentity (); glOrtho (0.0, 100.0, 0.0, 100.0, 0.0, 1.0); glClearColor (0.0, 0.0, 0.0, 0.0); glClear(GL_COLOR_BUFFER_BIT); drawGeometry (GL_RENDER); 2009-2학기 가상현실
glFeedbackBuffer (1024, GL_3D_COLOR, feedBuffer); (void) glRenderMode (GL_FEEDBACK); drawGeometry (GL_FEEDBACK); size = glRenderMode (GL_RENDER); printBuffer (size, feedBuffer); } void keyboard(unsigned char key, int x, int y){ switch (key) { case 27: exit(0); break; 2009-2학기 가상현실
int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); glutInitWindowSize (100, 100); glutInitWindowPosition (100, 100); glutCreateWindow(argv[0]); init(); glutDisplayFunc(display); glutKeyboardFunc (keyboard); glutMainLoop(); return 0; } 2009-2학기 가상현실
2009-2학기 가상현실