Download presentation
Presentation is loading. Please wait.
1
Chapter 3. 뷰잉(Viewing)
2
3차원 좌표들의 변환과정 다음의 세 가지 컴퓨터 연산이 순차적으로 실행되면서 스크린 상의 픽셀로 변환
다음의 세 가지 컴퓨터 연산이 순차적으로 실행되면서 스크린 상의 픽셀로 변환 모델링, 뷰잉, 투영 연산 등과 같은 행렬 곱셈으로 표현된 변환 회전 변환, 평행이동 변환, 크기 변환, 반사, 직교투영, 원근 투영 등이 포함됨 장면은 사각형 윈도우에 렌더링되기 때문에 오브 젝트 또는 오브젝트의 일부가 윈도우 밖에 놓여 지는 경우 잘라내는 클리핑 수행 변환된 좌표와 스크린 픽셀을 서로 연결시켜주는 뷰포트 변환 2012-2학기 3장 뷰잉
3
뷰잉(viewing) 카메라 구조 뷰잉 및 모델링 변환 투영 변환 뷰포트 변환 변환에 관련된 문제 해결 방법
행렬 스택 조작하기 부가적인 클리핑 평면 여러가지 변환 함께 사용하기 변환을 역으로 수행하거나 흉내내기 2012-2학기 3장 뷰잉
4
카메라 구조 원하는 장면을 생성하기 위해 거치는 변환 과정은 카메라로 사진을 찍는 것 에 비유
원하는 장면을 생성하기 위해 거치는 변환 과정은 카메라로 사진을 찍는 것 에 비유 삼각대를 세우고, 카메라가 장면을 향하도 록 설정(뷰잉 변환) 원하는 장면을 화면에 담도록 모델을 정리 (모델링 변환) 사용할 카메라 렌즈를 선택하거나 줌을 조 절(투영 변환) 사진의 크기를 결정한다(뷰포트 변환). 2012-2학기 3장 뷰잉
5
정점 변환의 단계 뷰잉, 모델링, 투영 변환을 설정하려면 4 * 4 행렬 M을 만들고 장면의 각 정점 v에 대한 좌표와 곱해서 수행 v’ = Mv 사용자가 지정한 뷰잉 및 모델링 변환을 통해 모델 뷰 행렬을 만들 수 있 는데 이는 입력된 오브젝트 좌표에 적용, 눈좌표(eye coordinates) 생성 투영 행렬을 적용하여 클립 좌표(clip coordinate)를 생성 좌표값을 w로 나누는 투시분할(perspective division)을 실행하여 정규화 장치 좌표를 생성 변환된 좌표는 뷰포트 변환을 거쳐 윈도우 좌표로 변환 2012-2학기 3장 뷰잉
6
정점 변환의 단계 x y Vertex z w 눈좌표 Modelview matrix 오브젝트 좌표 Projection 클립좌표
정규화장치좌표 Perspective matrix Viewport transformation 윈도우좌표 2012-2학기 3장 뷰잉
7
정육면체를 그리는 간단한 [예제 3 – 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 (); } 2012-2학기 3장 뷰잉
8
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; 2012-2학기 3장 뷰잉
9
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; } 2012-2학기 3장 뷰잉
10
실행결과 2012-2학기 3장 뷰잉
11
뷰잉 변환 뷰잉 변환은 카메라의 위치와 방향을 지정하는 것에 비유 위의 [예제 3 – 1]
glLoadIdentity()를 사용, 현재 행렬을 단위행렬로 설정 행렬을 초기화 후, gluLookAt()으로 뷰잉 변환 지정 gluLookAt()을 호출하지 않으면 디폴트 위치와 방향설정 카메라 위치, 바라볼 방향, 어느쪽이 위쪽인지를 지정 카메라 위치: (0, 0, 5) 바라볼 방향: (0, 0, 0) 업벡터(up-vector): (0, 1, 0) 2012-2학기 3장 뷰잉
12
모델링 변환 모델의 위치와 방향은 모델링 변환으로 조절 모델을 회전 변환, 평행이동 변환, 크기 변환 등을 사용
[예제 3 – 1] 에서 glScalef()를 사용하여 모델링 변환 정육면체를 볼 수 있도록 뷰잉 변환으로 카메라를 이동하 는 대신 모델링 변환으로 카메라로부터 떨어지도록 설정 가능 이원성(duality) 존재로 뷰잉 변환과 모델링 변화을 하나의 모델뷰 행렬(modelview matrix) 로 설정 2012-2학기 3장 뷰잉
13
투영 변환 투영 변환을 설정하는 것은 카메라 렌즈를 고르는 것과 비슷
화각(field of view)이나 관측 공간(viewing volume)을 결정 어떤 오브젝트가 관측 공간 안에 들어 있게 되는지, 어느 정도 보이게 되는지 결정 투영의 방식 ( glFrustum() 사용 ) 원근(perspective) 투영 멀리 있는 물체는 가까이 있는 것보다 작게 나타남 glFrustum() 커맨드 사용 직교(orthographic) 투영 상대적인 크기에 관계 없이 물체를 스크린에 그대로 매핑 건축설계 및 CAD 설계용 응용 프로그램에서 주로 사용하며, 정확한 물체의 크기를 표현하는데 중점을 둠 2012-2학기 3장 뷰잉
14
뷰포트 변환 투영 변환과 뷰포트 변환은 장면과 컴퓨터 스크린이 매핑 되는 방식을 결정
투영변환은 매핑이 구체적으로 어떻게 이루어지는지 결 정 뷰포트 변환은 스크린을 매핑할 스크린 영역의 모양 나 타냄 glViewport()의 인자는 스크린 공간에 대한 원점, 영역의 폭 과 높이 설정, 픽셀 단위로 표현 이 커맨드는 reshape()루틴 안에서 호출되어야 함 윈도우의 크기를 변경하면 뷰포트 역시 변경해야 함 2012-2학기 3장 뷰잉
15
장면 그리기 장면에 나온 모든 오브젝트의 각 정점 을 모델링 및 뷰잉 변환에 따라 변환
변환된 정점들은 투영 변환에 따라 변 환 투영 변환에서 지정된 공간을 벗어나 는 오브젝트들은 잘라냄(Clip) 변환된 정점들을 w로 나눈 후 뷰포트 에 매핑 2012-2학기 3장 뷰잉
16
범용 변환 커맨드 변환을 직접 설정하는데 유용한 커맨드 glMatrixMode() glLoadIdentity()
glLoadMatrix*() glMultMatrix*() gluLookAt() glScale() void glMatrixMode(GLenum mode) 변환 커맨드를 실행하기 전에 모델뷰, 투영, 텍스처 행렬을 수정할지 여부 결정 mode : GL_MODELVIEW, GL_PROJECTION, GL_TEXTURE void glLoadIdentity(void); 나중에 실행할 변환 커맨드를 위해 수정 가능한 행렬을 클리어 현재 수정 가능한 행렬을 4x4 단위 행렬로 설정 2012-2학기 3장 뷰잉
17
현재 행렬로 로드할 행렬을 명시적으로 지정하기 위한 커맨드 void glLoadMatrix{fd}(const TYPE *m);
void glMultMatrix{fd}(const TYPE *m); m이 가리키는 16개 값으로 지정된 행렬을 현재 행렬과 곱하고, 그 결과를 현재 행렬에 저장 m1 m5 m9 m13 [주의사항] 행렬을 m[4][4]로 선언했다면 m[i][j] 원소는 OpenGL 변환 행렬의 j행, i 열에 있음. C와는 반대 m2 m6 m10 m14 M = m3 m7 m11 m15 m4 m8 m12 m16 2012-2학기 3장 뷰잉
18
뷰잉 및 모델링 변환 모델링 변환이나 뷰잉 변환을 실행하기 위해서는 반드시 glMatrixMode()에 GL_MODELVIEW 를 인자로 주고 호출해야 함. 변환 이해하기 모든 뷰잉 변환 및 모델링 변환은 4 * 4행렬로 표현 glMultMatrix*()과 같은 변환 커맨드들은 새로 주어진 4 * 4행 렬 M을 현재 모델뷰 행렬 C와 곱하여 CM을 생성 그 다음, 정점 v를 현재 모델뷰 행렬에 곱함 즉, 프로그램 상에서 가장 늦게 호출한 변환 커맨드가 정점 에 가장 먼저 적용(CMv) 2012-2학기 3장 뷰잉
19
glMatrixMode (GL_MODELVIEW); glLoadIdentity(); glMultMatrix(N);
예제 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 에 적용. 2012-2학기 3장 뷰잉
20
고정 좌표계 모델의 위치, 방향, 크기 등에 영향을 미치는 행렬 곱셈을 고정 좌표계 (Grand, Fixed Coordinate System) 관점에서 생각할 경우, 코드에 나온 순서와 반대로 곱셈이 수행 연산(회전, 평행 이동)을 수행한 후 오브젝트가 좌표축에 놓여 있도록 하기 위해서는(오브젝트는 원점에서 생성) 회전을 먼저 한 후, 평행이동 시켜야 함 명령문 예(역순으로 지정해야) glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glMultMatrixf(T); /* 평행이동 */ glMultMatrixf(R); /* 회 전 */ Draw_the_object(); 1-Rotate 2-Translate 2012-2학기 3장 뷰잉
21
로컬 좌표계 이동하기 행렬 곱셈을 바라볼 때 변환할 오브젝트가 고정 좌 표계에 있지 않고, 오브젝트에 로컬 좌표계가 달려 있는 것처럼 생각 모든 연산들은 이러한 좌표계에 상대적으로 수행 이러한 접근 방식에서는 행렬 곱셈이 코드상에 지정 된 순서대로 실행 앞의 예제를 다음과 같이 실행하게 된다. 좌표계가 달린 오브젝트를 그리고 오브젝트와 오브젝트에 지정된 좌표계를 X축으로 평행 이동시킨다. 원점에 대해 회전시키면 오브젝트는 X축상의 평 행 이동된 위치에서 회전하게 됨. 2012-2학기 3장 뷰잉
22
모델링 변환 모델링 변환을 위해 세가지 커맨드들을 제공 평행이동
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*() 사용보다는 위의 세 루틴 사용이 좀 더 빠르게 동작함. 2012-2학기 3장 뷰잉
23
모델링 변환 예제 솔리드 와이어프레임 삼각형을 아무런 모델링 변환도 적용 안함
솔리드 와이어프레임 삼각형을 아무런 모델링 변환도 적용 안함 삼각형을 대시 모양의 라인 스티플과 평행이동 변환을 사용 높이(y축)는 절반 줄이고 폭(x축)은 50% 늘인 긴 대시 모양의 라인 스티플 삼각형을 점선으로 표현, 회전 2012-2학기 3장 뷰잉
24
#include <GL/glut. h> #include <stdlib
#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(); 2012-2학기 3장 뷰잉
25
뷰잉 및 모델링 변환 void display(void){ glClear (GL_COLOR_BUFFER_BIT); glColor3f (1.0, 1.0, 1.0); glLoadIdentity (); draw_triangle (); glEnable (GL_LINE_STIPPLE); glLineStipple (1, 0xF0F0); glTranslatef (-20.0, 0.0, 0.0); 2012-2학기 3장 뷰잉
26
glDisable (GL_LINE_STIPPLE); glFlush (); }
glLineStipple (1, 0xF00F); glLoadIdentity (); glScalef (1.5, 0.5, 1.0); draw_triangle (); glLineStipple (1, 0x8888); glRotatef (90.0, 0.0, 0.0, 1.0); glDisable (GL_LINE_STIPPLE); glFlush (); } 2012-2학기 3장 뷰잉
27
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); } 2012-2학기 3장 뷰잉
28
void keyboard(unsigned char key, int x, int y) { switch (key) { case 27: exit(0); break; }
2012-2학기 3장 뷰잉
29
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; } 2012-2학기 3장 뷰잉
30
실행결과 2012-2학기 3장 뷰잉
31
Nate Robins 의 변환관련 튜토리얼 http://www.cs.utah.edu/~narobins/opengl.html
transformation 프로그램 실행 2012-2학기 3장 뷰잉
32
뷰잉 변환 뷰잉 변환을 사용하면 시점의 위치와 방향을 변경
카메라 비유에서 본 것처럼 뷰잉 변환은 카메라를 삼각대에 놓고, 모 델을 향하도록 조절하는 단계 뷰잉 변환은 일반적으로 이동 변환과 회전변환으로 구성 반시계 방향으로 오브젝트를 회전시키는 모델링 변환은 카메라를 시 계 방향으로 회전시키는 뷰잉 변환과 동일한 효과를 얻을 수 있다. 뷰잉 변환에 관련된 커맨드들은 반드시 모델링 변환을 수행하기 전에 호출해야만 오브젝트에 대한 모델링 변환의 효과가 먼저 나타나게 된 다. 뷰잉 변환의 다양한 방법 한 개 이상의 모델링 변환 커맨드 사용 glTranslate*(), glRotate*() 등 유틸리티 라이브러리 루틴인 gluLookAt() 사용, 시선을 정의 회전 변환, 이동 변환을 캡슐화 하는 유틸리티를 직접 만듬 2012-2학기 3장 뷰잉
33
glTranslate*() 와 glRotate*() 사용하기
뷰잉변환 표현을 위해 모델링 변환을 사용할 때 오브젝트는 월드 공간에 고정시켜두고 시점만 이동시켜야 하는 경 우가 있다. 초기에는 시점이 원점에 있고, 대부분 오브젝트는 원점에 생성되어 있기 때문에 몇 가지 변환 필요 카메라는 초기에 z 축의 음의 방향을 향하고 있음 간단한 방법으로 시점을 오브젝트 뒤로 이동 glTranslatef(0.0, 0.0, -5.0); 오브젝트를 장면으로부터 z축 방향으로 –5만큼 이동시킨다. 카메라를 z축 방향으로 +5만큼 이동시킨 것과 같은 효과 2012-2학기 3장 뷰잉
34
시점과 오브젝트 분리: glTranslate(0.0, 0.0, -5.0) 한 후
y y 카메라 카메라 x x z z 2012-2학기 3장 뷰잉
35
고정 좌표계에서는 실제 효과 순서와 역순으로 커맨드 호출
오브젝트를 옆에서 보도록 설정하는 경우 고정 좌표계 방식으로 생각할 경우 오브젝트를 회전 카메라로부터 멀리 떨어지도록 이동 고정 좌표계에서는 실제 효과 순서와 역순으로 커맨드 호출 로컬 좌표계 방식으로 생각할 경우 오브젝트와 로컬 좌표계를 원점으로부터 이동 그 뒤 회전 변환은 이동된 좌표계를 기준으로 회전 로컬 좌표계는 순서대로 커맨드 호출 2012-2학기 3장 뷰잉
36
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 2012-2학기 3장 뷰잉
37
카메라의 디폴트 위치는 원점이고 디폴트 방향을 z 축의 음 의 방향이며 위쪽에 대한 기본값을 y축의 양의 방향일 때,
gluLookAt(0,0, 0.0, 0.0, 0.0, 0.0, -100, 0.0, 1.0, 0.0); 기준점의 z 값은 어떠한 음수로도 상관 없다. 같은 효과. y y 업벡터 x 카메라 x z 2012-2학기 3장 뷰잉
38
gluLookAt(4.0, 2.0, 1.0, 2.0, 4.0, -3.0, 2.0, 2.0, -1.0); y (2.0, 4.0, -3.0) (2,0, 2.0, -1.0) 카메라 (4.0, 2.0, 1.0) x z 2012-2학기 3장 뷰잉
39
Nate Robins 의 투영 관련 튜토리얼 projection 프로그램 2012-2학기 3장 뷰잉
40
투영 변환 투영 변환은 관측 공간을 정의하는데 사용 두 가지 방식
오브젝트가 스크린에 투영 되는 형태(원근, 직교 투영) 최종 이미지에서 어떤 오브젝트가 클리핑 될지를 결정 여기에서 설명하는 커맨드를 호출하기 전에 반 드시 다음과 같은 커맨드를 호출 glMatrixMode(GL_PROJECTION); glLoadIdentity(); 2012-2학기 3장 뷰잉
41
원근 투영(perspective projection)
원근투영의 가장 큰 특징은 바로 포쇼트닝(foreshortening) Foreshortening : 단축법, 오브젝트가 카메라로부터 멀리 떨어질수록 작 게 그리는 기법 이런 효과는 관측 공간을 피라미드의 절두체로 정의할 때 나타남 절두체 : frustum, 밑면과 평행으로 꼭지 부분을 잘라낸 피라미드 오브젝트들은 피라미드의 정점(apex)방향으로 투영하며 이 지점에 카메 라 혹은 시점 위치 시점에 가까이 놓여진 오브텍트들은 먼 것보다 크게 보임 Wikipedia Figure shows two different projections of a stack of two cubes, illustrating oblique parallel projection foreshortening ("A") and perspective foreshortening ("B"). 2012-2학기 3장 뷰잉
42
원근 투영을 나타내는 행렬을 생성하고 이를 현재 행렬과 곱한다.
void glFrustum(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far); 원근 투영을 나타내는 행렬을 생성하고 이를 현재 행렬과 곱한다. 관측 공간(절두체)은 이 공간 밖에 놓인 오브젝트들을 클리핑 하 는데 사용됨 절두체 정의 (left, bottom, -near)와 (right, top, -near) 각각 카메라와 가까운 곳에 위치한 클리핑 평면의 좌측 하단 모서리와 우측 상단 모서리 좌표를 나타냄 near 와 far 인자는 항상 양수로 정해야 함 2012-2학기 3장 뷰잉
43
glFrustum()과 같은 관측 공간 생성, 지정방식의 차이가 있다. fovy는 y축 방향의 FOV 각도를 나타냄
void gluPerspective(GLdouble fovy, GLdouble aspect, GLdouble near, GLdouble far); glFrustum()과 같은 관측 공간 생성, 지정방식의 차이가 있다. fovy는 y축 방향의 FOV 각도를 나타냄 aspect 인자는 절두체의 종횡비(x/y, 정사각형의 경우 종횡비는 1.0 이다) fovy h w near 카메라 far Aspect = w/h 2012-2학기 3장 뷰잉
44
직교 투영(Orthogonal projection)
평행 육면체 모양의 관측 공간을 사용. 원근 투영과 달리 관측 공간의 양 끝면의 크기가 일정. 카메라의 거리가 오브젝트의 모양에 영향을 안 미침. 건축 설계도나 CAD 설계 등과 같이 오브젝트의 크기와 각도를 정확히 유지해야 하는 응용 프로그램에서 주로 사용 top left far 관측공간 right 시점방향 bottom near 2012-2학기 3장 뷰잉
45
직교관측공간의 행렬을 생성하고 이를 현재 행렬과 곱한다. glFrustum()과 동일한 방식의 인자.
직교형 관측 공간의 생성 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축의 음의 방향 2012-2학기 3장 뷰잉
46
2차원 좌표를 스크린에 투영하는 행렬을 생성하고 현재 행렬과 곱한다. 클리핑 영역 좌측 하단 모서리 (left, bottom)
이미지를 2차원 스크린에 투영하는 특수한 경우 void gluOrtho2D(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top); 2차원 좌표를 스크린에 투영하는 행렬을 생성하고 현재 행렬과 곱한다. 클리핑 영역 좌측 하단 모서리 (left, bottom) 우측 상단 모서리 (right, top) Nate Robins 의 투영 관련 튜토리얼 projection 프로그램 관측 공간 클리핑(clipping) 장면에 있는 오브젝트 정점들을 모델뷰 행렬과 투영 행렬로 모두 변환하 였다면 공간의 밖에 있는 모든 프리미티브 들은 클리핑된다. 2012-2학기 3장 뷰잉
47
뷰포트 변환 뷰포트 변환 카메라에 비유하면, 뷰포트 변환을 현상할 사진의 크기를 선택하는 단계
뷰포트 변환 뷰포트 변환 카메라에 비유하면, 뷰포트 변환을 현상할 사진의 크기를 선택하는 단계 컴퓨터 그래픽스에서 뷰포트는 그려질 윈 도우의 직사각형 모양의 영역 뷰포트는 윈도우 좌표로 측정 측정된 좌표는 윈도우의 좌측 하단 모서리 를 기준으로 스크린 상의 픽셀 위치로 표 현 2012-2학기 3장 뷰잉
48
뷰포트 정의하기 스크린 상에 윈도우를 생성하는 작업은 OpenGL이 아닌 윈도우 시스 템이 담당
윈도우를 처음 생성할 때 전체 윈도우에 해당하는 픽셀 영역을 뷰포 트로 설정 이보다 작은 영역을 뷰포트로 설정할 때는 glViewport() 커맨드 사용 void glViewport(GLint x, GLint y, Glsizei width, Glsizei height); 최종 이미지가 매핑될 윈도우의 픽셀 사각형을 정의한다. x, y 매개변수는 이러한 뷰포트의 좌측 하단 모서리 나타냄 width, 와 height 인자는 뷰포트의 크기를 지정 뷰포트의 종횡비는 관측공간의 종횡비와 비슷하다. 두 비율이 서로 다르면 투영된 이미지가 서로 뒤틀리게 된다. 2012-2학기 3장 뷰잉
49
변환된 깊이 좌표 뷰포트 변환이 수행되는 동안 깊이(z) 좌표는 인코딩
Z 값을 원하는 범위 내에서 조절하려면 glDepthRange()사용 윈도우의 x, y 좌표와는 달리 OpenGL 에서 z 좌표는 항상 0.0과 1.0 사이 에 있는 것으로 취급된다. void glDepthRange(GLclampd near, GLclampd far); 뷰포트 변환에서 사용될 z 좌표를 인코딩한다. near, far 인자는 깊이 버퍼에 저장될 최소 및 최대 수정 범위 기본적으로 이 값은 0.0 과 1.0 으로 설정 2012-2학기 3장 뷰잉
50
행렬 스택 조작하기 행렬 스택은 단순한 모델로 부터 복잡한 모델을 구성하는 것처럼 모델을 계층 적으로 구성할 때 유용
행렬연산(glLoadMatrix(), glMultMatrix(), glLoadIdentity())과 특정한 변환행렬을 생성하는 커맨드들은 현재 행렬이나 스택의 top행렬을 처리. 현재 행렬에 대한 복사본을 수택의 top에 복사하는 glPushMatrix()나, 스택의 top행렬을 버리는 glPopMatrix()와 같은 커맨드를 사용, top 의 원소를 지정 glPushMatrix() : 현재 위치를 저장 glPopMatrix() : 이전 위치로 되돌려 놓는다. void glPushMatrix(void): 현재 스택에 있는 모든 행렬들을 한 단계 아래로 이동(push) void glPopMatrix(void); 스택의 top원소(행렬) 를 뽑아낸다(pop) 현재 스택은 glMatrixMode()로 결정한다. 2012-2학기 3장 뷰잉
51
예제 3-4 행렬을 push 또는 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(); } 2012-2학기 3장 뷰잉
52
draw_body_and_wheel_and_bolts() { draw_car_body(); glPushMatrix(); glTranslatef(40, 0, 30); /* 첫번째 바퀴의 위치로 이동 */ draw_wheel_and_bolts(); glPopMatrix(); glTranslatef(40, 0, -30); /* 두 번째 바퀴의 위치로 이동 */ … } 2012-2학기 3장 뷰잉
53
모델뷰 행렬 스택 모델뷰 행렬에는 뷰잉 및 모델링 변환 행렬을 곱한 값들이 누적되 어 있다.
각각의 뷰잉 또는 모델링 변환들은 현재 모델뷰 행렬과 곱할 새로 운 행렬을 생성 변환의 결과로 생성된 행렬은 새로운 현재 행렬로 설정 모델뷰 행렬 스택에는 최소 32개의 4x4 행렬들을 저장할 수 있다. 초기에는 스택의 Top원소로 단위 행렬이 저장 스택의 최대 저장 개수 확인 glGetIntegerv(GL_MAX_MODELVIEW_STACK_DEPTH, GLint *params); 2012-2학기 3장 뷰잉
54
투영 행렬 스택 투영행렬 스택은 관측 공간을 구성하는 투영 변환을 위한 행렬을 저장
투영행렬 스택은 관측 공간을 구성하는 투영 변환을 위한 행렬을 저장 투영 행렬을 직접 작성하지 않기 때문에 투영 변환을 수행하기 전 에 glLoadIdentity()를 호출 스택의 깊이를 확인 glGetIntegerv(GL_MAX_PROJECTION_STACK_DEPTH, GLlint *params); 2012-2학기 3장 뷰잉
55
부가적인 클리핑 평면 관측공간에 존재하는 여섯 개의 클리핑 평면(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); 2012-2학기 3장 뷰잉
56
클리핑 평면에 대한 코드 [예제 3 – 5 ]: 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); 2012-2학기 3장 뷰잉
57
glColor3f (1. 0, 1. 0, 1. 0); glPushMatrix(); glTranslatef (0. 0, 0
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 (); } 2012-2학기 3장 뷰잉
58
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; 2012-2학기 3장 뷰잉
59
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; } 2012-2학기 3장 뷰잉
60
실행결과 2012-2학기 3장 뷰잉
61
여러가지 변환 함께 사용하기 태양계 만들기 #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); } 2012-2학기 3장 뷰잉
62
void display(void){ glClear (GL_COLOR_BUFFER_BIT); glColor3f (1. 0, 1
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(); } 2012-2학기 3장 뷰잉
63
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); } 2012-2학기 3장 뷰잉
64
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; 2012-2학기 3장 뷰잉
65
case 'y': year = (year + 5) % 360; glutPostRedisplay(); break; case 'Y': year = (year - 5) % 360; case 27: exit(0); default: break; } } 2012-2학기 3장 뷰잉
66
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; } 2012-2학기 3장 뷰잉
67
실행 결과 2012-2학기 3장 뷰잉
68
로봇팔 만들기 #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); } 2012-2학기 3장 뷰잉
69
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); glScalef (2.0, 0.4, 1.0); glutWireCube (1.0); glPopMatrix(); 2012-2학기 3장 뷰잉
70
glTranslatef (1. 0, 0. 0, 0. 0); glRotatef ((GLfloat) elbow, 0. 0, 0
glTranslatef (1.0, 0.0, 0.0); glRotatef ((GLfloat) elbow, 0.0, 0.0, 1.0); glPushMatrix(); glScalef (2.0, 0.4, 1.0); glutWireCube (1.0); glPopMatrix(); glutSwapBuffers(); } 2012-2학기 3장 뷰잉
71
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); } 2012-2학기 3장 뷰잉
72
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; case 'e': elbow = (elbow + 5) % 360; 2012-2학기 3장 뷰잉
73
case 'E': elbow = (elbow - 5) % 360; glutPostRedisplay(); break; case 27: exit(0); default: }
2012-2학기 3장 뷰잉
74
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; } 2012-2학기 3장 뷰잉
75
실행 결과 2012-2학기 3장 뷰잉
76
변환을 역으로 수행하거나 흉내내기 기하 처리 파이프 라인은 뷰잉 및 투영 행렬, 뷰포트를 통해 정점 의 월드(혹은 오브젝트)좌표를 윈도우(또는 스크린)좌표로 변환 이러한 처리 순서와 반대로 실행해야 하는 경우가 생김 3차원상의 위치를 마우스로 선택하는 경우 마우스는 스크린상의 커서의 위치를 나타내는 2차원 값만 반환 프로그램은 변환과정을 역으로 수행하여 마우스로 지정한 스크린의 위치에 대한 3차원 공간값을 결정해야 한다. gluUnProject() 와 gluUnProject4() 사용 2012-2학기 3장 뷰잉
77
함수가 성공적이면 GL_TRUE, 에러가 발생하면 GL_FALSE를 리 턴한다.
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를 리 턴한다. 2012-2학기 3장 뷰잉
78
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 좌표값 도 처리할 수 있다. 2012-2학기 3장 뷰잉
79
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를 리턴한다. 2012-2학기 3장 뷰잉
80
기하 프로세싱 파이프라인을 반대로 실행하기 [예제 3 – 8 ]: unproject.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(); 2012-2학기 3장 뷰잉
81
gluPerspective (45. 0, (GLfloat) w/(GLfloat) h, 1. 0, 100
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 월드 좌표 */ 2012-2학기 3장 뷰잉
82
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); 2012-2학기 3장 뷰잉
83
gluUnProject ((GLdouble) x, (GLdouble) realy, 1
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); default: 2012-2학기 3장 뷰잉
84
void keyboard(unsigned char key, int x, int y) { switch (key) { case 27: exit(0); break; }
2012-2학기 3장 뷰잉
85
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; } 2012-2학기 3장 뷰잉
86
실행 결과 2012-2학기 3장 뷰잉
Similar presentations