OpenGL로 외부 이미지파일을 읽어와서 출력할 때
glDrawPixels()함수를 쓰는 방법과 텍스쳐(texture)를 사용하는 방법이 있는데,
glDrawPixels()는 그릴 때마다 메인 메모리에서 픽셀값들을 읽어들이는 반면
텍스쳐는 생성할 때 그래픽 처리 장치의 메모리에 저장되므로 속도가 더 빠르다.
또한 텍스쳐를 그릴 때 확대/축소와 위치 지정을 자유롭게 할 수 있다.
먼저 테스트용으로 쓸 이미지 배열을 만든다.
여기서는 텍스쳐 포멧으로 RGBA_8888를 사용할 것인데,
Red, Green, Blue, Alpha(불투명도)에 해당하는 정보들을 각각 8비트(1바이트)씩 사용하는 방법이다.
1 2 3 4 5 6 7 8 9 10 11 12 13 | int w = 100; int h = 100; GLubyte map[100*100*4]; int i,j; for(i=0; i<h; i++) { for(j=0; j<w; j++) { map[w*i*4+j*4+0] = 0x99; //Red map[w*i*4+j*4+1] = 0x99; //Green map[w*i*4+j*4+2] = 0xCC; //Blue map[w*i*4+j*4+3] = 0xAA; //Alpha } } |
100x100 크기의 0x9999CCAA색 사각형을 나타내는 1차원 배열이 생성된다.
(그릴 때는 2차원으로 처리된다.)
알파 채널을 사용하기 위해 GL_BLEND를 활성화하고,
텍스쳐id로 텍스쳐를 생성한 뒤 glBindTexture()로 텍스쳐id와 텍스쳐라이징 대상을 연결한다.
그리고 glTexImage2D()로 텍스쳐로 쓸 GLubyte 배열을 쓴다.
glTexParameteri()로 확대/축소시 텍스쳐 필터를 설정하고
glTexEnvi()로 텍스쳐 환경 설정을 한다.(레퍼런스 참고)
glEnable(GL_BLEND); glTexImage2D( |
텍스쳐의 너비와 높이가 각각 2의 거듭제곱 꼴일 때 높은 성능을 얻을 수 있다.
(메모리에 2의 거듭제곱 단위로 할당되기 때문에..)
OpenGL ES에서는 아예 2의 거듭제곱꼴만 하용하고 있다.
예시) 64x128, 128x128, 256x64 등
이제 텍스쳐를 그리는 부분이다.
여기서는 평면상에 텍스쳐를 그릴 것인데, 먼저 OpenGL의 좌표계에 대해 알아야 한다.
별도의 설정을 하지 않을 시, 화면의 중앙이 원점이 되며 우측 상단으로 갈 수록 x와 y 값이 각각 증가한다.
우측 상단 꼭지점의 좌표는 (1, 1)이다.
텍스쳐 이미지 자체의 좌표는, 이미지의 좌측하단이 원점이며,
이미지의 우측상단이 (1, 1)이다.
glOrtho()함수를 쓰면 좌표계(클리핑 범위)를 재설정할 수 있다. 형식은 아래와 같다.
glOrtho(왼쪽, 오른쪽, 아래, 위, z축 근거리방향, z축 원거리방향)
2D만 고려할 때, glOrtho(0, 너비, 높이, 0 정도로 지정하면
MFC, JS 등에서처럼 좌측상단을 원점으로 쓸 수 있다.
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
glTexCoord2f()로 그릴 텍스쳐 영역을 지정할 때
텍스쳐가 뒤집혀 있는 상태이므로 아래와 같은 순서로 그린 것이다.
아래는 png 이미지를 로드하여 화면에 두 번 표시해본 화면이다.
이미지를 로드하기 위해 SDL2를 사용했는데, SDL2 대신 glut과 pnglib라이브러리를 써도 png 이미지파일을 읽어올 수 있다. (pnglib라이브러리 없이도 BMP파일은 로드 가능.)
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 | #pragma comment (lib,"SDL2") #pragma comment (lib,"SDL2main") #pragma comment (lib,"SDL2_image") #pragma comment (lib,"opengl32.lib") #include <cstdio> #include <SDL.h> #include <SDL_opengl.h> #include <SDL_image.h> using namespace std; SDL_Renderer *renderer; int main(int argc, char **argv){ int winWidth = 800; int winHeight = 600; SDL_Window *win = NULL; SDL_Renderer *renderer = NULL; SDL_Surface *image; SDL_RWops *rwop; rwop = SDL_RWFromFile("../res/img.png", "rb"); image = IMG_LoadPNG_RW(rwop); GLubyte *map = (GLubyte*)image->pixels; int w, h; w = image->w; h = image->h; if (SDL_Init(SDL_INIT_VIDEO) < 0) return 1; win = SDL_CreateWindow("gl", 100, 100, winWidth, winHeight, SDL_WINDOW_OPENGL); renderer = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED); SDL_GLContext context; context = SDL_GL_CreateContext(win); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); glEnable(GL_TEXTURE_2D); GLuint texId; glGenTextures(1, &texId); glBindTexture(GL_TEXTURE_2D, texId); glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, map ); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); while (1) { SDL_Event e; if (SDL_PollEvent(&e)) { if (e.type == SDL_QUIT) break; else if (e.type == SDL_KEYUP && e.key.keysym.sym == SDLK_ESCAPE) break; } glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glOrtho(0, winWidth, winHeight, 0, -1, 1); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glBindTexture(GL_TEXTURE_2D, texId); glBegin(GL_QUADS); glTexCoord2f(0.0, 0.0); glVertex2f(0, 0); glTexCoord2f(1.0, 0.0); glVertex2f(w, 0); glTexCoord2f(1.0, 1.0); glVertex2f(w, h); glTexCoord2f(0.0, 1.0); glVertex2f(0, h); glEnd(); glBegin(GL_QUADS); glTexCoord2f(0.0, 0.0); glVertex2f(0+30, 0+30); glTexCoord2f(1.0, 0.0); glVertex2f(w+30, 0+30); glTexCoord2f(1.0, 1.0); glVertex2f(w+30, h+30); glTexCoord2f(0.0, 1.0); glVertex2f(0+30, h+30); glEnd(); SDL_GL_SwapWindow(win); SDL_Delay(21); } SDL_GL_DeleteContext(context); SDL_DestroyRenderer(renderer); SDL_DestroyWindow(win); return 0; } | cs |