기하학적 객체와 변환
좌표계와 프레임 e v a + = 좌표계 (coordinate systems) : 기저 벡터 v 원점은 ? e 3 2 1 3
공통된 점으로부터 나온 벡터에 의한 좌표계 옮겨진 벡터에 의한 좌표계
프레임 (frames) : 기저벡터 + 참조점 1 e 2 3 v å = i e v a 벡터 å + = i e P a 점
좌표계의 변경
v
동차 좌표
프레임과 ADT point3 p, q; vector3 v, u; q = p + v; u = p – q; 객체 지향 언어 q = v; u = p + q; /* error */ typedef float point3[4]; /* 4차원 배열을 사용한 동차 좌표 표현 */ typedef float point2[4]; /* 삼차원 그래픽스의 특수한 경우로 취급 */ p = new_point3(1.0, 2.0, 3.0); vector3 v; frame f; v = point_sub(p, q, f); 객체 지향 언어
OpenGL에서의 프레임 카메라 프레임, 세계 프레임 d 디폴트 위치 모델-관측 행렬을 적용한 후
OpenGL에서의 프레임 모델-관측 행렬 점과 벡터의 동차 좌표 표현을 카메라 프레임에서의 표현으로 변환 glLoadMatrix에 16원소의 배열을 보냄으로써 모델-관측 행렬 설정 회전, 이동, 크기 변환 등의 일련의 기하학적인 변환들에 의해서 하나의 프레임에서 다른 프레임으로 변환 세계 프레임에서 점 카메라 프레임에서 점
색 입방체 모델링 회전하는 입방체 그리기 모델링 카메라 프레임으로 변환 절단 투영 은면 제거 래스터화
입방체의 모델링 다른 다섯 면도 같은 방법으로 정의 OpenGL은 모든 정점들을 4차원 동차 좌표로 구현 typedef GLfloat point3[3]; point3 vertices[8] ={{-1.0, -1.0, -1.0}, {1.0, -1.0, -1.0}, {1.0, 1.0, -1.0}, {-1.0, 1.0, -1.0}, {-1.0, -1.0, 1.0}, {1.0, -1.0, 1.0}, {1.0, 1.0, 1.0}, {-1.0, 1.0, 1.0}}; glBegin(GL_POLYGON); glVertex3fv(vertices[0]); glVertex3fv(vertices[3]); glVertex3fv(vertices[2]); glVertex3fv(vertices[1]); glEnd(); 다른 다섯 면도 같은 방법으로 정의 OpenGL은 모든 정점들을 4차원 동차 좌표로 구현
내향면과 외향면 외부로 향하는 면 (outward facing) 정점들이 반시계 방향 순서로 순회 오른손 법칙 0, 3, 2, 1 = 1, 0, 3, 2 (외향면) 0, 1, 2, 3 (내향면)
객체 표현을 위한 데이터 구조 기하학적 모양 (geometry) VS 위상 (topology) 정점 리스트 표현 장점 : 기하학적 위치가 면에 사용될 때 단지 한번만 나타남
색 입방체 typedef GLfloat point3[3]; point3 vertices[8] ={{-1.0, -1.0, -1.0}, {1.0, -1.0, -1.0}, {1.0, 1.0, -1.0}, {-1.0, 1.0, -1.0}, {-1.0, -1.0, 1.0}, {1.0, -1.0, 1.0}, {1.0, 1.0, 1.0}, {-1.0, 1.0, 1.0}}; GLfloat colors[8][3] ={{0.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, {1.0, 1.0, 0.0}, {0.0, 1.0, 0.0}, {0.0, 0.0, 1.0}, {1.0, 0.0, 1.0}, {1.0, 1.0, 1.0}, {0.0, 1.0, 1.0}}; void quad(int a, int b, int c, int d) { glBegin(GL_POLYGON); glColor3fv(colors[a]); glVertex3fv(vertices[a]); glColor3fv(colors[b]); glVertex3fv(vertices[b]);
색 입방체 glColor3fv(colors[c]); glVertex3fv(vertices[c]); glColor3fv(colors[d]); glVertex3fv(vertices[d]); glEnd(); } void colorcube() { quad(0, 3, 2, 1); quad(2, 3, 7, 6); quad(0, 4, 7, 3); quad(1, 2, 6, 5); quad(4, 5, 6, 7); quad(0, 1, 5, 4);
쌍일차 보간 쌍일차 보간 (bilinear interpolation) 가 0에서 1까지 변함 가 0에서 1까지 변함 네 정점이 같은 평면에 있지 않다면 표면에서의 위치가 명확히 정의 되지 않음
주사선 보간 주사선 보간 (scan-line interpolation) 이차원으로 투영된 후에 보간 평면성 문제 해결 주사 변환 처리의 일부로 만들 수 있음 OpenGL 에서 사용
정점 배열 정점 배열 (vertex array) OpenGL에서 허용하는 배열의 형 몇 번의 함수 호출만으로 다면체 객체를 그릴 수 있도록 데이터 구조에 있는 정보를 캡슐화 1 단계 : 정점 배열의 기능을 인에이블 2 단계 : 정점 배열의 위치 및 형식을 OpenGL에 알림 3 단계 : 객체 렌더링 OpenGL에서 허용하는 배열의 형 정점, 색, 색 인덱스, 법선, 텍스처 좌표, 변 플래그(edge flag)
정점 배열 glEnableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_VERTEX_ARRAY); GLfloat vertices[] ={{-1.0, -1.0, -1.0}, {1.0, -1.0, -1.0}, {1.0, 1.0, -1.0}, {-1.0, 1.0, -1.0}, {-1.0, -1.0, 1.0}, {1.0, -1.0, 1.0}, {1.0, 1.0, 1.0}, {-1.0, 1.0, 1.0}}; GLfloat colors[] ={{0.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, {1.0, 1.0, 0.0}, {0.0, 1.0, 0.0}, {0.0, 0.0, 1.0}, {1.0, 0.0, 1.0}, {1.0, 1.0, 1.0}, {0.0, 1.0, 1.0}}; glVertexPointer(3, GL_FLOAT, 0, vertices); glColorPointer(3, GL_FLOAT, 0, colors); 3: 3차원, GL_FLOAT : 타입, 0 : 연속적, vertices and colors : 배열 포인터
정점 배열 여섯개의 면에 대한 24개의 순서를 갖는 정점 인덱스 배열 지정 GLubyte cubeIndices[24] = { 0, 3, 2, 1, 2, 3, 7, 6, 0, 4, 7, 3, 1, 2, 6, 5, 4, 5, 6, 7, 0, 1, 5, 4 } - 첫번째 면 (0,3,2,1) 두번째 면 (2,3,7,6) : 외향면이 되도록 주의 glDrawElements(type, n, format, pointer); type : 배열이 정의하는 선이나 다각형과 같은 원소의 형 n : 원소의 개수 format : 인덱스 배역에 있는 데이터의 형식 pointer : 사용할 첫번째 인덱스 for(i=0; i<6; i++) glDrawElements(GL_POLYGON, 4, GL_UNSIGNED_BYTE, &cubeIndex[4*i]); => 함수 6번 호출 glDrawElements(GL_QUAD, 24, GL_UNSIGNED_BYTE, cubeIndices); => 함수 1번 호출
어파인 변환 변환 (transformation)
선형 변환 (linear transformation) 두 벡터의 합 -> 변환 = 각 벡터의 변환 -> 합 벡터와 스칼라의 곱 -> 변환 = 벡터의 변환 -> 스칼라 곱 P = f (P) P = f (P1 + P2) = f( P1) + f(P2) 정점들의 선형조합 변환된 정점들의 선형조합
행렬 표현 P = f (P) P = M P v = f (v) v = M v 정방행렬(square matrix)은 선형 변환을 의미함 선형 변환은 직선 보존 (straight and parallel lines) 그러나 이동은 포함하지 않음. 즉, 원점이 이동되지 않음 선형변환에서 길이, 각도, 면적, 볼륨과 같은 다른 기하학적 특성은 변경됨
어파인 변환 (affine transformation) 이동을 포함하는 선형 변환 모든 선형 변환은 어파인 변환이지만 모든 어파인 변환은 선형변환은 아님 컴퓨터 그래픽스에서 가장 일반적으로 다루게 될 변환
Y = yes, ‘ ’ = not always Transform Linear Affine Linear transformations Y Affine transformations Invertible transformations Angle-preserving transformations Orthogonal transformations Rigid-body transformations Translation Rotation Uniform scale Non-uniform scale Orthographic projection Reflection Shearing Y = yes, ‘ ’ = not always
회전, 이동, 크기변환 이동 (translation) 회전 (rotation) : z 축 중심의 회전 크기 변환 (scaling) 밀림 (shear)
이 동 이동 (translation)
회 전 회전 (rotation) 이차원 회전
고정점을 중심으로 한 이차원 회전
삼차원 회전 고정점 Pf 고정점 각도 축 v
크기 변환 이동, 회전 : 강체 변환 크기 변환 : 비강체 변환
균일 크기 변환과 비균일 크기 변환
크기 변환 매개 변수 고정점 방향 크기 변환 계수
반사 : 일종의 크기 변환
밀 림 밀림 (shear)
동차 좌표에서의 변환 프레임 내의 각 어파인 변환 (4x4 행렬에 의해 표현) 이동 (translation) 크기 변환 (scaling) 회전 (rotation) 밀림 (shear)
이 동 이동 행렬 (translation matrix)
이동 행렬의 역
크기 변환 크기 변환 행렬 크기 변환 행렬의 역
회 전 z축 중심의 회전
x축 중심의 회전 y축 중심의 회전
직교 행렬 (orthogonal matrix) 회전 행렬의 역 직교 행렬 (orthogonal matrix) 역 행렬이 전치 행렬과 같은 행렬 모든 직교 행렬은 원점에 대한 회전과 대응
밀 림 ’ 밀림 행렬의 역
변환의 연결 변환의 연결 (concatenating) 한번에 한 개의 변환 적용 파이프라인 변환
고정점에 대한 회전 Z축 중심으로 회전
고정점에 대한 회전 원점 이동 -> Z축 회전 -> 중심을 로 이동
일반 3차원 회전 Z축에 대한 회전 Y축에 대한 회전 X축에 대한 회전
사례 변환 단순 객체들의 장면 - 각 객체형을 편리한 크기, 방향, 위치로 정의 - 각 객체들의 등장은 객체 원형의 사례 (instance)임 즉, 원형에 어파인 변환 (사례 변환)을 적용하여 원하는 크기, 방향, 위치 정보를 얻음
임의의 축에 대한 3차원 회전 고정점 회전 중심인 벡터 회전각 1. 를 원점으로 이동 2. 를 z축과 일치 시킴 1. 를 원점으로 이동 2. 를 z축과 일치 시킴 3. z 축 중심으로 만큼 회전 4. 2번 역순 5. 1번 역순
임의의 축에 대한 3차원 회전 를 정규화 가 x-z 평면에 닿을 때까지 x축을 중심으로 회전 - 가 z 축에 닿을 때까지 y축을 중심으로 회전 -
임의의 축에 대한 3차원 회전
임의의 축에 대한 3차원 회전 x 와 y 의 계산 v = 방향 코사인들
x 회전의 계산
y 회전의 계산
4.9 OpenGL 변환 행렬들 현재 변환 행렬 (current transformation matrix : CTM)
C <-- I C <-- T C <-- S C <-- R C <-- C T C <-- C S C <-- C R C <-- M C <-- C M
회전, 이동, 크기 변환 모든 기본 요소에 적용되는 행렬 모델-관측 행렬(GL_MODELVIEW)과 투영행렬(GL_PROJECTION)의 곱 glLoadMatrixf(pointer_to_matrix); glLoadIdentity(); glMultMatrixf(pointer_to_matrix);
회전, 이동, 크기변환 함수 glRotatef(angle, vx, vy, vz); /* 각은 도(degree)로 지정 */ glTranslate(dx, dy, dz); /* 변수 dx, dy, dz 는 변위 벡터의 성분 */ glScalef(sx, sy, sz); /* sx, sy, sz 는 좌표축을 따른 크기 변환 인자 */ 모두 뒤에서 곱함으로써 선택된 행렬을 바꿀 수 있음
OpenGL에서 고정점에 대한 회전 고정점을 (4,5,6)으로 하고, 원점과 점 (1,2,3)을 지나는 직선에 대해 45도 회전하는데 필요한 행렬 형성 glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(4.0, 5.0, 6.0); glRotatef(45.0, 1.0, 2.0, 3.0); glTranslatef(-4.0, -5.0, -6.0);
변환 순서 OpenGL 에서의 규칙 C I C CT(4.0, 5.0, 6.0) C CR(45.0, 1.0, 2.0, 3.0) C CT(-4.0, -5.0, -6.0) C = T(4.0,5.0,6.0)R(45.0,1.0,2.0,3.0)T(-4.0,-5.0,-6.0) q = Cp glPushMatrix( ); glPopMatrix( );
입방체 돌리기 세 개의 콜백 함수 디스플레이 콜백 함수 glutDisplayFunc(display); glutIdleFunc(spincube); glutMouseFunc(mouse); 디스플레이 콜백 함수 void display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) glLoadIdentity(); glRotatef(theta[0], 1.0, 0.0, 0.0); glRotatef(theta[1], 0.0, 1.0, 0.0); glRotatef(theta[2], 0.0, 0.0, 1.0); colorcube(); glutSwapBuffers(); }
마우스 콜백 함수 휴지 콜백 함수 void mouse(int btn, int state, int x, int y) { if(btn==GLUT_LEFT_BUTTON) && state == GLUT_DOWN) axis = 0; if(btn==GLUT_MIDDLE_BUTTON) && state == GLUT_DOWN) axis = 1; if(btn==GLUT_RIGHT_BUTTON) && state == GLUT_DOWN) axis = 2; } 휴지 콜백 함수 void spincube() theta[axis] += 2.0; if(h[axis] > 360.0) theta[axis] -= 360.0; glutPostRedisplay();
행렬의 적재, 푸시, 팝 행렬의 적재 변환 실행 후 실행 전의 상태로 되돌아 갈 때 glLoadMatrix(myarray); /* 4*4 동차 좌표 행렬을 현재 행렬로 적재 */ glMultMatrix(myarray); /* 현재 행렬의 오른편에 사용자가 정의한 행렬을 곱함 */ myarray : 열(column)에 의해서 배열된 16개의 원소를 갖는 일차원 배열 Glfloat myarray[16]; for(i=0; i<=3; i++) for(j=0; j<=3; j++) { myarray[4*j+i] = m[i][j]; } 변환 실행 후 실행 전의 상태로 되돌아 갈 때 glPushMatrix( ); glTranslatef( … ); glRotatef( … ); glScalef( … ); /* 객체를 여기에 그림 */ glPopMatrix( );