86
Chapter 3. 뷰뷰 (Viewing)

Chapter 3. 뷰잉 (Viewing)

Embed Size (px)

DESCRIPTION

Chapter 3. 뷰잉 (Viewing). 3 차원 좌표들의 변환과정. 다음의 세 가지 컴퓨터 연산이 순차적으로 실행되면서 스크린 상의 픽셀로 변환 모델링 , 뷰잉 , 투영 연산 등과 같은 행렬 곱셈으로 표현된 변환 회전 변환 , 평행이동 변환 , 크기 변환 , 반사 , 직교투영 , 원근 투영 등이 포함됨 장면은 사각형 윈도우에 렌더링되기 때문에 오브젝트 또는 오브젝트의 일부가 윈도우 밖에 놓여지는 경우 잘라내는 클리핑 수행 변환된 좌표와 스크린 픽셀을 서로 연결시켜주는 뷰포트 변환. - PowerPoint PPT Presentation

Citation preview

Page 1: Chapter 3.  뷰잉 (Viewing)

Chapter 3. 뷰잉 (Viewing)

Page 2: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 2

3 차원 좌표들의 변환과정

다음의 세 가지 컴퓨터 연산이 순차적으로 실행되면서 스크린 상의 픽셀로 변환 모델링 , 뷰잉 , 투영 연산 등과 같은 행렬 곱셈으로 표현된 변환

회전 변환 , 평행이동 변환 , 크기 변환 , 반사 , 직교투영 , 원근 투영 등이 포함됨

장면은 사각형 윈도우에 렌더링되기 때문에 오브젝트 또는 오브젝트의 일부가 윈도우 밖에 놓여지는 경우 잘라내는 클리핑 수행

변환된 좌표와 스크린 픽셀을 서로 연결시켜주는 뷰포트 변환

Page 3: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 3

뷰잉 (viewing)

카메라 구조

뷰잉 및 모델링 변환

투영 변환

뷰포트 변환

변환에 관련된 문제 해결 방법

행렬 스택 조작하기

부가적인 클리핑 평면

여러가지 변환 함께 사용하기

변환을 역으로 수행하거나 흉내내기

Page 4: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 4

카메라 구조

원하는 장면을 생성하기 위해 거치는 변환 과정은 카메라로 사진을 찍는 것에 비유

삼각대를 세우고 , 카메라가 장면을 향하도록 설정 ( 뷰잉 변환 ) 원하는 장면을 화면에 담도록 모델을 정리 ( 모델링 변환 ) 사용할 카메라 렌즈를 선택하거나 줌을 조절 ( 투영 변환 ) 사진의 크기를 결정한다 ( 뷰포트 변환 ).

Page 5: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 5

정점 변환의 단계 뷰잉 , 모델링 , 투영 변환을 설정하려면 4 * 4 행렬 M 을

만들고 장면의 각 정점 v 에 대한 좌표와 곱해서 수행 v’ = Mv

사용자가 지정한 뷰잉 및 모델링 변환을 통해 모델 뷰 행렬을 만들 수 있는데 이는 입력된 오브젝트 좌표에 적용 , 눈좌표 (eye coordinates) 생성

투영 행렬을 적용하여 클립 좌표 (clip coordinate) 를 생성

좌표값을 w 로 나누는 투시분할 (perspective division) 을 실행하여 정규화 장치 좌표를 생성

변환된 좌표는 뷰포트 변환을 거쳐 윈도우 좌표로 변환

Page 6: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 6

정점 변환의 단계

xyzw

Modelviewmatrix

Projectionmatrix

Perspectivematrix

Viewporttransformation

Vertex

눈좌표

클립좌표

정규화장치좌표

윈도우좌표

오브젝트좌표

Page 7: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 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 (); }

Page 8: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 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; }}

Page 9: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 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;}

Page 10: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 10

실행결과

Page 11: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 11

뷰잉 변환

뷰잉 변환은 카메라의 위치와 방향을 지정하는 것에 비유

위의 [ 예제 3 – 1] glLoadIdentity() 를 사용 , 현재 행렬을 단위행렬로 설정 행렬을 초기화 후 , gluLookAt() 으로 뷰잉 변환 지정

gluLookAt() 을 호출하지 않으면 디폴트 위치와 방향설정

카메라 위치 , 바라볼 방향 , 어느쪽이 위쪽인지를 지정 카메라 위치 : (0, 0, 5) 바라볼 방향 : (0, 0, 0) 업벡터 (up-vector): (0, 1, 0)

Page 12: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 12

모델링 변환

모델의 위치와 방향은 모델링 변환으로 조절 모델을 회전 변환 , 평행이동 변환 , 크기 변환 등을 사용 [ 예제 3 – 1] 에서 glScalef() 를 사용하여 모델링 변환

정육면체를 볼 수 있도록 뷰잉 변환으로 카메라를 이동하는 대신 모델링 변환으로 카메라로부터 떨어지도록 설정 가능

이원성 (duality) 존재로 뷰잉 변환과 모델링 변화을 하나의 모델뷰 행렬 (modelview matrix) 로 설정

Page 13: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 13

투영 변환 투영 변환을 설정하는 것은 카메라 렌즈를 고르는 것과 비슷 화각 (field of view) 이나 관측 공간 (viewing volume) 을 결정 어떤 오브젝트가 관측 공간 안에 들어 있게 되는지 , 어느 정도

보이게 되는지 결정 투영의 방식 ( glFrustum() 사용 )

원근 (perspective) 투영 멀리 있는 물체는 가까이 있는 것보다 작게 나타남 glFrustum() 커맨드 사용

직교 (orthographic) 투영 상대적인 크기에 관계 없이 물체를 스크린에 그대로 매핑 건축설계 및 CAD 설계용 응용 프로그램에서 주로

사용하며 , 정확한 물체의 크기를 표현하는데 중점을 둠

Page 14: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 14

뷰포트 변환 투영 변환과 뷰포트 변환은 장면과 컴퓨터 스크린이 매핑되는

방식을 결정 투영변환은 매핑이 구체적으로 어떻게 이루어지는지 결정 뷰포트 변환은 스크린을 매핑할 스크린 영역의 모양 나타냄

glViewport() 의 인자는 스크린 공간에 대한 원점 , 영역의 폭과 높이 설정 , 픽셀 단위로 표현

이 커맨드는 reshape() 루틴 안에서 호출되어야 함 윈도우의 크기를 변경하면 뷰포트 역시 변경해야 함

Page 15: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 15

장면 그리기 장면에 나온 모든 오브젝트의 각 정점을 모델링 및 뷰잉 변환에

따라 변환 변환된 정점들은 투영 변환에 따라 변환 투영 변환에서 지정된 공간을 벗어나는 오브젝트들은 잘라냄

(Clip) 변환된 정점들을 w 로 나눈 후 뷰포트에 매핑

Page 16: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 16

범용 변환 커맨드 변환을 직접 설정하는데 유용한 커맨드

glMatrixMode() glLoadIdentity() glLoadMatrix*() glMultMatrix*() gluLookAt() glScale()

void glMatrixMode(GLenum mode) 변환 커맨드를 실행하기 전에 모델뷰 , 투영 , 텍스처 행렬을

수정할지 여부 결정 mode : GL_MODELVIEW, GL_PROJECTION, GL_TEXTURE

void glLoadIdentity(void); 나중에 실행할 변환 커맨드를 위해 수정 가능한 행렬을 클리어 현재 수정 가능한 행렬을 4x4 단위 행렬로 설정

Page 17: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 17

현재 행렬로 로드할 행렬을 명시적으로 지정하기 위한 커맨드

void glLoadMatrix{fd}(const TYPE *m); 현재 행렬의 16 개 값 (4 * 4) 을 m 으로 지정된 행렬의

값으로 설정

void glMultMatrix{fd}(const TYPE *m); m 이 가리키는 16 개 값으로 지정된 행렬을 현재 행렬과

곱하고 , 그 결과를 현재 행렬에 저장

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 와는 반대

Page 18: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 18

뷰잉 및 모델링 변환

모델링 변환이나 뷰잉 변환을 실행하기 위해서는 반드시 glMatrixMode() 에 GL_MODELVIEW 를 인자로 주고 호출해야 함 .

변환 이해하기

모든 뷰잉 변환 및 모델링 변환은 4 * 4 행렬로 표현 glMultMatrix*() 과 같은 변환 커맨드들은 새로 주어진 4 * 4

행렬 M 을 현재 모델뷰 행렬 C 와 곱하여 CM 을 생성 그 다음 , 정점 v 를 현재 모델뷰 행렬에 곱함 즉 , 프로그램 상에서 가장 늦게 호출한 변환 커맨드가 정점에

가장 먼저 적용 (CMv)

Page 19: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 19

예제 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 에 적용 .

Page 20: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 20

고정 좌표계 모델의 위치 , 방향 , 크기 등에 영향을 미치는 행렬 곱셈을 고정

좌표계 (Grand, Fixed Coordinate System) 관점에서 생각할 경우 , 코드에 나온 순서와 반대로 곱셈이 수행

연산 ( 회전 , 평행 이동 ) 을 수행한 후 오브젝트가 좌표축에 놓여 있도록 하기 위해서는 ( 오브젝트는 원점에서 생성 )

회전을 먼저 한 후 , 평행이동 시켜야 함

명령문 예 ( 역순으로 지정해야 ) glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glMultMatrixf(T); /* 평행이동 */ glMultMatrixf(R); /* 회 전 */ Draw_the_object();

1-Rotate

2-Translate

Page 21: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 21

로컬 좌표계 이동하기 행렬 곱셈을 바라볼 때 변환할 오브젝트가 고정 좌표계에 있지

않고 , 오브젝트에 로컬 좌표계가 달려 있는 것처럼 생각 모든 연산들은 이러한 좌표계에 상대적으로 수행 이러한 접근 방식에서는 행렬 곱셈이 코드상에 지정된 순서대로

실행 앞의 예제를 다음과 같이 실행하게 된다 .

좌표계가 달린 오브젝트를 그리고 오브젝트와 오브젝트에 지정된 좌표계를 X 축으로 평행

이동시킨다 . 원점에 대해 회전시키면 오브젝트는 X 축상의 평행 이동된

위치에서 회전하게 됨 .

Page 22: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 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*() 사용보다는 위의 세 루틴 사용이 좀 더 빠르게 동작함 .

Page 23: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 23

모델링 변환 예제 솔리드 와이어프레임 삼각형을 아무런 모델링 변환도 적용 안함 삼각형을 대시 모양의 라인 스티플과 평행이동 변환을 사용 높이 (y 축 ) 는 절반 줄이고 폭 (x 축 ) 은 50% 늘인 긴 대시

모양의 라인 스티플 삼각형을 점선으로 표현 , 회전

Page 24: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 24

#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();}

Page 25: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 25

뷰잉 및 모델링 변환

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 ();

Page 26: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 26

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 ();}

Page 27: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 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);}

Page 28: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 28

void keyboard(unsigned char key, int x, int y){ switch (key) { case 27: exit(0); break; }}

Page 29: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 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;}

Page 30: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 30

실행결과

Page 31: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 31

Nate Robins 의 변환관련 튜토리얼

http://www.cs.utah.edu/~narobins/opengl.html transformation 프로그램 실행

Page 32: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 32

뷰잉 변환 뷰잉 변환을 사용하면 시점의 위치와 방향을 변경 카메라 비유에서 본 것처럼 뷰잉 변환은 카메라를 삼각대에 놓고 ,

모델을 향하도록 조절하는 단계 뷰잉 변환은 일반적으로 이동 변환과 회전변환으로 구성 반시계 방향으로 오브젝트를 회전시키는 모델링 변환은 카메라를

시계 방향으로 회전시키는 뷰잉 변환과 동일한 효과를 얻을 수 있다 .

뷰잉 변환에 관련된 커맨드들은 반드시 모델링 변환을 수행하기 전에 호출해야만 오브젝트에 대한 모델링 변환의 효과가 먼저 나타나게 된다 .

뷰잉 변환의 다양한 방법 한 개 이상의 모델링 변환 커맨드 사용

glTranslate*(), glRotate*() 등 유틸리티 라이브러리 루틴인 gluLookAt() 사용 , 시선을

정의 회전 변환 , 이동 변환을 캡슐화 하는 유틸리티를 직접 만듬

Page 33: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 33

glTranslate*() 와 glRotate*() 사용하기

뷰잉변환 표현을 위해 모델링 변환을 사용할 때 오브젝트는 월드 공간에 고정시켜두고 시점만 이동시켜야 하는

경우가 있다 . 초기에는 시점이 원점에 있고 , 대부분 오브젝트는 원점에

생성되어 있기 때문에 몇 가지 변환 필요 카메라는 초기에 z 축의 음의 방향을 향하고 있음 간단한 방법으로 시점을 오브젝트 뒤로 이동

glTranslatef(0.0, 0.0, -5.0); 오브젝트를 장면으로부터 z 축 방향으로 – 5만큼

이동시킨다 . 카메라를 z 축 방향으로 +5 만큼 이동시킨 것과 같은 효과

Page 34: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 34

시점과 오브젝트 분리 : glTranslate(0.0, 0.0, -5.0) 한 후

x

y

z

카메라

z

카메라 x

y

Page 35: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 35

오브젝트를 옆에서 보도록 설정하는 경우

고정 좌표계 방식으로 생각할 경우 오브젝트를 회전 카메라로부터 멀리 떨어지도록 이동 고정 좌표계에서는 실제 효과 순서와 역순으로 커맨드 호출

로컬 좌표계 방식으로 생각할 경우 오브젝트와 로컬 좌표계를 원점으로부터 이동 그 뒤 회전 변환은 이동된 좌표계를 기준으로 회전 로컬 좌표계는 순서대로 커맨드 호출

Page 36: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 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

Page 37: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 37

카메라의 디폴트 위치는 원점이고 디폴트 방향을 z 축의 음의 방향이며 위쪽에 대한 기본값을 y 축의 양의 방향일 때 , gluLookAt(0,0, 0.0, 0.0, 0.0, 0.0, -100, 0.0, 1.0, 0.0);

기준점의 z 값은 어떠한 음수로도 상관 없다 . 같은 효과 .

x

y

z

카메라

x

y

업벡터

Page 38: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 38

gluLookAt(4.0, 2.0, 1.0, 2.0, 4.0, -3.0, 2.0, 2.0, -1.0);

x

y

z

카메라

(4.0, 2.0, 1.0)

(2.0, 4.0, -3.0)

(2,0, 2.0, -1.0)

Page 39: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 39

Nate Robins 의 투영 관련 튜토리얼 projection 프로그램

Page 40: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 40

투영 변환

투영 변환은 관측 공간을 정의하는데 사용 두 가지 방식

오브젝트가 스크린에 투영 되는 형태 ( 원근 , 직교 투영 )최종 이미지에서 어떤 오브젝트가 클리핑 될지를 결정

여기에서 설명하는 커맨드를 호출하기 전에 반드시 다음과 같은 커맨드를 호출

glMatrixMode(GL_PROJECTION); glLoadIdentity();

Page 41: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 41

원근 투영 (perspective projection)

원근투영의 가장 큰 특징은 바로 포쇼트닝 (foreshortening)Foreshortening : 단축법 , 오브젝트가 카메라로부터 멀리 떨어질수록 작게 그리는 기법 이런 효과는 관측 공간을 피라미드의 절두체로 정의할 때 나타남 절두체 : frustum, 밑면과 평행으로 꼭지 부분을 잘라낸 피라미드

오브젝트들은 피라미드의 정점 (apex) 방향으로 투영하며 이 지점에 카메라 혹은 시점 위치시점에 가까이 놓여진 오브텍트들은 먼 것보다 크게 보임

Page 42: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 42

void glFrustum(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far);

원근 투영을 나타내는 행렬을 생성하고 이를 현재 행렬과 곱한다 .

관측 공간 ( 절두체 ) 은 이 공간 밖에 놓인 오브젝트들을 클리핑 하는데 사용됨

절두체 정의 (left, bottom, -near) 와 (right, top, -near) 각각 카메라와 가까운 곳에 위치한 클리핑 평면의 좌측 하단

모서리와 우측 상단 모서리 좌표를 나타냄 near 와 far 인자는 항상 양수로 정해야 함

Page 43: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 43

void gluPerspective(GLdouble fovy, GLdouble aspect, GLdouble near, GLdouble far);

glFrustum() 과 같은 관측 공간 생성 , 지정방식의 차이가 있다 . fovy 는 y 축 방향의 FOV 각도를 나타냄 aspect 인자는 절두체의 종횡비 (x/y, 정사각형의 경우 종횡비는 1.0 이다 )

카메

wh

Aspect = w/h

fovy

near far

Page 44: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 44

직교 투영 (Orthogonal projection) 평행 육면체 모양의 관측 공간을 사용 . 원근 투영과 달리 관측 공간의 양 끝면의 크기가 일정 . 카메라의 거리가 오브젝트의 모양에 영향을 안 미침 . 건축 설계도나 CAD 설계 등과 같이 오브젝트의 크기와 각도를

정확히 유지해야 하는 응용 프로그램에서 주로 사용

관측공간

top

left

far

right

bottomnear

시점방향

Page 45: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 45

직교형 관측 공간의 생성 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 축의 음의 방향

Page 46: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 46

이미지를 2차원 스크린에 투영하는 특수한 경우 void gluOrtho2D(GLdouble left, GLdouble right, GLdouble

bottom, GLdouble top);

2차원 좌표를 스크린에 투영하는 행렬을 생성하고 현재 행렬과 곱한다 . 클리핑 영역

좌측 하단 모서리 (left, bottom) 우측 상단 모서리 (right, top)

Nate Robins 의 투영 관련 튜토리얼 projection 프로그램

관측 공간 클리핑 (clipping)

장면에 있는 오브젝트 정점들을 모델뷰 행렬과 투영 행렬로 모두 변환하였다면 공간의 밖에 있는 모든 프리미티브 들은 클리핑된다 .

Page 47: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 47

뷰포트 변환

뷰포트 변환 카메라에 비유하면 , 뷰포트 변환을 현상할 사진의 크기를

선택하는 단계 컴퓨터 그래픽스에서 뷰포트는 그려질 윈도우의 직사각형

모양의 영역 뷰포트는 윈도우 좌표로 측정 측정된 좌표는 윈도우의 좌측 하단 모서리를 기준으로 스크린

상의 픽셀 위치로 표현

Page 48: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 48

뷰포트 정의하기 스크린 상에 윈도우를 생성하는 작업은 OpenGL 이 아닌 윈도우

시스템이 담당 윈도우를 처음 생성할 때 전체 윈도우에 해당하는 픽셀 영역을

뷰포트로 설정 이보다 작은 영역을 뷰포트로 설정할 때는 glViewport()

커맨드 사용 void glViewport(GLint x, GLint y, Glsizei width, Glsizei

height);최종 이미지가 매핑될 윈도우의 픽셀 사각형을 정의한다 . x, y 매개변수는 이러한 뷰포트의 좌측 하단 모서리 나타냄 width, 와 height 인자는 뷰포트의 크기를 지정

뷰포트의 종횡비는 관측공간의 종횡비와 비슷하다 . 두 비율이 서로 다르면 투영된 이미지가 서로 뒤틀리게 된다 .

Page 49: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 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 으로 설정

Page 50: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 50

행렬 스택 조작하기행렬 스택은 단순한 모델로 부터 복잡한 모델을 구성하는 것처럼 모델을 계층적으로 구성할 때 유용행렬연산 (glLoadMatrix(), glMultMatrix(), glLoadIdentity()) 과 특정한 변환행렬을 생성하는 커맨드들은 현재 행렬이나 스택의 top 행렬을 처리 .현재 행렬에 대한 복사본을 수택의 top 에 복사하는 glPushMatrix() 나 , 스택의 top 행렬을 버리는 glPopMatrix() 와 같은 커맨드를 사용 , top 의 원소를 지정 glPushMatrix() : 현재 위치를 저장 glPopMatrix() : 이전 위치로 되돌려 놓는다 .

void glPushMatrix(void): 현재 스택에 있는 모든 행렬들을 한 단계 아래로 이동 (push)

void glPopMatrix(void); 스택의 top 원소 ( 행렬 ) 를 뽑아낸다 (pop)

현재 스택은 glMatrixMode() 로 결정한다 .

Page 51: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 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(); }

}

Page 52: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 52

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(); …

}

Page 53: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 53

모델뷰 행렬 스택

모델뷰 행렬에는 뷰잉 및 모델링 변환 행렬을 곱한 값들이 누적되어 있다 .각각의 뷰잉 또는 모델링 변환들은 현재 모델뷰 행렬과 곱할 새로운 행렬을 생성변환의 결과로 생성된 행렬은 새로운 현재 행렬로 설정모델뷰 행렬 스택에는 최소 32 개의 4x4 행렬들을 저장할 수 있다 .초기에는 스택의 Top 원소로 단위 행렬이 저장스택의 최대 저장 개수 확인 glGetIntegerv(GL_MAX_MODELVIEW_STACK_DEPTH,

GLint *params);

Page 54: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 54

투영 행렬 스택

투영행렬 스택은 관측 공간을 구성하는 투영 변환을 위한 행렬을 저장투영 행렬을 직접 작성하지 않기 때문에 투영 변환을 수행하기 전에 glLoadIdentity() 를 호출스택의 깊이를 확인 glGetIntegerv(GL_MAX_PROJECTION_STACK_DEPTH,

GLlint *params);

Page 55: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 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);

Page 56: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 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);

Page 57: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 57

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 ();}

Page 58: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 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; }}

Page 59: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 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;}

Page 60: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 60

실행결과

Page 61: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 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);}

Page 62: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 62

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();}

Page 63: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 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);}

Page 64: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 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; glutPostRedisplay(); break;

Page 65: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 65

case 'y': year = (year + 5) % 360; glutPostRedisplay(); break; case 'Y': year = (year - 5) % 360; glutPostRedisplay(); break; case 27: exit(0); break; default: break; }}

Page 66: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 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;}

Page 67: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 67

실행 결과

Page 68: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 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);}

Page 69: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 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); glPushMatrix(); glScalef (2.0, 0.4, 1.0); glutWireCube (1.0); glPopMatrix();

Page 70: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 70

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();}

Page 71: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 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);}

Page 72: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 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; glutPostRedisplay(); break; case 'e': elbow = (elbow + 5) % 360; glutPostRedisplay(); break;

Page 73: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 73

case 'E': elbow = (elbow - 5) % 360; glutPostRedisplay(); break; case 27: exit(0); break; default: break; }}

Page 74: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 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;}

Page 75: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 75

실행 결과

Page 76: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 76

변환을 역으로 수행하거나 흉내내기

기하 처리 파이프 라인은 뷰잉 및 투영 행렬 , 뷰포트를 통해 정점의 월드 ( 혹은 오브젝트 ) 좌표를 윈도우 ( 또는 스크린 ) 좌표로 변환이러한 처리 순서와 반대로 실행해야 하는 경우가 생김 3 차원상의 위치를 마우스로 선택하는 경우

마우스는 스크린상의 커서의 위치를 나타내는 2차원 값만 반환

프로그램은 변환과정을 역으로 수행하여 마우스로 지정한 스크린의 위치에 대한 3 차원 공간값을 결정해야 한다 .

gluUnProject() 와 gluUnProject4() 사용

Page 77: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 77

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 를 리턴한다 .

Page 78: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 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 좌표값도 처리할 수 있다 .

Page 79: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 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 를 리턴한다 .

Page 80: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 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();

Page 81: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 81

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 월드 좌표 */

Page 82: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 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);

Page 83: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 83

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; }}

Page 84: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 84

void keyboard(unsigned char key, int x, int y){ switch (key) { case 27: exit(0); break; }}

Page 85: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 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;}

Page 86: Chapter 3.  뷰잉 (Viewing)

2010-2 학기 가상현실 86

실행 결과