OpenGL 프로그래밍을 위한 준비과정은 다음 포스팅을 참고하세요.
[그래픽스&컴퓨터비전/Augmented Reality] - OpenGL( freeGLUT ) 을 Visual Studio 2015에 연동하기
[그래픽스&컴퓨터비전/Augmented Reality] - Ubuntu 16.04에서 OpenGL( freeGLUT ) 프로그래밍
OpenGL에서 윈도우의 사이즈를 다음처럼 지정해주어 생성합니다.
1 | glutInitWindowSize(500, 500); //윈도우의 width와 height |
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(500, 500); //윈도우의 width와 height glutInitWindowPosition(100, 100); //윈도우의 위치 (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(0, 0, 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.0, 1.0); } else { // aspect < 1이면, width를 [-1,1]로 설정하고 height를 [-1/aspect, 1/aspect]로 설정한다. gluOrtho2D(-1.0, 1.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(500, 500); //윈도우의 width와 height glutInitWindowPosition(100, 100); //윈도우의 위치 (x,y) glutCreateWindow("OpenGL Example"); //윈도우 생성 //디스플레이 콜백 함수 등록, display함수는 윈도우 처음 생성할 때와 화면 다시 그릴 필요 있을때 호출된다. glutDisplayFunc(display); //키보드 콜백 함수 등록, 키보드가 눌러지면 호출된다. glutKeyboardFunc(keyboard); //reshape 콜백 함수 등록, reshape함수는 윈도우 처음 생성할 때와 윈도우 크기 변경시 호출된다. glutReshapeFunc(reshape); //GLUT event processing loop에 진입한다. //이 함수는 리턴되지 않기 때문에 다음줄에 있는 코드가 실행되지 않는다. glutMainLoop(); return 0; } | cs |
'OpenGL' 카테고리의 다른 글
OpenGL 강좌 - 키보드로 3D 큐브(Cube) 움직이기 (0) | 2016.12.29 |
---|---|
OpenGL 강좌 - 삼각형이 회전하는 애니메이션 구현 (0) | 2016.12.20 |
Intel HD 4600에서 벌칸(Vulkan) API 사용해보기 (4) | 2016.11.15 |
Ubuntu 16.04에서 OpenGL( freeGLUT ) 프로그래밍 (2) | 2016.11.10 |
OpenGL( freeGLUT ) 을 Visual Studio 2015에 연동하기 (2) | 2016.09.09 |
시간날때마다 틈틈이 이것저것 해보며 블로그에 글을 남깁니다.
블로그의 문서는 종종 최신 버전으로 업데이트됩니다.
여유 시간이 날때 진행하는 거라 언제 진행될지는 알 수 없습니다.
영화,책, 생각등을 올리는 블로그도 운영하고 있습니다.
https://freewriting2024.tistory.com
제가 쓴 책도 한번 검토해보세요 ^^
그렇게 천천히 걸으면서도 그렇게 빨리 앞으로 나갈 수 있다는 건.
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!