5. 좌표변환과 OpenGL행렬 이론
목차 좌표 변환의 이해 투영 / 뷰포트 변환 OpenGL과 행렬 카메라와 시점 좌표 조망 변환 모델뷰 행렬 이동 / 회전 gluLookAt()함수의 사용 glRotate()와 glTranslate()함수의 사용 모델링 변환 투영 / 뷰포트 변환 OpenGL과 행렬 모델뷰 행렬 이동 / 회전 확대 / 축소 행렬 스택 OpenGL이 기본적으로 제공하는 변환들과 특별한 변환을 위해 임의의 행렬을 Opengl에 적용하는 방법에 대해서 알아보자
5-1 좌표 변환의 이해(1/6) 변환의 용도 순서를 지켜야 함 변환 설명 3D 좌표를 2D 화면에 투영 이동, 회전, 확대 축소(실제로 이동하는 것은 좌표계) 순서를 지켜야 함 조망변환은 반드시 모델링 변환 이전에 수행되어야 함 투영변환과 뷰 포트 변환은 랜더링 이전이기만 하면 됨 변환 설명 조망변환 카메라의 위치를 지정한다. 모델링 변환 장면 안에서 객체를 움직인다.(이동, 회전, 확대/축소) 투영 변환 조망 입체와 절단면들을 정의한다. 뷰 포트 장면의 2D 투영을 랜더링 창에 매핑한다. 모델 뷰 조망 변환과 모델링 변환을 결합한 것 변환은 3D안에서 객체들을 이동, 회전, 조작하기 위한 수단으로 변환의 용도로는 XX가 있다. 3D장면을 랜더링 할때는 다음과 같은 세가지 변환들을 거쳐야 한다. (조망, 모델링, 투영)
5-1 좌표 변환의 이해(2/6) 카메라와 시점 좌표 기본 카메라는 항상 음의 Z축 쪽을 바라봄 시점 좌표는 카메라에 적용된 좌표계로부터 직접적으로 도출 시점 좌표는 정점 변환으로부터 영향을 받지 않음 전역좌표계 (시점 좌표계) 객체좌표계 하나의 삼각형을 회전시킨다는 말은 그 삼각형의 좌표계를 시점 좌표에 대해 회전시킨다는 의미
5-1 좌표 변환의 이해(3/6) 조망 변환 회전과 이동을 통해 카메라의 기본 위치/방향을 변경시킴 카메라의 기본 방향은 음의 Z축 방향, 기본 위치는 (0,0,0) 시점 좌표계에 대해 현재 좌표계를 이동 수행과정 glLoadIdentity()함수 사용 : 현재 행렬을 초기화하여 단위행렬 생성 조망 변환에 적용될 행렬을 현재 행렬로 설정 단위 행렬을 그대로 둔다. gluLookAt()함수를 사용하여 카메라의 시선을 설정 고정된 카메라에 대해 객체들을 움직이는 방법(glTranslate()함수와 glRotate()함수를 사용) 독자적인 좌표계를 위한 이동과 회전루틴 직접 작성 조망 변환은 시점 좌표계에 대해 현재 좌표계를 이동시키며 다른 모든 변환들은 이동된 현재 좌표계에 기반해서 수행하기 때문에 가장 먼저 완료되어야 하는 작업이다. 조망변환에 적용될 행렬을 현재 행렬로 설정하는 방법 네가지
5-1 좌표 변환의 이해(4/6) gluLookAt()함수의 사용(그림 5.4) 카메라 위치 void gluLookAt(Gldouble eyex, Gldouble eyey, Gldouble eyez, Gldouble centerx, Gldouble centery, Gldouble centerz, Gldouble upx,Gldouble upy, Gldouble upz); 카메라가 가리키는 곳의 위치 위쪽방향을 알려주는 상향 벡터 //gluLookAt()함수로 조망 변환을 설정 //카메라가 음의 x축인 (0.0, 0.0, -100.0)을 바라보게 함 gluLookAt(0.0f, 0.0f, 10.0f, 0.0f, 0.0f, -100.0f, 0.0f, 1.0f, 0.0f); glBegin(GL_TRIANGLE); glVertexf(10.0f, 0.0f, 0.0f); glVertexf(0.0f, 10.0f, 0.0f); glVertexf(-10.0f, 0.0f, 0.0f); glEnd(); 카메라의 위치를 0, 0, 10으로 설정하고 음의 z축 방향에 있는 0.0 -100을 바라보게 한다. 원점에 삼각형을 하나 그린다.
5-1 좌표 변환의 이해(5/6) glRotate()와 glTranslate()함수의 사용 gluLookAt()함수는 프로그램을 만들 때 반드시 GLU라이브러리를 링크해야함 GLU라이브러리를 사용하지 않고 고정적인 카메라에 대한 전역 공간 안의 객체의 위치를 수정 glRotate() : 카메라의 방향을 이동시킴 glTranslate() : 카메라의 위치를 이동시킴 //glTranslatef()함수로 조망 변환을 설정 //모델링 변환을 (0.0, 0.0, -10.0)으로 설정 glTranslatef(0.0f, 0.0f, -10.0f); glBegin(GL_TRIANGLE); glVertextf(10.0, 0.0f, 0.0f); glVertextf(0.0, 10.0f, 0.0f); glVertextf(-10.0, 0.0f, 0.0f); glEnd(); 모델링 변환을 ( )로 변환 시킴으로써 카메라의 위치를 (0.0, 0.0, 10.0)으로 옮기는 효과를 얻게 된다. 모델링 변환을 (0.0, 0.0, -10.0)으로 설정함으로써 카메라를 (0.0, 0.0, 10.0)으로 옮기는 효과.
5-1 좌표 변환의 이해(6/6) 커스텀 변환 루틴의 작성 후 사용 극좌표 방식의 변환 설정 퀘이크 스타일의 변환 설정 하나의 고정된 점을 회전의 중심으로 사용 퀘이크 스타일의 변환 설정 마우스나 키보드를 이용해서 카메라를 조종 P155 코드 : 비행 시뮬레이터의 조망변환 예 모델링 변환을 ( )로 변환 시킴으로써 카메라의 위치를 (0.0, 0.0, 10.0)으로 옮기는 효과를 얻게 된다.
5.2 모델링 변환 모델을 이동, 회전, 확대.축소 함으로써 모델의 위치와 방향을 조작 모델링 변환들이 일어나는 순서는 최종적인 장면에 영향을 미침 객체를 이동시킨 다음 회전시키는 것과 객체를 회전시킨 다음 이동시키는 것은 결과가 틀림 회전후 이동 (5, 4.33) 이동후 회전 (5, 0)
5.3 투영 변환 & 뷰포트 변환 투영 변환 뷰포트 변환 조망 입체와 절단면들을 결정 모델뷰 변환 이후에 일어남 원근 투영 실세계에서 인간이 보는 것과 비슷한 방식으로 3D를 투영 카메라에 가까운 객체는 크게, 먼 객체는 작게 나타남 직교 투영 거리에 상관없이 객체를 실제 크기로 투영 CAD 소프트웨어에서 흔히 쓰임 뷰포트 변환 투영변환에 의해 만들어진 2차원 장면을 윈도우의 렌더링 표면에 대응 최종적인 2차원 화면을 랜더링 표면의 크기에 맞게 확대/축소 시키는 것
void glMatrixMode(GLenum mode); 5.4 OpenGL과 행렬(1/7) 모든 변환은 행렬에 의해 연산 모델뷰 행렬 (cf. 투영 행렬, 텍스쳐 행렬) 객체의 위치와 방향을 잡는데 쓰이는 좌표계를 정의 모델뷰 행렬은 4 * 4 행렬이며 이 행렬의 정점들이 곱해짐으로써 모델링과 조망변환이 발생 glMatirexMode()함수 행렬을 수정하고자 할 때 지금부터 수정할 행렬이 모델뷰 행렬임을 알려주는 역할 <모델뷰 행렬의 초기화 예> glMatrixMode(GL_MODELVIEW); glLoadIdentity(); //모델뷰 행렬을 초기화 …….. //변환들을 수행 glBegin(GL_POINTS); glVertex3f(0.0f, 0.0f, 0.0f); glEnd(); void glMatrixMode(GLenum mode); Mode인자에 GL_MODELVIEW를 지정하면 모델뷰 행렬이 현재 행렬로 지정 이후의 변환 명령들은 모두 모델뷰 행렬에 영향을 미침
5.4 OpenGL과 행렬(2/7) 이동 모델뷰 행렬을 현재 행렬로 설정한 후 초기화 객체를 한 곳에서 다른 곳으로 옮기는 것 glLoadIdentity()함수를 호출하여 수행 이 함수를 호출하면 모델뷰 행렬이 단위 행렬이 되고, 현재 좌표계는 전역 좌표계의 원점에 위치 이동 객체를 한 곳에서 다른 곳으로 옮기는 것 두 함수의 차이는 인자들의 데이터형 뿐 원하는 정밀도에 따라 달라짐(double이 정밀도가 더 높음) void glTranslatef(GLfloat x, GLfoat y, GLfoat z); void glTranslated(Gldoule x, Gldoule y, Gldoule z); 하나의 입방체를 원점에서 (5, 5, 5)로 이동시키는 예제 가장먼저 모델뷰 행렬을 현재 행렬로 선택 하고 단위행렬로 초기화 해야 한다. glMatrixMod(GL_MODELVIEW); glLoadIdentity(); glTranslatef(5.0f, 5.0f, 5.0f); DrawCube(); 모델뷰 행렬을 현재 행렬로 설정 모델뷰 행렬을 단위 행렬로 초기화 (5, 5, 5)로 이동 입방체를 그린다.
5.4 OpenGL과 행렬(3/7) 회전 glRotate()함수를 통해서 일어난다. 회전각을 음수로 주면 시계 방향으로 회전 임의의 축에 대한 회전도 가능 x, y, z에 (1, 1, 0)을 지정하면 원점에서 (1, 1, 0)을 잊는 벡터가 회전축이 된다. void glRotatef(GLfloat angle, GLfoat x , GLfoat y, GLfoat z); void glTranslated(Gldoule angle, Gldoule x , Gldoule y, Gldoule z); 회전각으로 단위는 도 이며 반시계 방향이 양의 각도임 glRotatef(135.0f, 0.0f, 1.0f, 0.0f); Y축에 대해 135도 회전
5.4 OpenGL과 행렬(4/7) 여러 개의 회전들을 결합하는 것도 가능 glMatrixMod(GL_MODELVIEW); glLoadIdentity(); glRotatef(60.0f, 1.0f, 0.0, 0.0f); glRotatef(45.0f, 0.0f, 1.0f, 0.0f); DrawCube(); 모델뷰 행렬을 현재 행렬로 설정 단위 행렬을 최기화 한다. X축에 대해 60도 회전 Y축에 대해 45도 회전 입방체를 그린다. (1,1,0) glRotatef(105.0f, 1.0f, 1.0f, 0.0f);
5.4 OpenGL과 행렬(5/7) 확대 / 축소 객체의 크기를 키우거나 줄이는 것 glScale()함수를 사용 비율이 1보다 크면 확대이고 1보다 작으면 축소 void glScalef(GLfoat x , GLfoat y, GLfoat z); void glScaled(Gldoule x , Gldoule y, Gldoule z); glScalef(2.0f, 2.0f, 2.0f); glSaclef(0.5f, 0.5f, 0.5f); 비율을 현재의 2배만큼 확대 비율을 현재의 반으로 축소
5.4 OpenGL과 행렬(6/7) 행렬 스택 모델뷰 행렬 스택 투영 행렬 스택 텍스쳐 행렬 스택 좀 더 간단한 객체들로부터 복잡한 모델들을 구축하는 데 쓰임 모델뷰 행렬 스택의 최상위 행렬은 모델뷰 행렬 투영 행렬 스택 투영 행렬 스택의 최상위 행렬은 투영행렬 텍스쳐 행렬 스택 로봇을 만들 때, 각 부품마다 서로 다른 변환들이 일어나야 하기 때문에 서로 다른 행렬들이 적용되어야 함 행렬 스택은 각기 다른 상황에 대해 서로 다른 행렬들을 적용하려 할 때 행렬들을 일시적으로 저장해 두기 위한 수단 OpenGL이 사용하는 행렬 스택은 세가지 이다. 예를들어
5.4 OpenGL과 행렬(7/7) glPushMatrix() 함수 glPopMatirx() 함수 현재 행렬을 복사해서 그것을 행렬 스택에 밀어넣는 작업 스택에 너무 많은 행렬이 쌓이면 OpenGL은 GL_STACK_OVERFLOW 오류를 발생 glPopMatirx() 함수 현재 행렬을 폐기하고 스택에서 현재 행렬 바로 아래에 있는 행렬을 현재 행렬로 만듬 스택에 행렬이 하나 밖에 없는 상태에서 이 함수를 호출하면 OpenGL은 GL_STACK_UNDERFLOW 오류를 발생 glPushMatrix() 행렬 스택 glPopMatrix()
5.5 변환의 일반적인 순서 정점 데이터 (x, y, z, w) 모델뷰 행렬 시점좌표 투영행렬 클립좌표 윈도우 좌표 정점 변환 파이프 라인을 예로 변환의 일반적인 순서를 그림으로 나타낸것이다. 윈도우 좌표 (x, y) 뷰포트 변환 정규회된 장치 좌표 원근조정
5.6 로봇 Source (1/8)
5.6 로봇 Source (2/8)
5.6 로봇 Source (3/8)
5.6 로봇 Source (4/8)
5.6 로봇 Source (5/8)
5.6 로봇 Source (6/8)
5.6 로봇 Source (7/8)
5.6 로봇 Source (8/8)
5.7 응용 Source (1/4)
5.7 응용 Source (2/4)
5.7 응용 Source (3/4)
5.7 응용 Source (4/4)
5.8 투영 직교(평행) 투영 원근 투영 투영변환 조망입체 원근을 고려하지 않는 투영 사실적인 장면들을 담아내는 원근을 고려한 투영(절두체) 절단면 정의 투영변환 조망입체 객체 그려지는 방식 결정
5.8 투영 직교(평행) 투영 glOrtho(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far); glOrtho2D(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top);
5.8 투영 원근 투영 void glFrustum(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far); void gluPerspective(GLdouble fov, GLdouble aspect, GLdouble near, GLdouble far);
5.9 커스텀 행렬 사용 부동 소수점 값들로 된 열 우선 4 x 4 행렬 m0 m4 m8 m12 m1 m5 m9 m13 void glLoadMatrix(const Gldouble *matrix); void glLoadMatrixf(const Glfloat *matrix); void glMultMatrix(const Gldouble *matrix); void glMultMatrixf(const Glfloat *matrix);