[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