[6th week] cg_practice_implement_of_transformation_projecti

Download Report

Transcript [6th week] cg_practice_implement_of_transformation_projecti

Implement of
transformation ,projection,
viewing
Hanyang University
Jungsik Park
변환 파이프라인
 모델링 변환: 모델좌표계의 3D 객체들을 월드좌표계로 가져옴
 뷰잉 변환: 월드좌표계에서 표현된 3D 객체들을 뷰잉좌표계로
변환

모델링 변환과 뷰잉 변환을 합쳐 모델뷰 변환으로 나타냄.
 투영: 뷰잉좌표계로 변환된 3D 객체들을 2차원 뷰평면에 투영
 윈도우-뷰포트 변환: 투영좌표계의 결과를 출력장치의
장치좌표계로 표현
Division of Electrical and Computer Engineering, Hanyang University
Homogeneous Coordinate System
 Homogeneous Coordinate System 이용
 perspective projection을 matrix 형태로 표현 가능
 여러 단계의 변환을 행렬 곱셈으로 하나의 행렬로 표현
2D
3D
Division of Electrical and Computer Engineering, Hanyang University
OpenGL 변환 행렬
 OpenGL에서는 3D 기하 변환을 위해 4x4 행렬을
사용한다(homogeneous coordinate system).
 열 우선 (column major order) 행렬의 사용
 일반적인 프로그래밍에서 행렬을 표현하는 방식인
행 우선(row major order)이 아닌 열 우선으로 행렬
표현.
 변환 행렬에서 각각 x,y,z축 방향 벡터와 translation
벡터를 나타내는 열벡터의 복사를 빠르게 수행.
 행렬 곱으로 여러 변환을 하나의 행렬로 표현
가능하므로 현재의 변환 행렬만 유지하여
사용한다.

단, 트리/그래프 구조의 모델을 순회할 때 현재의
변환 행렬을 저장하기 위해 행렬 스택을 이용한다.
Division of Electrical and Computer Engineering, Hanyang University
행렬 관련 함수
 void glMatrixMode(GLenum mode)
 현재 행렬을 설정한다.
• mode
• GL_MODELVIEW : 행렬 연산이 모델 관측 스택에 적용된다.
 - 장면 상에서 물체를 이동할 때 사용한다.
• GL_PROJECTION : 행렬 연산이 투영 행렬 스택에 적용된다.
 - 클리핑 공간을 정의할 때 사용한다.
• GL_TEXTURE : 행렬 연산이 텍스쳐 행렬 스택에 적용된다.
 - 텍스쳐 좌표를 조작한다.
 void glLoadIdentity()

이 함수는 현재 변환 행렬을 주어진 단위 행렬로
바꾼다
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
Division of Electrical and Computer Engineering, Hanyang University
행렬 관련 함수
 void glLoadMatrixf(const GLfloat *M)
현재 행렬을 주어진 행렬로 설정한다.
 void glMultMatrixf(const GLfloat *M)
 현재 행렬을 주어진 행렬과 곱한다.
• *M : 이 배열은 현재 변환 행렬로 설정될 4X4행렬을

나타낸다. 이 배열은 16개의 연속된 값을 가지며, 열
우선순위로 저장되어 있다
glMatrixMode(GL_MODELVIEW);
float m[] =
{
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
};
glLoadMatrixf(m);
glMultiMatrixf(m);
Division of Electrical and Computer Engineering, Hanyang University
행렬 관련 함수
 void glGetFloatv(Glenum pname, GLfloat *params)
 현재의 modelview 행렬을 가져오는 경우
float *m;
glGetFloatv(GL_MODELVIEW_MATRIX, m);
 void glPushMatrix ()
현재 행렬을 행렬 스택에 Push 한다
 void glPopMatrix ()
 현재 행렬을 행렬 스택에서 Pop 한다.

Division of Electrical and Computer Engineering, Hanyang University
Modelview 변환 행렬 함수
 void glTranslatef(GLfloat dx, GLfloat dy, GLfloat dz)
 현재 행렬을 이동 변환 행렬과 곱한다.
• dx, dy, dz : x, y, z축 좌표값
 void glScalef(GLfloat sx, GLfloat sy, GLfloat sz)
 현재 행렬과 크기 변환 행렬을 곱한다.
• sx, sy, sz : x, y, z 축에 대한 크기 변환 인수
 void glRotatef(GLfloat angle, GLfloat x, GLfloat y,
GLfloat z)
 현재 행렬과 회전 변환 행렬을 곱한다.
• angle : 회전각을 도(degree)단위로 나타낸다.
• x, y, z : 회전축이 되는 방향 벡터의 x, y, z 성분
Division of Electrical and Computer Engineering, Hanyang University
//방법 1
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotatef(45.0, 0.0, 0.0, 1.0);
glTranslatef(0.5, -0.5, 0.0);
glutSolidCube(0.3);
//방법 2
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.707, 0.0, 0.0);
glRotatef(45.0, 0.0, 0.0, 1.0);
glutSolidCube(0.3);
Division of Electrical and Computer Engineering, Hanyang University
Example
void MyDisplay()
{
glClear(GL_COLOR_BUFFER_BIT);
glViewport(0, 0, 300, 300);
glMatrixMode(GL_MODELVIEW);
//빨간 사각형
glColor3f(1.0, 0.0, 0.0);
glLoadIdentity();
glutSolidCube(0.3);
// 방법 1 녹색 사각형
glColor3f(0.0, 1.0, 0.0);
glLoadIdentity();
glRotatef(45.0, 0.0, 0.0, 1.0);
glTranslatef(0.6, 0.0, 0.0);
glutSolidCube(0.3);
// 방법 2 파란색 사각형
glColor3f(0.0, 0.0, 1.0);
glLoadIdentity();
glTranslatef(0.6, 0.0, 0.0);
glRotatef(45.0, 0.0, 0.0, 1.0);
glutSolidCube(0.3);
glFlush();
}
int main(int argc, char** argv)
{
glutInitDisplayMode(GLUT_RGBA);
glutInitWindowSize(300, 300);
glutCreateWindow("OpenGL Sample Drawing");
glClearColor(1.0, 1.0, 1.0, 1.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
glutDisplayFunc(MyDisplay);
glutMainLoop();
return 0;
}
회전 및 평행이동
변환의 수행 순서에
따라 다른 결과가
나타난다
Division of Electrical and Computer Engineering, Hanyang University
타이머를 사용한 변환
 시간의 변화에 따라 변환을 수행하도록 하는 경우,
타이머를 이용한다.
 void glutTimerFunc(unsigned int mills, void(*func)(int
value), int value);


value : 이벤트 ID. 여러 타이머 이벤트를 처리하고자 할
경우 각 이벤트마다 다른 ID를 부여.
타이머 콜백함수에서는 각 이벤트 ID에 따라 처리를 해
주고, 타이머를 다시 설정해 준다.
Division of Electrical and Computer Engineering, Hanyang University
Example
#include <gl/glut.h>
#include <gl/glu.h>
#include <gl/gl.h>
static int Day = 0, Time = 0;
void MyDisplay()
{
glClear(GL_COLOR_BUFFER_BIT
|GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0, 0.0, -2.0);
/***지구***/
glPushMatrix();
//지구의공전
glRotatef((float)Day, 0.0, 1.0, 0.0);
glTranslatef(0.7, 0.0, 0.0);
//지구의자전
glRotatef((float)Time, 0.0, 1.0, 0.0);
glColor3f(0.5, 0.6, 0.7);
glutSolidSphere(0.1, 30, 8);
/***달***/
glPushMatrix();
//달의공전
glRotatef((float)Time, 0.0, 1.0, 0.0);
glTranslatef(0.2, 0.0, 0.0);
glColor3f(0.9, 0.8, 0.2);
glutSolidSphere(0.04, 30, 8);
glPopMatrix();
glPopMatrix();
/***태양***/
glColor3f(1.0, 0.3, 0.4);
glutSolidSphere(0.2, 30, 16);
glutSwapBuffers();
void MyTimer(int value)
{
Day = (Day + 10) % 360;
Time = (Time + 5) % 360;
glutTimerFunc(100, MyTimer, 1);
glutPostRedisplay();
}
int main(int argc, char** argv)
{
glutInitDisplayMode(GLUT_DOUBLE |
GLUT_RGB);
glutInitWindowSize(500, 500);
glutCreateWindow("Solar system");
glClearColor(0.0, 0.0, 0.0, 0.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 3.0);
glutDisplayFunc(MyDisplay);
glutTimerFunc(100, MyTimer, 1);
glutMainLoop();
return 0;
}
}
Division of Electrical and Computer Engineering, Hanyang University
Division of Electrical and Computer Engineering, Hanyang University
Example - 마우스를 이용한 모델의 회전
#include <gl/glut.h>
bool bDrag = false;
float g_fDistance = -300.0f;
float g_fSpinX = 0.0f;
float g_fSpinY = 0.0f;
int ptLastMousePositX, ptLastMousePositY;
int ptCurrentMousePositX, ptCurrentMousePositY;
void ChangeSize(GLsizei width, GLsizei height)
{
GLfloat fAspect = (GLfloat)width/(GLfloat)height;
GLfloat nRange = height/4.0;
if(height == 0)
height = 1;
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (width <= height)
glOrtho (-nRange, nRange, -nRange/fAspect, nRange/fAspect, -nRange*4.0f, nRange*4.0f);
else
glOrtho (-nRange*fAspect, nRange*fAspect, -nRange, nRange, -nRange*4.0f, nRange*4.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void MyMouseClick(GLint Button, GLint State, GLint X, GLint Y)
{
if(Button == GLUT_LEFT_BUTTON )
{
if (State == GLUT_DOWN)
{
ptLastMousePositX = ptCurrentMousePositX = X;
ptLastMousePositY = ptCurrentMousePositY = Y;
bDrag = true;
}
else if (State == GLUT_UP)
bDrag = false;
}
}
Division of Electrical and Computer Engineering, Hanyang University
void MyMouseMove(GLint X, GLint Y)
{
ptCurrentMousePositX = X;
ptCurrentMousePositY = Y;
if( bDrag )
{
g_fSpinX -= (ptCurrentMousePositX - ptLastMousePositX);
g_fSpinY -= (ptCurrentMousePositY - ptLastMousePositY);
}
ptLastMousePositX = ptCurrentMousePositX;
ptLastMousePositY = ptCurrentMousePositY;
glutPostRedisplay();
}
void RenderScene(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glTranslatef(0.0f, 0.0f, g_fDistance);
glRotatef( -g_fSpinY, 1.0f, 0.0f, 0.0f );
glRotatef( -g_fSpinX, 0.0f, 1.0f, 0.0f );
glColor3f(0.0f, 1.0f, 0.0f);
glutWireTeapot(100.0);
glPopMatrix();
glutSwapBuffers();
}
int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(600, 600);
glutCreateWindow("Perspective Projection");
glutReshapeFunc(ChangeSize);
glutMouseFunc(MyMouseClick);
glutMotionFunc(MyMouseMove);
glutDisplayFunc(RenderScene);
glutMainLoop();
return 0;
}
Division of Electrical and Computer Engineering, Hanyang University
Projection
 View volume
 뷰 평면의 윈도우 내에 투영되는 공간상의 일정 영역
 Orthographic projection
 직육면체의 공간을 뷰 평면에 투영
 void glOrtho(GLdouble left, GLdouble right, GLdouble
bottom, GLdouble top , GLdouble zNear , GLdouble zFar)
Division of Electrical and Computer Engineering, Hanyang University
Projection
 Perspective projection
 프러스텀의 뷰 볼륨을 뷰 평면에 투영
 뷰 볼륨을 정규화된 정육면체로 변환하여 직각투영을
이용하면 투영과 클리핑이 간단해진다.
Division of Electrical and Computer Engineering, Hanyang University
Division of Electrical and Computer Engineering, Hanyang University
Projection 변환 행렬 함수

void glFrustum(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top , GLdouble
zNear , GLdouble zFar)

void gluPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear , GLdouble zFar)
Division of Electrical and Computer Engineering, Hanyang University
Example source
#include <gl/glut.h>
static GLfloat xRot = 0.0f;
static GLfloat yRot = 0.0f;
static int width, height;
bool bPerspective = true;
void SetProjection()
{
GLfloat fAspect = (GLfloat)width/(GLfloat)height;
GLfloat nRange = height/4.0;
if(height == 0)
height = 1;
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (bPerspective)
gluPerspective(60.0f, fAspect, 1.0, 400.0);
else
{
if (width <= height)
glOrtho (-nRange, nRange, -nRange/fAspect, nRange/fAspect, -nRange*4.0f, nRange*4.0f);
else
glOrtho (-nRange*fAspect, nRange*fAspect, -nRange, nRange, -nRange*4.0f, nRange*4.0f);
}
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
Division of Electrical and Computer Engineering, Hanyang University
Example source
void ChangeSize(GLsizei w, GLsizei h)
{
width = w;
height = h;
SetProjection();
}
void SpecialKeys(int key, int x, int y)
{
if(key == GLUT_KEY_UP)
if(key == GLUT_KEY_DOWN)
if(key == GLUT_KEY_LEFT)
if(key == GLUT_KEY_RIGHT)
xRot-= 5.0f;
xRot += 5.0f;
yRot -= 5.0f;
yRot += 5.0f;
xRot = (GLfloat)((const int)xRot % 360);
yRot = (GLfloat)((const int)yRot % 360);
if (key == GLUT_KEY_F1)
{
bPerspective = !bPerspective;
SetProjection();
}
glutPostRedisplay();
}
Division of Electrical and Computer Engineering, Hanyang University
Example source
void RenderScene(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glTranslatef(0.0f, 0.0f, -300.0f);
glRotatef(xRot, 1.0f, 0.0f, 0.0f);
glRotatef(yRot, 0.0f, 1.0f, 0.0f);
glColor3f(1.0f, 0.0f, 0.0f);
glutWireCube(100.0);
glPopMatrix();
glutSwapBuffers();
}
int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(600, 600);
glutCreateWindow("Perspective Projection");
glutReshapeFunc(ChangeSize);
glutSpecialFunc(SpecialKeys);
glutDisplayFunc(RenderScene);
glutMainLoop();
return 0;
}
Division of Electrical and Computer Engineering, Hanyang University
 Orthogonal projection
 Perspective projection
Division of Electrical and Computer Engineering, Hanyang University
시점 이동(gluLookAt)
 void gluLookAt(GLdouble eyex, GLdouble eyey,
GLdouble eyez, GLdouble centerx, GLdouble
centery, GLdouble centerz, GLdouble upx, GLdouble
upy, Gldouble upz)



Eye : 카메라의 위치
Center : 바라볼 장면의 중앙
Up : 카메라의 위쪽 방향을 향하는 상향 벡터
 임의의 시점으로 이동시키는 경우 간단히 사용할 수
있으나, 카메라의 이동에 x축/z축을 회전축으로
회전하는 성분이 있을 경우 up 벡터를 그에 맞춰
계산해 주어야 한다.
Division of Electrical and Computer Engineering, Hanyang University
카메라 오브젝트
 카메라 오브젝트를 만들어 시점 이동에 이용
 Position, forward vector, along vector, up vector를 직접
관리(glRotate, glTranslate 등을 사용하지 않음)
 up, forward, along vector는 각각 서로 직교한다.
 시점이 이동되어야 할 경우 삼각함수와 벡터연산으로 up,
forward, along vector 및 position를 계산하여 업데이트
 up, forward, along vector 및 position으로부터 변환 행렬을
만들어 glLoadMatrix()로 로드시켜 사용.
Division of Electrical and Computer Engineering, Hanyang University
카메라 오브젝트
struct Vector3D
{
float x;
float y;
float z;
};
class Camera {
private:
Vector3D
Vector3D
Vector3D
Vector3D
Position;
Along;
Up;
Forward;
public:
void
void
void
void
...
Pitch(GLfloat theta);
Yaw(GLfloat theta);
Roll(GLfloat theta);
Update();
};
Division of Electrical and Computer Engineering, Hanyang University