Computer Graphics

Chapter08. 시점변환(gluLookat)

CodeJB 2021. 6. 5. 18:25

시점 변환

지난 시간까지 모델변환을 통해서 Object의 기하변환을 가하였고, 전역 좌표계와 모델 좌표계 등에 대해서 알았다. 이젠 Viewer의 관점에서 오브젝트를 어디서, 어떤 방향으로 볼 것인지를 결정해줄 것이다. 가장 핵심적인 함수는 gluLookat이고 이전 시간에도 사용해왔다.


void WINAPI gluLookAt(GLdouble eyex,GLdouble eyey,GLdouble eyez,
GLdouble centerx,GLdouble centery,GLdouble centerz,
GLdouble upx,GLdouble upy,GLdouble upz
);
: View Transform Matrix를 정의하는 함수
: 시점 좌표계를 정의하는 함수로, (eyeX, eyeY, eyeZ)에 있는 카메라가 (centerX, centerY, cneterZ)에 있는 
  초점을 바라보는 것이다.
: (upX, upY, upZ)는 카메라 상향 벡터이다. 카메라의 머리를 어느 방향으로 하느냐에 따라서 카메라가 회전을 할 것이다
: 한마디로 카메라의 방향이라고 생각하면 된다.

sideVector는 UpVector와 ForwardVector의 외적이다. 두 벡터의 곱은, 두 벡터가 이루는 평면에 수직인 벡터를 만든다.

OpenGL 실습 : 카메라 회전과 애니메이션 적용

#include <OpenGL/OpenGL.h>
#include <GLUT/GLUT.h>
#include <math.h>
#include <iostream>

#define _WINDOW_WIDTH 800
#define _WINDOW_HEIGHT 800

int angle_upper = 0;
int angle_lower = 0;

int dir_upper = 1;
int dir_lower = 1;

GLfloat camPos_x = 0.5, camPos_y = 0.5, camPos_z = 1; //위치
GLfloat camAt_x = 0, camAt_y = 0, camAt_z = 0; //바라보는 곳
GLfloat camUp_x = 0, camUp_y = 1, camUp_z = 0; //방향

void MyReshape(int width, int height){
    glViewport(0, 0, width, height);
    GLfloat f_w = (GLfloat)width / (GLfloat)_WINDOW_WIDTH;
    GLfloat f_h = (GLfloat)height / (GLfloat)_WINDOW_HEIGHT;
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-1.0*f_w, 1.0*f_w, -1.0*f_h, 1.0*f_h, -2, 2);
}

void drawXAxis(){
    glBegin(GL_LINES);
        //선
        glVertex3f(0, 0, 0);
        glVertex3f(0.3, 0, 0);
        //선머리
        glVertex3f(0.3, 0, 0);
        glVertex3f(0.21, 0.09, 0);
        //선머리
        glVertex3f(0.3, 0, 0);
        glVertex3f(0.21, -0.09, 0);
    
    glEnd();
}

void drawAxis(){
    glColor3f(1, 1, 1);
   // glMatrixMode(GL_MODELVIEW);
   // glLoadIdentity(); // 초기화

    drawXAxis();
    glPushMatrix();//행렬 스택에 push
        glRotatef(90, 0, 0, 1);
        drawXAxis();
    glPopMatrix(); //모델 좌표계의 행렬스택중 Top Data삭제
    
    glPushMatrix();
        glRotatef(-90, 0, 1, 0);
        drawXAxis();
    glPopMatrix();
}

void drawCuboid(GLfloat sx, GLfloat sy, GLfloat sz){
    glPushMatrix();
        glScalef(sx, sy, sz);
        glutWireCube(1);
    glPopMatrix();
}

void drawBody(){
    drawAxis();
    drawCuboid(0.5,1,0.2);
}

void drawHead(){
    glPushMatrix();
    glTranslatef(0, 0.55, 0);
    drawAxis();
    drawCuboid(0.3, 0.1, 0.2);
    glPopMatrix();
}

void drawUpperArm(GLfloat Angle){
    glTranslatef(0.25,0.3, 0);
    glRotatef(Angle, 0, 0, 1);
    glTranslatef(0.25,0, 0);
    drawCuboid(0.5, 0.2, 0.2);
}

void drawLowerArm(GLfloat Angle){
    drawAxis();//Axis확인하면서 평행이동하면 편함
    glTranslatef(0.25,0, 0);
    glRotatef(Angle, 0, 0, 1);
    glTranslatef(0.25,0, 0);
    drawAxis();
    drawCuboid(0.5, 0.2, 0.2);
}

void drawHand(){
    glTranslatef(0.35, 0, 0);
    glutWireSphere(0.1, 15, 15);
}

void drawFinger1(){
    glPushMatrix();
        glTranslatef(0.15, 0, 0);
        drawCuboid(0.1, 0.05, 0.05);
    glPopMatrix();
}
void drawFinger2(){
    glPushMatrix();
        glRotatef(30, 0, 0, 1);
        glTranslatef(0.15, 0, 0);
        drawCuboid(0.1, 0.05, 0.05);
    glPopMatrix();
}

void MyDisplay(){
    glClear(GL_COLOR_BUFFER_BIT);
    //drawAxis();
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    
    gluLookAt(camPos_x, camPos_y, camPos_z, camAt_x, camAt_y, camAt_z, camUp_x,camUp_y, camUp_z);
    
    drawBody();
    drawHead();
    drawUpperArm(angle_upper);//timer에 따라 angle 변함
    drawLowerArm(angle_lower);//timer에 따라 angle 변함
    drawHand();
    drawFinger1();
    drawFinger2();
    //glFlush();
    glutSwapBuffers(); //애니메이션 사용을 위해서 Flush없애고 스왑버퍼 호출
}

void MyTimer(int value){
    angle_upper += dir_upper; //1도씩 움직이기
    angle_lower += dir_lower; //5도씩 움직이기
    
    if(angle_upper <= 0)
        dir_upper = 1;
    else if(angle_upper >= 60)
        dir_upper = 0;
    //std::cout << angle_upper << std::endl;
    if(angle_lower <= -70)
        dir_lower = 5;
    else if(angle_lower >= 100)
        dir_lower = -5;
        
    glutTimerFunc(20, MyTimer, 1);
    glutPostRedisplay();
}

void CameraAnimationTimer(int value){
    GLfloat Theta = 0.01;
    
    //모델의 y축 기준으로 카메라 회전시키기 회전공식 참고
    camPos_x = camPos_x * cos(Theta) + camPos_z * sin(Theta);
    camPos_z = camPos_x * -sin(Theta) + camPos_z * cos(Theta);
    
    
    glutTimerFunc(20, CameraAnimationTimer, 2);
    glutPostRedisplay();
}

int main(int argc, char ** argv) {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE);
    glutInitWindowSize(_WINDOW_WIDTH, _WINDOW_HEIGHT);
    glutCreateWindow("title");
    
    //콜백
    glutDisplayFunc(MyDisplay);
    glutReshapeFunc(MyReshape);
    
    glutTimerFunc(20, MyTimer, 1);
    glutTimerFunc(20, CameraAnimationTimer, 2);
    
    glutMainLoop();
}