Chapter 3. Chapter 3. 뷰뷰 뷰뷰 (Viewing) (Viewing)
Jan 06, 2016
Chapter 3. Chapter 3. 뷰잉뷰잉 (Viewing)(Viewing)
33 차원 좌표들의 변환과정차원 좌표들의 변환과정 다음의 세 가지 컴퓨터 연산이 순차적으로 실행되면서 스크린 상의
픽셀로 변환◦ 모델링 , 뷰잉 , 투영 연산 등과 같은 행렬 곱셈으로 표현된 변환
회전 변환 , 평행이동 변환 , 크기 변환 , 반사 , 직교투영 , 원근 투영 등이 포함됨
◦ 장면은 사각형 윈도우에 렌더링되기 때문에 오브젝트 또는 오브젝트의 일부가 윈도우 밖에 놓여지는 경우 잘라내는 클리핑 수행
◦ 변환된 좌표와 스크린 픽셀을 서로 연결시켜주는 뷰포트 변환
2013-2 학기 3 장 뷰잉
2013-2 학기
뷰잉뷰잉 (viewing)(viewing)
카메라 구조
뷰잉 및 모델링 변환
투영 변환
뷰포트 변환
변환에 관련된 문제 해결 방법
행렬 스택 조작하기
부가적인 클리핑 평면
여러가지 변환 함께 사용하기
변환을 역으로 수행하거나 흉내내기
3 장 뷰잉
카메라 구조카메라 구조 원하는 장면을 생성하기 위해 거치는 변환 과정은 카메라로
사진을 찍는 것에 비유
◦ 삼각대를 세우고 , 카메라가 장면을 향하도록 설정 ( 뷰잉 변환 )◦ 원하는 장면을 화면에 담도록 모델을 정리 ( 모델링 변환 )◦ 사용할 카메라 렌즈를 선택하거나 줌을 조절 ( 투영 변환 )◦ 사진의 크기를 결정한다 ( 뷰포트 변환 ).
2013-2 학기 3 장 뷰잉
정점 변환의 단계정점 변환의 단계 뷰잉 , 모델링 , 투영 변환을 설정하려면 4 * 4 행렬 M 을 만들고 장면의
각 정점 v 에 대한 좌표와 곱해서 수행◦ v’ = Mv
사용자가 지정한 뷰잉 및 모델링 변환을 통해 모델 뷰 행렬을 만들 수 있는데 이는 입력된 오브젝트 좌표에 적용 , 눈좌표 (eye coordinates) 생성
투영 행렬을 적용하여 클립 좌표 (clip coordinate) 를 생성
좌표값을 w 로 나누는 투시분할 (perspective division) 을 실행하여 정규화 장치 좌표를 생성
변환된 좌표는 뷰포트 변환을 거쳐 윈도우 좌표로 변환
2013-2 학기 3 장 뷰잉
정점 변환의 단계정점 변환의 단계
2013-2 학기
xyzw
Modelviewmatrix
Projectionmatrix
Perspectivematrix
Viewporttransformation
Vertex
눈좌표
클립좌표
정규화장치좌표
윈도우좌표
오브젝트좌표
3 장 뷰잉
정육면체를 그리는 간단한 정육면체를 그리는 간단한 [[ 예제 예제 3 3 –– 1]: cube.c 1]: cube.c#include <GL/glut.h>#include <stdlib.h>
void init(void) { glClearColor (0.0, 0.0, 0.0, 0.0); glShadeModel (GL_FLAT); }
void display(void){ glClear (GL_COLOR_BUFFER_BIT); glColor3f (1.0, 1.0, 1.0); glLoadIdentity (); /* 행렬을 클리어 */ gluLookAt (0.0,0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); /* 뷰잉변환
*/ glScalef (1.0, 2.0, 1.0); /* 모델 변환 */ glutWireCube (1.0); glFlush (); }
2013-2 학기 3 장 뷰잉
void reshape (int w, int h){ glViewport (0, 0, (GLsizei) w, (GLsizei) h); glMatrixMode (GL_PROJECTION); glLoadIdentity (); glFrustum (-1.0, 1.0, -1.0, 1.0, 1.5, 20.0); glMatrixMode (GL_MODELVIEW);}
void keyboard(unsigned char key, int x, int y){ switch (key) { case 27: exit(0); break; }}
2013-2 학기 3 장 뷰잉
int main(int argc, char** argv){ glutInit(&argc, argv); glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB); glutInitWindowSize (500, 500); glutInitWindowPosition (100, 100); glutCreateWindow (argv[0]); init (); glutDisplayFunc(display); glutReshapeFunc(reshape); glutKeyboardFunc(keyboard); glutMainLoop(); return 0;}
2013-2 학기 3 장 뷰잉
실행결과실행결과
2013-2 학기 3 장 뷰잉
뷰잉 변환뷰잉 변환 뷰잉 변환은 카메라의 위치와 방향을 지정하는 것에 비유
위의 [ 예제 3 – 1]
◦ glLoadIdentity() 를 사용 , 현재 행렬을 단위행렬로 설정◦ 행렬을 초기화 후 , gluLookAt() 으로 뷰잉 변환 지정
gluLookAt() 을 호출하지 않으면 디폴트 위치와 방향설정 카메라 위치 , 바라볼 방향 , 어느쪽이 위쪽인지를 지정
카메라 위치 : (0, 0, 5) 바라볼 방향 : (0, 0, 0) 업벡터 (up-vector): (0, 1, 0)
2013-2 학기 3 장 뷰잉
모델링 변환모델링 변환모델의 위치와 방향은 모델링 변환으로 조절
◦ 모델을 회전 변환 , 평행이동 변환 , 크기 변환 등을 사용
◦ [ 예제 3 – 1] 에서 glScalef() 를 사용하여 모델링 변환정육면체를 볼 수 있도록 뷰잉 변환으로 카메라를
이동하는 대신 모델링 변환으로 카메라로부터 떨어지도록 설정 가능◦ 이원성 (duality) 존재로 뷰잉 변환과 모델링 변화을
하나의 모델뷰 행렬 (modelview matrix) 로 설정
2013-2 학기 3 장 뷰잉
투영 변환투영 변환 투영 변환을 설정하는 것은 카메라 렌즈를 고르는 것과 비슷 화각 (field of view) 이나 관측 공간 (viewing volume) 을 결정 어떤 오브젝트가 관측 공간 안에 들어 있게 되는지 , 어느 정도
보이게 되는지 결정 투영의 방식 ( glFrustum() 사용 )
◦ 원근 (perspective) 투영 멀리 있는 물체는 가까이 있는 것보다 작게 나타남 glFrustum() 커맨드 사용
◦ 직교 (orthographic) 투영 상대적인 크기에 관계 없이 물체를 스크린에 그대로 매핑 건축설계 및 CAD 설계용 응용 프로그램에서 주로 사용하며 ,
정확한 물체의 크기를 표현하는데 중점을 둠
2013-2 학기 3 장 뷰잉
뷰포트 변환뷰포트 변환 투영 변환과 뷰포트 변환은 장면과 컴퓨터 스크린이 매핑되는 방식을
결정◦ 투영변환은 매핑이 구체적으로 어떻게 이루어지는지 결정◦ 뷰포트 변환은 스크린을 매핑할 스크린 영역의 모양 나타냄
glViewport() 의 인자는 스크린 공간에 대한 원점 , 영역의 폭과 높이 설정 , 픽셀 단위로 표현◦ 이 커맨드는 reshape() 루틴 안에서 호출되어야 함◦ 윈도우의 크기를 변경하면 뷰포트 역시 변경해야 함
2013-2 학기 3 장 뷰잉
장면 그리기장면 그리기 장면에 나온 모든 오브젝트의 각 정점을 모델링 및 뷰잉 변환에
따라 변환 변환된 정점들은 투영 변환에 따라 변환 투영 변환에서 지정된 공간을 벗어나는 오브젝트들은 잘라냄
(Clip) 변환된 정점들을 w 로 나눈 후 뷰포트에 매핑
2013-2 학기 3 장 뷰잉
범용 변환 커맨드범용 변환 커맨드 변환을 직접 설정하는데 유용한 커맨드
◦ glMatrixMode()◦ glLoadIdentity()◦ glLoadMatrix*()◦ glMultMatrix*()◦ gluLookAt()◦ glScale()
void glMatrixMode(GLenum mode)◦ 변환 커맨드를 실행하기 전에 모델뷰 , 투영 , 텍스처 행렬을 수정할지
여부 결정◦ mode : GL_MODELVIEW, GL_PROJECTION, GL_TEXTURE
void glLoadIdentity(void);◦ 나중에 실행할 변환 커맨드를 위해 수정 가능한 행렬을 클리어◦ 현재 수정 가능한 행렬을 4x4 단위 행렬로 설정
2013-2 학기 3 장 뷰잉
현재 행렬로 로드할 행렬을 명시적으로 지정하기 위한 커맨드◦ void glLoadMatrix{fd}(const TYPE *m);
현재 행렬의 16 개 값 (4 * 4) 을 m 으로 지정된 행렬의 값으로 설정
◦ void glMultMatrix{fd}(const TYPE *m); m 이 가리키는 16 개 값으로 지정된 행렬을 현재 행렬과
곱하고 , 그 결과를 현재 행렬에 저장
2013-2 학기
m1 m5 m9 m13
m2 m6 m10 m14
m3 m7 m11 m15
m4 m8 m12 m16
M =
[ 주의사항 ]행렬을 m[4][4] 로 선언했다면m[i][j] 원소는 OpenGL 변환행렬의 j 행 , i 열에 있음 .C 와는 반대
3 장 뷰잉
뷰잉 및 모델링 변환뷰잉 및 모델링 변환 모델링 변환이나 뷰잉 변환을 실행하기 위해서는 반드시
glMatrixMode() 에 GL_MODELVIEW 를 인자로 주고 호출해야 함 .
변환 이해하기
◦ 모든 뷰잉 변환 및 모델링 변환은 4 * 4 행렬로 표현◦ glMultMatrix*() 과 같은 변환 커맨드들은 새로 주어진 4 *
4 행렬 M 을 현재 모델뷰 행렬 C 와 곱하여 CM 을 생성◦ 그 다음 , 정점 v 를 현재 모델뷰 행렬에 곱함◦ 즉 , 프로그램 상에서 가장 늦게 호출한 변환 커맨드가
정점에 가장 먼저 적용 (CMv)
2013-2 학기 3 장 뷰잉
예제 glMatrixMode (GL_MODELVIEW); glLoadIdentity(); glMultMatrix(N); glMultMatrix(M); glMultMtrix(L); glBegin(GL_POINTS); glVertex3f(v); glEnd();
모델뷰 행렬은 I, N, NM, NML 순서로 변경 정점변환은 N(M(Lv)) 와 같이 수행 v 에 대해 변환을 수행한 결과는 이들을 지정한 순서와는
반대로 나타냄 . 실제로는 정점에 대해 모델뷰 행렬을 한번만 곱한다 . L, M, N
행렬들을 한번에 곱한 후 v 에 적용 .
2013-2 학기 3 장 뷰잉
고정 좌표계고정 좌표계 모델의 위치 , 방향 , 크기 등에 영향을 미치는 행렬 곱셈을 고정
좌표계 (Grand, Fixed Coordinate System) 관점에서 생각할 경우 , 코드에 나온 순서와 반대로 곱셈이 수행
연산 ( 회전 , 평행 이동 ) 을 수행한 후 오브젝트가 좌표축에 놓여 있도록 하기 위해서는 ( 오브젝트는 원점에서 생성 )
회전을 먼저 한 후 , 평행이동 시켜야 함
명령문 예 ( 역순으로 지정해야 )◦ glMatrixMode(GL_MODELVIEW);◦ glLoadIdentity();◦ glMultMatrixf(T); /* 평행이동 */◦ glMultMatrixf(R); /* 회 전 */◦ Draw_the_object();
2013-2 학기
1-Rotate
2-Translate
3 장 뷰잉
로컬 좌표계 이동하기로컬 좌표계 이동하기 행렬 곱셈을 바라볼 때 변환할 오브젝트가 고정 좌표계에 있지 않
고 , 오브젝트에 로컬 좌표계가 달려 있는 것처럼 생각 모든 연산들은 이러한 좌표계에 상대적으로 수행 이러한 접근 방식에서는 행렬 곱셈이 코드상에 지정된 순서대로
실행 앞의 예제를 다음과 같이 실행하게 된다 .
◦ 좌표계가 달린 오브젝트를 그리고◦ 오브젝트와 오브젝트에 지정된 좌표계를 X 축으로 평행
이동시킨다 .◦ 원점에 대해 회전시키면 오브젝트는 X 축상의 평행 이동된
위치에서 회전하게 됨 .
2013-2 학기 3 장 뷰잉
모델링 변환모델링 변환 모델링 변환을 위해 세가지 커맨드들을 제공
◦ 평행이동 void glTranslate{fd}(TYPE x, TYPE y, TYPE z);
◦ 회전 void glRotate{fd}(TYPE angle, TYPE x, TYPE y, TYPE z);
오브젝트 ( 또는 로컬좌표계 ) 를 원점에서 (x, y, z) 에 이르는 선을 기준으로 반시계 방향으로 angle 각도 만큼 회전
◦ 크기변환 void glScale{fd}(TYPE x, TYPE y, TYPE z);
평행이동 , 회전 , 크기변환 행렬 등을 계산한 뒤에 glMultMatrix*()의 인자로 전달하고 호출하는 것과 동일하다 .
glMultMatrix*() 사용보다는 위의 세 루틴 사용이 좀 더 빠르게 동작함 .
2013-2 학기 3 장 뷰잉
모델링 변환 예제모델링 변환 예제 솔리드 와이어프레임 삼각형을 아무런 모델링 변환도 적용 안함 삼각형을 대시 모양의 라인 스티플과 평행이동 변환을 사용 높이 (y 축 ) 는 절반 줄이고 폭 (x 축 ) 은 50% 늘인 긴 대시
모양의 라인 스티플 삼각형을 점선으로 표현 , 회전
2013-2 학기 3 장 뷰잉
#include <GL/glut.h>#include <stdlib.h>
void init(void) { glClearColor (0.0, 0.0, 0.0, 0.0); glShadeModel (GL_FLAT);}
void draw_triangle(void){ glBegin (GL_LINE_LOOP); glVertex2f(0.0, 25.0); glVertex2f(25.0, -25.0); glVertex2f(-25.0, -25.0); glEnd();}
2013-2 학기 3 장 뷰잉
뷰잉 및 모델링 변환뷰잉 및 모델링 변환void display(void){
glClear (GL_COLOR_BUFFER_BIT);
glColor3f (1.0, 1.0, 1.0);
glLoadIdentity ();
glColor3f (1.0, 1.0, 1.0);
draw_triangle ();
glEnable (GL_LINE_STIPPLE);
glLineStipple (1, 0xF0F0);
glLoadIdentity ();
glTranslatef (-20.0, 0.0, 0.0);
draw_triangle ();
2013-2 학기 3 장 뷰잉
glLineStipple (1, 0xF00F); glLoadIdentity (); glScalef (1.5, 0.5, 1.0); draw_triangle ();
glLineStipple (1, 0x8888); glLoadIdentity (); glRotatef (90.0, 0.0, 0.0, 1.0); draw_triangle (); glDisable (GL_LINE_STIPPLE);
glFlush ();}
2013-2 학기 3 장 뷰잉
void reshape (int w, int h)
{
glViewport (0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
if (w <= h)
glOrtho (-50.0, 50.0, -50.0*(GLfloat)h/(GLfloat)w,
50.0*(GLfloat)h/(GLfloat)w, -1.0, 1.0);
else
glOrtho (-50.0*(GLfloat)w/(GLfloat)h,
50.0*(GLfloat)w/(GLfloat)h, -50.0, 50.0, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
}
2013-2 학기 3 장 뷰잉
void keyboard(unsigned char key, int x, int y)
{ switch (key) { case 27: exit(0); break; }}
2013-2 학기 3 장 뷰잉
int main(int argc, char** argv){ glutInit(&argc, argv); glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB); glutInitWindowSize (500, 500); glutInitWindowPosition (100, 100); glutCreateWindow (argv[0]); init (); glutDisplayFunc(display); glutReshapeFunc(reshape); glutKeyboardFunc (keyboard); glutMainLoop(); return 0;}
2013-2 학기 3 장 뷰잉
실행결과실행결과
2013-2 학기 3 장 뷰잉
Nate Robins Nate Robins 의 변환관련 의 변환관련 튜토리얼튜토리얼 http://www.cs.utah.edu/~narobins/opengl.html
transformation 프로그램 실행
2013-2 학기 3 장 뷰잉
뷰잉 변환뷰잉 변환 뷰잉 변환을 사용하면 시점의 위치와 방향을 변경 카메라 비유에서 본 것처럼 뷰잉 변환은 카메라를 삼각대에 놓고 ,
모델을 향하도록 조절하는 단계 뷰잉 변환은 일반적으로 이동 변환과 회전변환으로 구성 반시계 방향으로 오브젝트를 회전시키는 모델링 변환은 카메라를
시계 방향으로 회전시키는 뷰잉 변환과 동일한 효과를 얻을 수 있다 . 뷰잉 변환에 관련된 커맨드들은 반드시 모델링 변환을 수행하기 전에
호출해야만 오브젝트에 대한 모델링 변환의 효과가 먼저 나타나게 된다 .
뷰잉 변환의 다양한 방법◦ 한 개 이상의 모델링 변환 커맨드 사용
glTranslate*(), glRotate*() 등◦ 유틸리티 라이브러리 루틴인 gluLookAt() 사용 , 시선을 정의◦ 회전 변환 , 이동 변환을 캡슐화 하는 유틸리티를 직접 만듬
2013-2 학기 3 장 뷰잉
glTranslate*() glTranslate*() 와 와 glRotate*() glRotate*() 사용하기사용하기
뷰잉변환 표현을 위해 모델링 변환을 사용할 때◦ 오브젝트는 월드 공간에 고정시켜두고 시점만 이동시켜야 하는
경우가 있다 .◦ 초기에는 시점이 원점에 있고 , 대부분 오브젝트는 원점에
생성되어 있기 때문에 몇 가지 변환 필요◦ 카메라는 초기에 z 축의 음의 방향을 향하고 있음◦ 간단한 방법으로 시점을 오브젝트 뒤로 이동
glTranslatef(0.0, 0.0, -5.0); 오브젝트를 장면으로부터 z 축 방향으로 – 5만큼 이동시킨다 . 카메라를 z 축 방향으로 +5 만큼 이동시킨 것과 같은 효과
2013-2 학기 3 장 뷰잉
시점과 오브젝트 분리 : glTranslate(0.0, 0.0, -5.0) 한 후
2013-2 학기
x
y
z
카메라
z
카메라 x
y
3 장 뷰잉
오브젝트를 옆에서 보도록 설정하는 경우
◦ 고정 좌표계 방식으로 생각할 경우 오브젝트를 회전 카메라로부터 멀리 떨어지도록 이동 고정 좌표계에서는 실제 효과 순서와 역순으로 커맨드 호출
◦ 로컬 좌표계 방식으로 생각할 경우 오브젝트와 로컬 좌표계를 원점으로부터 이동 그 뒤 회전 변환은 이동된 좌표계를 기준으로 회전 로컬 좌표계는 순서대로 커맨드 호출
2013-2 학기 3 장 뷰잉
gluLookAt() gluLookAt() 유틸리티 유틸리티 사용하기사용하기
원점이나 그 밖의 편리한 위치에서 장면을 구성한 다음 이를 임의의 지점에서 바라보도록 코드를 작성
이 루틴은 시점의 위치를 나타내는 세 개의 인자를 받아서 카메라가 바라볼 기준점 (reference point) 과 어느뱡향이 위쪽인지 결정
gluLookAt() 루틴은 카메라를 상하 , 좌우로 움직이며 바라볼 때 특히 유용
관측공간이 x, y 모두에 대칭일 경우 점 (eyex, eyey, eyez) 는 항상 이미지의 중앙에 위치하기 때문에 이 점을 이동시키면 카메라를 상하 혹은 좌우로 이동시키는 효과를 얻는다 .
void gluLookAt(GLdouble eyex, GLdouble eyey, GLdouble eyez, GLdouble centerx, GLdouble centery, GLdouble centerz, GLdouble upx, GLdouble upy, GLdouble upz)◦ 원하는 시점 : eyex, eyey, eyez◦ 바라보는 장면의 가운데 지점 : centerx, centery, centerz◦ 관측공간의 아래에서 위로의 방향 : upx, upy, upz
2013-2 학기 3 장 뷰잉
카메라의 디폴트 위치는 원점이고 디폴트 방향을 z 축의 음의 방향이며 위쪽에 대한 기본값을 y 축의 양의 방향일 때 ,◦ gluLookAt(0,0, 0.0, 0.0, 0.0, 0.0, -100, 0.0, 1.0,
0.0); 기준점의 z 값은 어떠한 음수로도 상관 없다 . 같은 효과 .
2013-2 학기
x
y
z
카메라
x
y
업벡터
3 장 뷰잉
gluLookAt(4.0, 2.0, 1.0, 2.0, 4.0, -3.0, 2.0, 2.0, -1.0);
2013-2 학기
x
y
z
카메라
(4.0, 2.0, 1.0)
(2.0, 4.0, -3.0)
(2,0, 2.0, -1.0)
3 장 뷰잉
Nate Robins 의 투영 관련 튜토리얼◦ projection 프로그램
2013-2 학기 3 장 뷰잉
투영 변환투영 변환 투영 변환은 관측 공간을 정의하는데 사용
◦ 두 가지 방식 오브젝트가 스크린에 투영 되는 형태 ( 원근 , 직교 투영 ) 최종 이미지에서 어떤 오브젝트가 클리핑 될지를 결정
◦ 여기에서 설명하는 커맨드를 호출하기 전에 반드시 다음과 같은 커맨드를 호출 glMatrixMode(GL_PROJECTION); glLoadIdentity();
2013-2 학기 3 장 뷰잉
원근 투영원근 투영 (perspective (perspective projection)projection)
원근투영의 가장 큰 특징은 바로 포쇼트닝 (foreshortening) Foreshortening : 단축법 , 오브젝트가 카메라로부터 멀리
떨어질수록 작게 그리는 기법◦ 이런 효과는 관측 공간을 피라미드의 절두체로 정의할 때 나타남◦ 절두체 : frustum, 밑면과 평행으로 꼭지 부분을 잘라낸 피라미드
오브젝트들은 피라미드의 정점 (apex) 방향으로 투영하며 이 지점에 카메라 혹은 시점 위치
시점에 가까이 놓여진 오브텍트들은 먼 것보다 크게 보임
2013-2 학기
Wikipedia Figure shows two different projections of a stack of two cubes, illustrating oblique parallel projection foreshortening ("A") and perspective foreshortening ("B").
3 장 뷰잉
void glFrustum(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far);
◦ 원근 투영을 나타내는 행렬을 생성하고 이를 현재 행렬과 곱한다 .
◦ 관측 공간 ( 절두체 ) 은 이 공간 밖에 놓인 오브젝트들을 클리핑 하는데 사용됨
◦ 절두체 정의 (left, bottom, -near) 와 (right, top, -near) 각각 카메라와 가까운 곳에 위치한 클리핑 평면의 좌측 하단
모서리와 우측 상단 모서리 좌표를 나타냄 near 와 far 인자는 항상 양수로 정해야 함
2013-2 학기 3 장 뷰잉
void gluPerspective(GLdouble fovy, GLdouble aspect, GLdouble near, GLdouble far);
◦ glFrustum() 과 같은 관측 공간 생성 , 지정방식의 차이가 있다 .◦ fovy 는 y 축 방향의 FOV 각도를 나타냄◦ aspect 인자는 절두체의 종횡비 (x/y, 정사각형의 경우 종횡비는 1.0 이다 )
2013-2 학기
카메
라
wh
Aspect = w/h
fovy
near far
3 장 뷰잉
직교 투영직교 투영 (Orthogonal (Orthogonal projection)projection) 평행 육면체 모양의 관측 공간을 사용 .
원근 투영과 달리 관측 공간의 양 끝면의 크기가 일정 . 카메라의 거리가 오브젝트의 모양에 영향을 안 미침 . 건축 설계도나 CAD 설계 등과 같이 오브젝트의 크기와 각도를 정확히
유지해야 하는 응용 프로그램에서 주로 사용
2013-2 학기
관측공간
top
left
far
right
bottomnear
시점방향
3 장 뷰잉
직교형 관측 공간의 생성◦ glOrtho() 커맨드로 생성◦ void glOrtho(GLdouble left, GLdouble right, GLdouble
bottom, GLdouble top, GLdouble near, GLdouble far); 직교관측공간의 행렬을 생성하고 이를 현재 행렬과 곱한다 . glFrustum() 과 동일한 방식의 인자 .
near 클리핑 평면의 좌측 하단 모서리와 우측 상단 모서리에 해당하는 점인 (left, bottom, -near) 와 (right, top, -near) 는 각각 뷰포트 윈도우의 좌측 하단 및 우측 상단 모서리에 매핑된다 .
투영의 방향은 z 축과 평행하며 , 시점은 z 축의 음의 방향
2013-2 학기 3 장 뷰잉
이미지를 2차원 스크린에 투영하는 특수한 경우◦ void gluOrtho2D(GLdouble left, GLdouble right, GLdouble
bottom, GLdouble top);
◦ 2차원 좌표를 스크린에 투영하는 행렬을 생성하고 현재 행렬과 곱한다 . ◦ 클리핑 영역
좌측 하단 모서리 (left, bottom) 우측 상단 모서리 (right, top)
Nate Robins 의 투영 관련 튜토리얼◦ projection 프로그램
관측 공간 클리핑 (clipping)
◦ 장면에 있는 오브젝트 정점들을 모델뷰 행렬과 투영 행렬로 모두 변환하였다면 공간의 밖에 있는 모든 프리미티브 들은 클리핑된다 .
2013-2 학기 3 장 뷰잉
뷰포트 변환뷰포트 변환 뷰포트 변환
◦ 카메라에 비유하면 , 뷰포트 변환을 현상할 사진의 크기를 선택하는 단계
◦ 컴퓨터 그래픽스에서 뷰포트는 그려질 윈도우의 직사각형 모양의 영역
◦ 뷰포트는 윈도우 좌표로 측정◦ 측정된 좌표는 윈도우의 좌측 하단 모서리를 기준으로 스크린
상의 픽셀 위치로 표현
2013-2 학기 3 장 뷰잉
뷰포트 정의하기뷰포트 정의하기 스크린 상에 윈도우를 생성하는 작업은 OpenGL 이 아닌 윈도우
시스템이 담당 윈도우를 처음 생성할 때 전체 윈도우에 해당하는 픽셀 영역을
뷰포트로 설정 이보다 작은 영역을 뷰포트로 설정할 때는 glViewport() 커맨드
사용 void glViewport(GLint x, GLint y, Glsizei width, Glsizei
height);◦ 최종 이미지가 매핑될 윈도우의 픽셀 사각형을 정의한다 .◦ x, y 매개변수는 이러한 뷰포트의 좌측 하단 모서리 나타냄◦ width, 와 height 인자는 뷰포트의 크기를 지정
뷰포트의 종횡비는 관측공간의 종횡비와 비슷하다 . 두 비율이 서로 다르면 투영된 이미지가 서로 뒤틀리게 된다 .
2013-2 학기 3 장 뷰잉
변환된 깊이 좌표변환된 깊이 좌표 뷰포트 변환이 수행되는 동안 깊이 (z) 좌표는 인코딩 Z 값을 원하는 범위 내에서 조절하려면 glDepthRange() 사용 윈도우의 x, y 좌표와는 달리 OpenGL 에서 z 좌표는 항상 0.0 과
1.0 사이에 있는 것으로 취급된다 .
void glDepthRange(GLclampd near, GLclampd far);◦ 뷰포트 변환에서 사용될 z 좌표를 인코딩한다 . ◦ near, far 인자는 깊이 버퍼에 저장될 최소 및 최대 수정 범위◦ 기본적으로 이 값은 0.0 과 1.0 으로 설정
2013-2 학기 3 장 뷰잉
행렬 스택 조작하기행렬 스택 조작하기 행렬 스택은 단순한 모델로 부터 복잡한 모델을 구성하는 것처럼 모델을
계층적으로 구성할 때 유용 행렬연산 (glLoadMatrix(), glMultMatrix(), glLoadIdentity()) 과 특정한
변환행렬을 생성하는 커맨드들은 현재 행렬이나 스택의 top 행렬을 처리 . 현재 행렬에 대한 복사본을 수택의 top 에 복사하는 glPushMatrix() 나 ,
스택의 top 행렬을 버리는 glPopMatrix() 와 같은 커맨드를 사용 , top 의 원소를 지정◦ glPushMatrix() : 현재 위치를 저장◦ glPopMatrix() : 이전 위치로 되돌려 놓는다 .
void glPushMatrix(void):◦ 현재 스택에 있는 모든 행렬들을 한 단계 아래로 이동 (push)
void glPopMatrix(void);◦ 스택의 top 원소 ( 행렬 ) 를 뽑아낸다 (pop)
현재 스택은 glMatrixMode() 로 결정한다 .
2013-2 학기 3 장 뷰잉
예제 예제 3-4 3-4 행렬을 행렬을 push push 또는 또는 pop pop 하기하기
draw_wheel_and_bolts()
{
long i;
draw_wheel();
for (i = 0; i < 5; i++) { glPushMatrix();
glRotatef(72.0*i, 0.0, 0.0, 1.0); glTranslatef(3.0, 0.0, 0.0); draw_bolt();
glPopMatrix();
}
}
2013-2 학기 3 장 뷰잉
draw_body_and_wheel_and_bolts()
{
draw_car_body();
glPushMatrix(); glTranslatef(40, 0, 30); /* 첫번째 바퀴의 위치로 이동 */ draw_wheel_and_bolts();
glPopMatrix();
glPushMatrix(); glTranslatef(40, 0, -30); /* 두 번째 바퀴의 위치로 이동 */ draw_wheel_and_bolts();
glPopMatrix();
…
}
2013-2 학기 3 장 뷰잉
모델뷰 행렬 스택모델뷰 행렬 스택 모델뷰 행렬에는 뷰잉 및 모델링 변환 행렬을 곱한 값들이
누적되어 있다 . 각각의 뷰잉 또는 모델링 변환들은 현재 모델뷰 행렬과 곱할
새로운 행렬을 생성 변환의 결과로 생성된 행렬은 새로운 현재 행렬로 설정 모델뷰 행렬 스택에는 최소 32 개의 4x4 행렬들을 저장할 수
있다 . 초기에는 스택의 Top 원소로 단위 행렬이 저장 스택의 최대 저장 개수 확인
◦ glGetIntegerv(GL_MAX_MODELVIEW_STACK_DEPTH, GLint *params);
2013-2 학기 3 장 뷰잉
투영 행렬 스택투영 행렬 스택 투영행렬 스택은 관측 공간을 구성하는 투영 변환을 위한 행렬을
저장 투영 행렬을 직접 작성하지 않기 때문에 투영 변환을 수행하기
전에 glLoadIdentity() 를 호출 스택의 깊이를 확인
◦ glGetIntegerv(GL_MAX_PROJECTION_STACK_DEPTH, GLlint *params);
2013-2 학기 3 장 뷰잉
부가적인 클리핑 평면부가적인 클리핑 평면 관측공간에 존재하는 여섯 개의 클리핑 평면 (left, right, bottom, top, near,
far)외에도 , 부가적인 클리핑 평면을 최대 여섯 개 까지 정의하여 관측 공간에 좀더 제한을 가할 수 있다 .
오브젝트의 단면을 보여줄 때와 같이 (cutaway view) 오브젝트의 불필요한 부분을 제거할 때 유용하다 .
각 평면은 다음과 같은 방적식의 계수로 표현◦ Ax + By + Cz + D = 0;
void glClipPlane(GLenum plane, const GLdouble *equation);◦ 클리핑 평면을 정의한다 .◦ equation 인자는 평면방정식의 4 개의 계수를 나타낸다 .◦ plane 인자는 GL_CLIP_PLANEi 로서 i는 사용 가능한 클리핑 공간을
가리킨다 .
정의한 클리핑 평면들은 다음과 같이 활성화시킨다 .◦ glEnable(GL_CLIP_PLANEi);
비활성화시킬 때는 ◦ glDisable(GL_CLIP_PLANEi);
2013-2 학기 3 장 뷰잉
클리핑 평면에 대한 코드 클리핑 평면에 대한 코드 [[ 예제 예제 3 3 –– 5 ]: clip.c5 ]: clip.c
#include <GL/glut.h>#include <stdlib.h>
void init(void) { glClearColor (0.0, 0.0, 0.0, 0.0); glShadeModel (GL_FLAT);}
void display(void){ GLdouble eqn[4] = {0.0, 1.0, 0.0, 0.0}; GLdouble eqn2[4] = {1.0, 0.0, 0.0, 0.0};
glClear(GL_COLOR_BUFFER_BIT);
2013-2 학기 3 장 뷰잉
glColor3f (1.0, 1.0, 1.0); glPushMatrix(); glTranslatef (0.0, 0.0, -5.0);
/* 아래쪽 절반 클리핑 -- y < 0 */ glClipPlane (GL_CLIP_PLANE0, eqn); glEnable (GL_CLIP_PLANE0); /* 왼쪽 절반 클리핑 -- x < 0 */ glClipPlane (GL_CLIP_PLANE1, eqn2); glEnable (GL_CLIP_PLANE1); glRotatef (90.0, 1.0, 0.0, 0.0); glutWireSphere(1.0, 20, 16); glPopMatrix(); glFlush ();}
2013-2 학기 3 장 뷰잉
void reshape (int w, int h){ glViewport (0, 0, (GLsizei) w, (GLsizei) h); glMatrixMode (GL_PROJECTION); glLoadIdentity (); gluPerspective(60.0, (GLfloat) w/(GLfloat) h, 1.0, 20.0); glMatrixMode (GL_MODELVIEW);}
void keyboard(unsigned char key, int x, int y){ switch (key) { case 27: exit(0); break; }}
2013-2 학기 3 장 뷰잉
int main(int argc, char** argv){ glutInit(&argc, argv); glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB); glutInitWindowSize (500, 500); glutInitWindowPosition (100, 100); glutCreateWindow (argv[0]); init (); glutDisplayFunc(display); glutReshapeFunc(reshape); glutKeyboardFunc(keyboard); glutMainLoop(); return 0;}
2013-2 학기 3 장 뷰잉
실행결과실행결과
2013-2 학기 3 장 뷰잉
여러가지 변환 함께 사용하기여러가지 변환 함께 사용하기 태양계 만들기
#include <GL/glut.h>
#include <stdlib.h>
static int year = 0, day = 0;
void init(void) {
glClearColor (0.0, 0.0, 0.0, 0.0);
glShadeModel (GL_FLAT);
}
2013-2 학기 3 장 뷰잉
void display(void){ glClear (GL_COLOR_BUFFER_BIT); glColor3f (1.0, 1.0, 1.0);
glPushMatrix(); glutWireSphere(1.0, 20, 16); /* 태양을 그린다 */ glRotatef ((GLfloat) year, 0.0, 1.0, 0.0); glTranslatef (2.0, 0.0, 0.0); glRotatef ((GLfloat) day, 0.0, 1.0, 0.0); glutWireSphere(0.2, 10, 8); /* 작은 행성을 그린다 */ glPopMatrix(); glutSwapBuffers();}
2013-2 학기 3 장 뷰잉
void reshape (int w, int h)
{
glViewport (0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
gluPerspective(60.0, (GLfloat) w/(GLfloat) h, 1.0, 20.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt (0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
}
2013-2 학기 3 장 뷰잉
void keyboard (unsigned char key, int x, int y)
{
switch (key) {
case 'd':
day = (day + 10) % 360;
glutPostRedisplay();
break;
case 'D':
day = (day - 10) % 360;
glutPostRedisplay();
break;
2013-2 학기 3 장 뷰잉
case 'y': year = (year + 5) % 360; glutPostRedisplay(); break; case 'Y': year = (year - 5) % 360; glutPostRedisplay(); break; case 27: exit(0); break; default: break; }}
2013-2 학기 3 장 뷰잉
int main(int argc, char** argv){ glutInit(&argc, argv); glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB); glutInitWindowSize (500, 500); glutInitWindowPosition (100, 100); glutCreateWindow (argv[0]); init (); glutDisplayFunc(display); glutReshapeFunc(reshape); glutKeyboardFunc(keyboard); glutMainLoop(); return 0;}
2013-2 학기 3 장 뷰잉
실행 결과실행 결과
2013-2 학기 3 장 뷰잉
로봇팔 만들기로봇팔 만들기#include <GL/glut.h>
#include <stdlib.h>
static int shoulder = 0, elbow = 0;
void init(void)
{
glClearColor (0.0, 0.0, 0.0, 0.0);
glShadeModel (GL_FLAT);
}
2013-2 학기 3 장 뷰잉
void display(void)
{
glClear (GL_COLOR_BUFFER_BIT);
glPushMatrix();
glTranslatef (-1.0, 0.0, 0.0);
glRotatef ((GLfloat) shoulder, 0.0, 0.0, 1.0);
glTranslatef (1.0, 0.0, 0.0);
glPushMatrix();
glScalef (2.0, 0.4, 1.0);
glutWireCube (1.0);
glPopMatrix();
2013-2 학기 3 장 뷰잉
glTranslatef (1.0, 0.0, 0.0);
glRotatef ((GLfloat) elbow, 0.0, 0.0, 1.0);
glTranslatef (1.0, 0.0, 0.0);
glPushMatrix();
glScalef (2.0, 0.4, 1.0);
glutWireCube (1.0);
glPopMatrix();
glPopMatrix();
glutSwapBuffers();
}
2013-2 학기 3 장 뷰잉
void reshape (int w, int h)
{
glViewport (0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
gluPerspective(65.0, (GLfloat) w/(GLfloat) h, 1.0, 20.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef (0.0, 0.0, -5.0);
}
2013-2 학기 3 장 뷰잉
void keyboard (unsigned char key, int x, int y){ switch (key) { case 's': shoulder = (shoulder + 5) % 360; glutPostRedisplay(); break; case 'S': shoulder = (shoulder - 5) % 360; glutPostRedisplay(); break; case 'e': elbow = (elbow + 5) % 360; glutPostRedisplay(); break;
2013-2 학기 3 장 뷰잉
case 'E':
elbow = (elbow - 5) % 360;
glutPostRedisplay();
break;
case 27:
exit(0);
break;
default:
break;
}
}
2013-2 학기 3 장 뷰잉
int main(int argc, char** argv){ glutInit(&argc, argv); glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB); glutInitWindowSize (500, 500); glutInitWindowPosition (100, 100); glutCreateWindow (argv[0]); init (); glutDisplayFunc(display); glutReshapeFunc(reshape); glutKeyboardFunc(keyboard); glutMainLoop(); return 0;}
2013-2 학기 3 장 뷰잉
실행 결과실행 결과
2013-2 학기 3 장 뷰잉
변환을 역으로 수행하거나 변환을 역으로 수행하거나 흉내내기흉내내기
기하 처리 파이프 라인은 뷰잉 및 투영 행렬 , 뷰포트를 통해 정점의 월드 ( 혹은 오브젝트 ) 좌표를 윈도우 ( 또는 스크린 )좌표로 변환
이러한 처리 순서와 반대로 실행해야 하는 경우가 생김◦ 3 차원상의 위치를 마우스로 선택하는 경우
마우스는 스크린상의 커서의 위치를 나타내는 2차원 값만 반환
프로그램은 변환과정을 역으로 수행하여 마우스로 지정한 스크린의 위치에 대한 3 차원 공간값을 결정해야 한다 .gluUnProject() 와 gluUnProject4() 사용
2013-2 학기 3 장 뷰잉
int gluUnProject(GLdouble winx, GLdouble winy, GLdouble winz, const GLdouble modelMatrix[16], const GLdouble projMatrix[16], const GLint viewport[4], GLdouble *objx, GLdouble *objy, GLdouble *objz);
◦ 모델뷰 행렬 (modelMatrix) 과 투영행렬 (projMatrix), 뷰포트 (viewport) 로 정의된 변환을 사용하여 주어진 윈도우 좌표 (winx, winy, winz) 를 오브젝트 좌표 (objx, objy, objz) 에 매핑한다 .
◦ 함수가 성공적이면 GL_TRUE, 에러가 발생하면 GL_FALSE를 리턴한다 .
2013-2 학기 3 장 뷰잉
Int gluUnProject4(GLdouble winx, GLdouble winy, GLdouble winz, gldouble clipw, const GLdouble modelMatrix[16], const GLdouble projMatrix[16], const GLint viewport[4], Glclampd zNear, Glclampd zFar, GLdouble *objx, GLdouble *objy, GLdouble *objz);
◦ gluUnProject() 와 비슷 . GLU1.3 에서 변경되어 gluUnProject4() 는 표준값이 아닌 glDepthRange 값뿐만 아니라 1보다 큰 w 좌표값도 처리할 수 있다 .
2013-2 학기 3 장 뷰잉
Int gluProject(GLdouble objx, GLdouble objy, GLdouble objz, const GLdouble modelMatrix[16], const GLdouble projMatrix[16], const GLint viewport[4], GLdouble *winx, GLdouble *winy, GLdouble *winz);
◦모델뷰 행렬 (modelMatrix), 투영행렬 (projMatrix), 뷰포트 (viewport) 로 정의된 변환을 통해 주어진 오브젝트 좌표 (objx, objy, objz) 를 윈도우 좌표에 매핑한다 .
◦함수를 성공적으로 수행하면 GL_TRUE, 에러가 발생하면 GL_FALSE 를 리턴한다 .
2013-2 학기 3 장 뷰잉
기하 프로세싱 파이프라인을 반대로 기하 프로세싱 파이프라인을 반대로 실행하기 실행하기 [[ 예제 예제 3 3 –– 8 ]: 8 ]: unproject.cunproject.c
#include <GL/glut.h>#include <stdlib.h>#include <stdio.h>
void display(void){ glClear(GL_COLOR_BUFFER_BIT); glFlush();}void reshape(int w, int h){ glViewport (0, 0, (GLsizei) w, (GLsizei) h); glMatrixMode(GL_PROJECTION); glLoadIdentity();
2013-2 학기 3 장 뷰잉
gluPerspective (45.0, (GLfloat) w/(GLfloat) h, 1.0, 100.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void mouse(int button, int state, int x, int y)
{
GLint viewport[4];
GLdouble mvmatrix[16], projmatrix[16];
GLint realy; /* OpenGL y 좌표 위치 */
GLdouble wx, wy, wz; /* 변환된 x, y ,z 월드 좌표 */
2013-2 학기 3 장 뷰잉
switch (button) {
case GLUT_LEFT_BUTTON:
if (state == GLUT_DOWN) {
glGetIntegerv (GL_VIEWPORT, viewport);
glGetDoublev (GL_MODELVIEW_MATRIX, mvmatrix);
glGetDoublev (GL_PROJECTION_MATRIX, projmatrix);
/* viewport[3] 은 윈도우의 높이를 픽셀 단위로 나타낸다는 것 주의 */
realy = viewport[3] - (GLint) y - 1;
printf ("Coordinates at cursor are (%4d, %4d)\n", x, realy);
gluUnProject ((GLdouble) x, (GLdouble) realy, 0.0,
mvmatrix, projmatrix, viewport, &wx, &wy, &wz);
printf ("World coords at z=0.0 are (%f, %f, %f)\n",
wx, wy, wz);
2013-2 학기 3 장 뷰잉
gluUnProject ((GLdouble) x, (GLdouble) realy, 1.0, mvmatrix, projmatrix, viewport, &wx, &wy, &wz); printf ("World coords at z=1.0 are (%f, %f, %f)\n", wx, wy, wz); } break; case GLUT_RIGHT_BUTTON: if (state == GLUT_DOWN) exit(0); break; default: break; }}
2013-2 학기 3 장 뷰잉
void keyboard(unsigned char key, int x, int y)
{
switch (key) {
case 27:
exit(0);
break;
}
}
2013-2 학기 3 장 뷰잉
int main(int argc, char** argv){ glutInit(&argc, argv); glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB); glutInitWindowSize (500, 500); glutInitWindowPosition (100, 100); glutCreateWindow (argv[0]); glutDisplayFunc(display); glutReshapeFunc(reshape); glutKeyboardFunc (keyboard); glutMouseFunc(mouse); glutMainLoop(); return 0;}
2013-2 학기 3 장 뷰잉
실행 결과실행 결과
2013-2 학기 3 장 뷰잉