OpenGL 프로그래밍을 위한 준비과정은 다음 포스팅을 참고하세요.

[그래픽스&컴퓨터비전/Augmented Reality] - OpenGL( freeGLUT ) 을 Visual Studio 2015에 연동하기

[그래픽스&컴퓨터비전/Augmented Reality] - Ubuntu 16.04에서 OpenGL( freeGLUT ) 프로그래밍



OpenGL에서 윈도우의 사이즈를 다음처럼 지정해주어 생성합니다.

1
glutInitWindowSize(500500);   //윈도우의 width와 height

cs


그래픽스에선 보통 왼쪽 상단에 원점이 있는 2차원 좌표계를 사용합니다. 그래서 아래로 갈수록 Y값이 증가하게 됩니다.



OpenGL에서는 Normalized Device Coordinates(NDC)를 사용합니다.  Y값이 위로 올라갈수록 커지며  중앙에 원점 (0,0)이 위치합니다. 좌표로 실수값을 사용하며  X와 Y의 범위가 각각 [-1, 1]입니다.  3차원인 경우에는 Z축의 범위도 [-1, 1]이고 화면 안쪽으로 갈수록 감소합니다.


glViewport함수로 viewport를 지정하면 screen coordinates로 변환할 수 있습니다.



한변의 길이가 1인 빨간색 사각형의 중앙이 원점(0,0)에 오도록해서 그리는 예제입니다. 주의 할 점은 사각형을 구성하는 네 개의 vertex를 지정해줄 때 반드시 반시계 방향으로 차례대로 지정해줘야 합니다.

1
2
3
4
5
6
    glBegin(GL_QUADS); //4점이 하나의 사각형을 구성한다. 반시계 방향으로 4점의 vertex를 지정해줘야 한다.
    glVertex2f(-0.5f, -0.5f);    // x, y
    glVertex2f(0.5f, -0.5f);
    glVertex2f(0.5f, 0.5f);
    glVertex2f(-0.5f, 0.5f);
    glEnd();
cs






코드는 윈도우 기준으로 되어 있습니다. 리눅스의 경우에는 헤더파일을 다음처럼 지정하고 라이브러리 지정해 준 줄들을 삭제해주면 됩니다.

1
#include "GL/freeglut.h"
cs



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
//상대경로로 헤더파일을 지정합니다.
#include ".\include\GL\freeglut.h"
#include <iostream>
 
//사용할 라이브러리를 지정해줍니다.
#pragma comment(lib, "freeglut.lib")
#pragma comment(lib, "glew32.lib")
 
using namespace std;
 
 
void keyboard(unsigned char key, int x, int y)
{
    cout << "다음 키가 눌러졌습니다. \"" << key << "\" ASCII: " << (int)key << endl;
 
    //ESC 키가 눌러졌다면 프로그램 종료
    if (key == 27)
    {
        exit(0);
    }
}
 
 
void drawBitmapText(char *str, float x, float y, float z)
{
    glRasterPos3f(x, y, z); //문자열이 그려질 위치 지정
 
    while(*str)
    {
        //GLUT_BITMAP_TIMES_ROMAN_24 폰트를 사용하여 문자열을 그린다.
        glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, *str);
 
        str++;
    }
}
 
 
void display() {
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f); //glClear에서 컬러 버퍼 지운 후 윈도우를 채울 색을 지정, 검은색
    glClear(GL_COLOR_BUFFER_BIT);         //컬러 버퍼를 지운다.
    glLoadIdentity();
 
    
    //중앙이 원점에 오도록 한변의 길이가 1인 빨간색 정사각형을 그린다. 
    glColor3f(1.0f, 0.0f, 0.0f); //빨간색 지정
    glBegin(GL_QUADS); //4점이 하나의 사각형을 구성한다. 반시계 방향으로 4점의 vertex를 지정해줘야 한다.
    glVertex2f(-0.5f, -0.5f);    // x, y
    glVertex2f(0.5f, -0.5f);
    glVertex2f(0.5f, 0.5f);
    glVertex2f(-0.5f, 0.5f);
    glEnd();
 
    glColor3f(1.0f, 1.0f, 1.0f);//흰색 지정
    drawBitmapText("-0.5, -0.5"-0.5f, -0.5f, 0.0f);// 지정한 좌표에 문자열 출력
    drawBitmapText("0.5, -0.5"0.5f, -0.5f, 0.0f);
    drawBitmapText("0.5, 0.5"0.5f, 0.5f, 0.0f);
    drawBitmapText("-0.5, 0.5"-0.5f, 0.5f, 0.0f);
    
    //더블 버퍼링을 하고 있다면, 프론트 버퍼와 백 버퍼 2개가 사용된다.현재 화면에 보여지는 것은 프론트 버퍼에 있는 내용이다.
    //백 버퍼는 다음 장면을 위해 렌더링을 하고 있는 곳이다.백 버퍼의 렌더링이 완료되면 두 개의 버퍼를 교환(swap)한다.
    //화면에 업데이트된 프론트 버퍼에 있는 내용이 출력된다.
 
    //싱글 버퍼라면 버퍼에 있는 것을 화면에 출력한다.
    glutSwapBuffers();
}
 
 
int main(int argc, char** argv) 
{
    glutInit(&argc, argv);  //GLUT 초기화
 
    glutInitWindowSize(500500);   //윈도우의 width와 height
    glutInitWindowPosition(100100); //윈도우의 위치 (x,y)
    glutCreateWindow("OpenGL Example"); //윈도우 생성
 
    //디스플레이 콜백 함수 등록, display함수는 윈도우 처음 생성할 때와 화면 다시 그릴 필요 있을때 호출된다. 
    glutDisplayFunc(display); 
    //키보드 콜백 함수 등록, 키보드가 눌러지면 호출된다. 
    glutKeyboardFunc(keyboard);
 
    //GLUT event processing loop에 진입한다.
    //이 함수는 리턴되지 않기 때문에 다음줄에 있는 코드가 실행되지 않는다. 
    glutMainLoop();          
 
    return 0;
}
cs



윈도우의 크기를 조정하면 정사각형의 모양이 왜곡되는 것을 볼 수 있습니다. 


윈도우의 크기 조정시 호출되는 reshape 콜백 함수에서  변경된 윈도우 크기의 aspect ratio를 참고하여 orthographic projection를 적용시켜주면 해결됩니다.  


orthographic projection은 원근이 있지만 거리가 멀어져도 정면에서는 항상 동일한 크기로 보이게 해줍니다.  참고로 perspective  projection은 거리가 멀어질 수록 정면에서 봤을때 작게 보이게 만듭니다. 

이 둘의 차이는 https://wiki.blender.org/index.php/Doc:KO/2.4/Manual/3D_interaction/Navigating/3D_View 에서 가져온 아래 이미지를 보면 이해가 될듯합니다. 



윈도우 크기 조정시 왜곡되는 문제를 해결한 코드입니다. 굵은 글씨가 추가된 코드입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
//상대경로로 헤더파일을 지정합니다.
#include ".\include\GL\freeglut.h"
#include <iostream>
 
//사용할 라이브러리를 지정해줍니다.
#pragma comment(lib, "freeglut.lib")
#pragma comment(lib, "glew32.lib")
 
using namespace std;
 
 
void keyboard(unsigned char key, int x, int y)
{
    cout << "다음 키가 눌러졌습니다. \"" << key << "\" ASCII: " << (int)key << endl;
 
    //ESC 키가 눌러졌다면 프로그램 종료
    if (key == 27)
    {
        exit(0);
    }
}
 
 
void drawBitmapText(char *str, float x, float y, float z)
{
    glRasterPos3f(x, y, z); //문자열이 그려질 위치 지정
 
    while(*str)
    {
        //GLUT_BITMAP_TIMES_ROMAN_24 폰트를 사용하여 문자열을 그린다.
        glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, *str);
 
        str++;
    }
}
 
 
void display() 
{
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f); //glClear에서 컬러 버퍼 지운 후 윈도우를 채울 색을 지정, 검은색
    glClear(GL_COLOR_BUFFER_BIT);         //컬러 버퍼를 지운다.
    glLoadIdentity();
 
    
    //중앙이 원점에 오도록 한변의 길이가 1인 빨간색 정사각형을 그린다. 
    glColor3f(1.0f, 0.0f, 0.0f); //빨간색 지정
    glBegin(GL_QUADS); //4점이 하나의 사각형을 구성한다. 반시계 방향으로 4점의 vertex를 지정해줘야 한다.
    glVertex2f(-0.5f, -0.5f);    // x, y
    glVertex2f(0.5f, -0.5f);
    glVertex2f(0.5f, 0.5f);
    glVertex2f(-0.5f, 0.5f);
    glEnd();
 
    glColor3f(1.0f, 1.0f, 1.0f);//흰색 지정
    drawBitmapText("-0.5, -0.5"-0.5f, -0.5f, 0.0f);// 지정한 좌표에 문자열 출력
    drawBitmapText("0.5, -0.5"0.5f, -0.5f, 0.0f);
    drawBitmapText("0.5, 0.5"0.5f, 0.5f, 0.0f);
    drawBitmapText("-0.5, 0.5"-0.5f, 0.5f, 0.0f);
    
    //더블 버퍼링을 하고 있다면, 프론트 버퍼와 백 버퍼 2개가 사용된다.현재 화면에 보여지는 것은 프론트 버퍼에 있는 내용이다.
    //백 버퍼는 다음 장면을 위해 렌더링을 하고 있는 곳이다.백 버퍼의 렌더링이 완료되면 두 개의 버퍼를 교환(swap)한다.
    //화면에 업데이트된 프론트 버퍼에 있는 내용이 출력된다.
 
    //싱글 버퍼라면 버퍼에 있는 것을 화면에 출력한다.
    glutSwapBuffers();
}
 
 
void reshape(GLsizei width, GLsizei height) 
{  
    if (height == 0) height = 1;                // 0으로 나누는 것 방지
    GLfloat aspect = (GLfloat)width / (GLfloat)height;
 
    //변경된 윈도우크기로 viewport를 설정한다.
    glViewport(00, width, height);
 
    glMatrixMode(GL_PROJECTION);  //뒤에 오는 계산들은 Projection matrix에 영향을 주도록 설정
    glLoadIdentity();             //projection matrix 초기화
    if ( width >= height) {
        // aspect >= 1 이면, height를 [-1,1]로 설정하고 width는 [-1*aspect, 1*aspect]로 설정한다.
        // left, right, top, bottom
        gluOrtho2D(-1.0 * aspect, 1.0 * aspect, -1.01.0);
    }
    else {
        // aspect < 1이면, width를 [-1,1]로 설정하고 height를  [-1/aspect, 1/aspect]로 설정한다.
        gluOrtho2D(-1.01.0-1.0 / aspect, 1.0 / aspect);
    }
 
    //뒤에 오는 계산들은 Modelview Matrix에 영향을 주도록 설정한다. 
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity(); //Modelview matrix 초기화
}
 
 
int main(int argc, char** argv) 
{
    glutInit(&argc, argv);  //GLUT 초기화
 
    glutInitWindowSize(500500);   //윈도우의 width와 height
    glutInitWindowPosition(100100); //윈도우의 위치 (x,y)
    glutCreateWindow("OpenGL Example"); //윈도우 생성
 
    //디스플레이 콜백 함수 등록, display함수는 윈도우 처음 생성할 때와 화면 다시 그릴 필요 있을때 호출된다. 
    glutDisplayFunc(display); 
    //키보드 콜백 함수 등록, 키보드가 눌러지면 호출된다. 
    glutKeyboardFunc(keyboard);
    //reshape 콜백 함수 등록, reshape함수는 윈도우 처음 생성할 때와 윈도우 크기 변경시 호출된다.
    glutReshapeFunc(reshape);
 
    //GLUT event processing loop에 진입한다.
    //이 함수는 리턴되지 않기 때문에 다음줄에 있는 코드가 실행되지 않는다. 
    glutMainLoop();          
 
    return 0;
}
cs






포스트 작성시에는 문제 없었지만 이후 문제가 생길 수 있습니다.
댓글로 알려주시면 빠른 시일내에 답변을 드리겠습니다.

여러분의 응원으로 좋은 컨텐츠가 만들어집니다.
지금 본 내용이 도움이 되었다면 유튜브 구독 부탁드립니다. 감사합니다 : )

유튜브 구독하기

  1. what 2017.02.08 15:40

    위 소스도 NDK로 AndroidStudio에서 구현 가능한가요??

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2017.02.08 16:08 신고

      안드로이드 프로젝트에 디폴트로 ndk 설정이 opencv에 대해서만 되있고 opengl es의 네이티브 라이브러리가 없어서 얘기하신 현재 ndk 세팅으로는 힘들거 같습니다.

      구글에서 opengl es와 ndk를 같이 사용하는 방법을 찾아봐야 합니다..

    • what 2017.02.08 16:30

      http://webnautes.tistory.com/1009

      위 글 포스팅 해주셨던데

      위 내용으로는 안되나요??

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2017.02.08 16:35 신고

      그건 opengl es를 이용하여 자바 코드로 작성한거라 지금 포스팅에 있는 내용과 전혀 다릅니다.

      자바 코드로 opengl 응용프로그램을 짜던가..

      아니면 ndk를 이용하여 c코드를 부분적으로 사용하던가 해야할듯하네요..

  2. 2019.07.18 14:53

    비밀댓글입니다

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.07.18 15:08 신고

      괜찮습니다. 가능하면 참고했다고 링크를 남겨주셨으면 합니다.

    • 2019.07.19 11:36

      비밀댓글입니다

+ Recent posts