철이의 컴노리
  • 안녕하세요!
  • KOTLIN
  • ANDROID
    • Architecture Components
      • 프로젝트에 추가하기
      • 데이터 바인딩 라이브러리
        • 시작하기
        • 레이아웃 및 바인딩 표현식
      • 라이프 사이클 처리
      • ViewModel
    • CameraX
      • CameraX 아키텍처
      • 구성
      • 미리보기
      • 이미지 분석
      • 이미지 캡처
      • 제조 업체 확장 기능
    • View
      • 커스텀뷰의 크기 정하기
    • JNI 튜토리얼
      • 1장. 저자 소개
      • 2장. Hello JNI
      • 3장. 메서드 등록
      • 4장. int 데이터형 값 주고 받기
      • 5장. boolean 데이터형 값 주고 받기
      • 6장. double 데이터형 값 주고 받기
      • 7장. float 데이터형 값 주고 받기
      • 8장. long 데이터형 값 주고 받기
      • 9장. short 데이터형 값 주고 받기
      • 10장. char 데이터형 값 주고 받기
      • 11장. byte 데이터형 값 주고 받기
      • 12장. JNI에서 문자열 다루기 1/3
      • 13장. JNI에서 문자열 다루기 2/3
      • 14장. JNI에서 문자열 다루기 3/3
      • 15장. 레퍼런스 이해하기
      • 16장. 배열 다루기 1/4
      • 17장. 배열 다루기 2/4
      • 18장. 배열 다루기 3/4
      • 19장. 배열 다루기 4/4
      • 20장. 중간 요약
      • 21장. 자바 클래스 찾기 1/2
      • 22장. 자바 클래스 찾기 2/2
      • 23장. 정적 메서드 찾기
      • 24장. 정적필드 찾기
      • 25장. 자바 클래스 인스턴스 생성하기
      • 26장. 자바 클래스 인스턴스 메서드 찾기
      • 27장. 자바 클래스의 인스턴스 필드 찾기
      • 28장. 네이티브 쓰레드 실행하기
  • Swift
    • What' New
      • Swift 5.0
        • Result 타입
        • Raw 문자열
        • 커스텀 문자열 보간
    • Codable
      • 커스텀 타입 인코딩 및 디코딩
  • iOS
  • OpenGL
    • OpenGL Tutorial
      • 1장. 저자 소개
      • 2장. OpenGL 윈도우 프레임웍 만들기 1편
      • 3장. OpenGL 윈도우 프레임웍 만들기 2편
      • 4장. 점그리기
      • 5장. 선 그리기
      • 6장. 다각형 그리기
      • 7장. 색 표현하기
      • 8장. 3차원 폴리곤 그리기
      • 9장. 투영변환
      • 10장. 이동, 회전, 크기 변환
      • 11장. 빛, 재질 표현하기
      • 12장. 텍스춰매핑
    • OpenGL ES Tutorial for iOS
      • 1장. 저자 소개
      • 2장. 튜토리얼 소개
      • 3장. OpenGL|ES 개발 환경 만들기
      • 4장. 뷰 배경색상 변경하기
      • 5장. 투영에 대해서 1/2
      • 6장. 투영에 대해서 2/2
      • 7장. 선분 및 삼각형 그리기
      • 8장. 색상칠하기
      • 9장. 텍스춰맵핑
      • 10장. 종횡비
      • 11장. 텍스춰 UV좌표
      • 12장. 텍스춰매핑 파라미터
      • 13장. 깊이버퍼
      • 14장. 원근투영
  • ENV
    • oh-my-zsh
      • 특정 git 폴더에서 zsh 이 느려질 때
  • Ubuntu
    • UEFI USB
    • nvidia driver
    • /dev/kvm on Android Studio
    • install oracle-jdk8
  • chromium
    • javap
Powered by GitBook
On this page

Was this helpful?

  1. OpenGL
  2. OpenGL Tutorial

9장. 투영변환

https://github.com/skyfe79/OpenGLTutorial

Previous8장. 3차원 폴리곤 그리기Next10장. 이동, 회전, 크기 변환

Last updated 6 years ago

Was this helpful?

  • GL_PROJECTION

  • glOrtho()

  • glFrustum()

  • gluPerspective()

OpenGL 의 렌더링 파이프 안에서 변환이 일어나는 것 중에 아핀 변환과 투영 변환이 있다. 아핀 변환(affine transformation)은 정점의 이동, 회전, 스케일 등의 변환를 말하며 이 변환의 특징은 변환 후에도 변환 전의 평행성과 비율을 보존해 준다는 것이다. 자세한 설명은 'OpenGL 을 통한 3차원 그래픽스 프로그래밍 기초편 - 임인성[도서출판그린]' 을 읽어보길 바란다. 투영 변환(projection transformation)은 n > m 이라 할 때 n 차원 공간의 점을 m 차원 공간의 점으로 바꾸어주는 변환을 말한다. 3차원의 한 점 p(x, y, z) 를 2차원의 한 점 p'(x, y) 로 변환하는 것을 예로 들 수 있다. OpenGL 의 렌더링 파이프 라인에서는 아핀 변환 후에 투영 변환이 일어난다. OpenGL 에서 아핀 변환에 쓰이는 함수는 glTranslatef(), glRotatef(), glScalef() 등이 있으며 투영 변환에 쓰이는 함수는 glOrtho() 함수와 glFrustum() 함수가 있고 glFrustum() 함수를 쓰기 쉽게 만들어 놓은 gluPerspective() 함수가 있다. OpenGL 에서의 투영 변환에는 2 가지의 변환이 있으며 하나는 직교 투영이고 다른 하나는 원근 투영이다. 이 두가지 외의 투영을 하려면 커스텀 투영 행렬을 만들어 현재 투영 행렬 스택에 glMultMatrix() 라는 함수를 이용해서 투영 행렬 스택의 최상단에 올려 놓으면 된다.

직교투영을 만드는 함수 glOrtho() 의 원형은 다음과 같다.

void glOrtho( GLdouble left, 
              GLdouble right, 
              GLdouble bottom, 
              GLdouble top, 
              GLdouble near, 
              GLdouble far )

이 함수에서 인자들의 의미는 아래 그림에 자세하게 설명되어 있다.

위의 그림에서 (left, bottom) - (right, top) 에 의해서 정의 되는 면은 클립핑된 영역이며 이 면에 2D 의 그림이 그려지게 된다. 즉 뒤의 육면체에서 우리가 생각하는 3D 의 폴리곤이 그려지고 아핀변환이 일어난 후에 클리핑된 면으로 투영 변환(여기서는 직교 변환, 3D 에서 2D 로 변환)이 일어나게 된다. 이 직교 투영의 변환 행렬은 아래와 같다.

원근투영을 만드는 함수 glFrustum() 의 원형은 다음과 같다.

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

이 함수에서 인자들의 의미는 아래 그림에 자세하게 설명되어 있다.

위의 그림에서 (left, bottom) - (right, top) 에 의해서 정의 되는 면은 클립핑된 영역이며 이 면에 2D 의 그림이 그려지게 된다. 즉 육면체(절두체)에서 우리가 생각하는 3D 의 폴리곤이 그려지고 아핀변환이 일어난 후에 클리핑된 면으로 투영 변환(여기서는 원근변환, 3D 에서 2D 로 변환)이 일어나게 된다. 이 원근 투영의 변환 행렬은 아래와 같다.

glFrustum() 함수를 좀 더 쉽게 쓰기 위해서 gluPerspective() 함수가 있는데 이 함수에 의해서 생성되는 원근 투영 행렬은 위의 행렬과는 다르다. 이는 직접 책을 찾아 보는 것이 좋을 것 같다. ;]

위의 두 행렬을 비교해 보면 아핀 변환을 할 수 있는 아핀 공간의 점은 p(x, y, z, w) 에서 w = 1 이다. 직교 투영 행렬은 w = 1 인 반면에 원근 투영 행렬은 w 가 1 이 아니다. 이 때문에 직교 투영은 아핀 변환의 특징인 평행성과 비율이 보존 되지만 원근 투영은 보존되지 않는다. 그렇다면 원근 투영에서 아핀 변환은 어떻게 할 수 있을까? 이에 대한 해답은 위에서 언급한 서적을 읽어보길 바란다.

아래의 그림은 아주 간단하게 만들어 본 직교 투영의 예제 프로그램 그림과 소스 코드이다. 원근감이 느껴지지 않는다.

void RenderWindow::OnSize(WPARAM wParam, LPARAM lParam)
{
    GLsizei width = LOWORD(lParam);
    GLsizei height = HIWORD(lParam);

    if (height == 0)
        height = 1;

    glViewport( 0, 0, width, height ); 

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    glOrtho(-3.0f, 3.0f, -3.0f, 3.0, 1.0f, 100.0f); //!

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

BOOL RenderWindow::InitGL(void)
{
    Window::InitGL();

    glEnable(GL_LIGHTING);

    GLfloat lightPos[4] = { 0.5f, 0.5f, 0.5f, 1.0f };
    glLightfv(GL_LIGHT0, GL_POSITION, lightPos);
    glEnable(GL_LIGHT0);

    return TRUE;
}

void RenderWindow::RenderGLScene(void)
{
    Window::RenderGLScene();

    glPushMatrix();
        glTranslatef(0.0f, 0.0f, -2.0f);
        glRotatef(33.0f, 1.0f, 0.0f, 0.0f);
        glRotatef(33.0f, 0.0f, 1.0f, 0.0f);
        glColor3f(0.5f, 0.5f, 0.5f);
        glutSolidTeapot(0.4f);
    glPopMatrix();

    glPushMatrix();
        glTranslatef(1.0f, 0.0f, -4.0f);
        glRotatef(33.0f, 1.0f, 0.0f, 0.0f);
        glRotatef(33.0f, 0.0f, 1.0f, 0.0f);
        glColor3f(0.3f, 0.3f, 0.3f);
        glutSolidTeapot(0.4f);
    glPopMatrix();

    glPushMatrix();
        glTranslatef(-1.0f, 0.0f, -6.0f);
        glRotatef(33.0f, 1.0f, 0.0f, 0.0f);
        glRotatef(33.0f, 0.0f, 1.0f, 0.0f);
        glColor3f(0.1f, 0.1f, 0.1f);
        glutSolidTeapot(0.4f);
    glPopMatrix();
}

아래의 그림은 아주 간단하게 만들어 본 원근 투영의 예제 프로그램 그림과 소스 코드이다. 원근감이 느껴진다.

void RenderWindow::OnSize(WPARAM wParam, LPARAM lParam)
{
    GLsizei width = LOWORD(lParam);
    GLsizei height = HIWORD(lParam);

    if (height == 0)
        height = 1;

    glViewport( 0, 0, width, height );

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    glFrustum(-1.0f, 1.0f, -1.0f, 1.0, 1.0f, 10.0f);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

BOOL RenderWindow::InitGL(void)
{
    Window::InitGL();

    glEnable(GL_LIGHTING);

    GLfloat lightPos[4] = { 0.5f, 0.5f, 0.5f, 1.0f };
    glLightfv(GL_LIGHT0, GL_POSITION, lightPos);
    glEnable(GL_LIGHT0);

    return TRUE;
}

void RenderWindow::RenderGLScene(void)
{
    Window::RenderGLScene();

    glPushMatrix();
        glTranslatef(0.0f, 0.0f, -2.0f);
        glRotatef(33.0f, 1.0f, 0.0f, 0.0f);
        glRotatef(33.0f, 0.0f, 1.0f, 0.0f);
        glColor3f(0.5f, 0.5f, 0.5f);
        glutSolidTeapot(0.4f);
    glPopMatrix();

    glPushMatrix();
        glTranslatef(1.0f, 0.0f, -4.0f);
        glRotatef(33.0f, 1.0f, 0.0f, 0.0f);
        glRotatef(33.0f, 0.0f, 1.0f, 0.0f);
        glColor3f(0.3f, 0.3f, 0.3f);
        glutSolidTeapot(0.4f);
    glPopMatrix();

    glPushMatrix();
        glTranslatef(-1.0f, 0.0f, -6.0f);
        glRotatef(33.0f, 1.0f, 0.0f, 0.0f);
        glRotatef(33.0f, 0.0f, 1.0f, 0.0f);
        glColor3f(0.1f, 0.1f, 0.1f);
        glutSolidTeapot(0.4f);
    glPopMatrix();
}