■ OpenGL: Modern OpenGL Tutorial Text Rendering 01[1]
1. 소개
OpenGL에서 text를 다루는 기능들이 별루 없다는 것을 알 수 있다. 그 이유는 세상에는 너무 많은 폰트들이 존재하기 때문에 사이즈와 폰트들의 수등을 전부 표현하기 어렵기 때문이라고 한다. (요약) 하지만 OpenGL에서 텍스트를 표현하기 위해 다음과 같은 방법들이 존재한다.
가. GL_LINES를 이용한 문자 그리기
나. GL_TRIANGLES를 이용한 문자 모양 채우기
다. 3D 문자 표현
라. 텍스쳐를 사용한 사각형에 문자 그리기
마. 텍스쳐가 적용된 사각형을 이용해 문장이나 절 그리기
바. glDrawPixels()로 framebuffer에 직접 텍스트그리기(OpenGL ES 2.0에서는 불가능하다고 함)
이 tutorial 에서는 사각형에 텍스쳐를 입혀 문장 또는 한글자를 표현함.
- 이 기술은 굉장히 유용함. 보고 계신 분들이 텍스쳐의 속성을 이해하게 되면 텍스트를 랜더링하는 가장 빠른 방법 중에 하나가 될 것임.
- 여기서 표현되는 텍스트는 보시는 분들의 워드프로세서 또는 브라우저(Browser)에 따라 품질이 다를 수 있음
2. 무료 라이브러리(FreeType Library)
OpenGL에서 텍스트를 표현하기 위해
step 1: 폰트 정보를 읽고
step 2: 해당 폰트를 형식에 변환해서 저장해야 함
위 방법을 지원하는 다양한 라이브러리가 있지만 잘 알려진 FreeType 라이브러리를 사용할 거야
이 라이브러리는 많은 폰트 포멧을 지원하고 TrueType과 OpenType를 포함한다고 함
TrueType: 컴퓨터에서 지원하는 타입
OpenType: 애플과 마이크로소프트 사에서 제공하는 타입
FreeType 라이브러리는 텍스트 레이아웃 엔진이 아니여라. 때문에 자동적으로 diacritics를 렌더링할 수 없으며, ligatures를 사용는거 또는 다른 복잡한 인쇄기능을 구현할 수가 없지롱. 만약 이 기능들이 필요하면 Pango라는 텍스트 레이아웃 라이브러리를 사용하면됨
사용방법
#include <ft2build.h>
#include FT_FREETYPE_H
FreeType 기능을 사용하기 위해 라이브러리 초기화 방법
FT_Library ft;
if(FT_Init_FreeType(&ft)) {
fprintf(stderr, "Could not init freetype library\n");
return 1;
}
3. 폰트와 Glyphs(글립스)
잠깐 아놔 글립스가 모야!!! 난 처음 본다. 급하게 검색해서 이해하자. TrueType 폰트를 구성하는 하나하나를 Glyph라고 한다. 요 아이는 수학적 함수를 통해 폰트의 외각선을 계산하기 때문에 비트맵 폰트에서 발생하는 계단현상을 극복하고 부드러운 폰트외각선을 그릴 수 있다는 것이 장점이넹..그렇군!!!
3.1 폰트 설정 및 정보 가져오기
폰트는 종류와 모양을 설정할 수 있는 그 방법은 다음과 같음
- 폰트체 설정: Times New Roman
- 폰트 모양 설정: regular, bold, italic, and other styles
FT_Face face;//폰트를 읽어서 저장하는 face 형 변수
if(FT_New_Face(ft, "FreeSans.ttf", 0, &face)) { // FreeSan 체 사용
fprintf(stderr, "Could not open font\n");
return 1;
}
FreeType library를 사용할 경우 사용자가 원하는 폰트에 대한 파일 경로를 다 써서 읽어야 함
이때 해당 폰트를 읽어서 저장하는 함수가 "face"임
- 폰트 사이즈 설정(폰트에서 사이즈 설정만 가능)
FT_Set_Pixel_Sizes(face, 0, 32); //폰트 사이즈를 32로 설정
3.2 Glyphs 값 가져오기
face에서 문자 Z에 대한 glyph 정보를 얻을라면 다음과 같이 쓰면 된다.
여기서 glyph 정보란 위 첫번째 그림과 같이 폰트를 그리기 위해 필요한 정보들이다.
if(FT_Load_Char(face, 'Z', FT_LOAD_RENDER)) {
fprintf(stderr, "Could not load character 'Z'\n");
return 1;
}
FT_LOAD_RENDER: FreeType는 8bit 그레이 스케일 이미지로 만들어짐, 이 정보는 face->glyph->bitmap로 얻을 수 있음
이렇게 얻어진 face에는 glyph slot에 대한 정보를 가지고 있으며 이 정보를 얻기 위해서는 FT_GlyphSlot 형의 변수를 선언하여 접근함
: 이런 줸장 또 glyph slot는 머야 ㅡㅡ^ 다음과 같다.
The glyph image is always stored in a special object called a glyph slot.
글립 이미지는 glyph slot라는 특별한 객체에 항상 저장된다고 한다. 즉 glyph slot는 폰트를 이루는 하나의 글자이미지 정보를 저장한 욘속이다.
FT_GlyphSlot g=face->glyph;
========================================================================================
g->bitmap.buffer//이전 설정된 폰트사이즈로 그려진 폰트의 8bit 그레이스케일 이미지에 대한 포인터
Pointer to the 8-bit greyscale image of the glyph, rendered at the previously selected font size.
g->bitmap.width
Width of the bitmap, in pixels.
g->bitmap.rows
Height of the bitmap, in pixels.
g->bitmap_left
Horizontal position relative to the cursor, in pixels.
g->bitmap_top
Vertical position relative to the baseline, in pixels.
g->advance.x //다음 문자와의 평행 거리?
How far to move the cursor horizontally for the next character, in 1/64 pixels.
g->advance.y //다음 문자와의 수직 거리? 거의 0이구만
How far to move the cursor vertically for the next character, in 1/64 pixels, almost always 0.
========================================================================================
왜 폰트만 가져다 찍으면 되지 위와 같이 이미지 정보를 가져와서 우짤라고?!! 머 이유가 있는데 모든 Glyph 들은 동일한 사이즈를 가지고 있지 않다고 하넹. FreeType는 이미지 폰트를 그리는데 충분한 문자 visible parts를 가지고 있다고 함. 머 폰트 마다 베이스 라인 잡고 포지션닝 하기 위해 위와 같은 정보가 필요하다고 한다. 난 폰트만 가져다가 찍고 싶은데 배울께 많다. 아마 지금 까지 읽으신 분들도 지루하실듯... 킁킁
4. Shaders
와 쉐이더~~~ 모닝 이아이는 또 모니~~
명사:
1. 물체의 색상, specularity(반사성), displacement(변위:이동 같은거)와 같은 장면에서 물체의 표면상태를 결정짓는 속성들. surface shader, volume shaders, displacement shaders, 그리고 light shaders 등을 포함하는 다양하고 많은 유형들을 가지고 있다.
2. shading을 결정짓는 속성들(blinn, phong, metal 등).
3. 3D 애니메이션에서 물체의 질감부분에 대한 여러 가지 특성과 기능을 관리하고 제어하는 사람.
[네이버 지식백과] 셰이더 [shader] (만화애니메이션사전, 2008.12.30, 한국만화영상진흥원)
그렇다고 한다.
텍스트 랜더링에서 기본적인 쉐이더를 사용할거랍니다. 기본적으로 텍스트는 2D 이기 때문에 이를 랜더하기 위해서는 다음과 같은 요소가 필요함
- attribute vec2 for vertices // 꼭지점에 관한 속성
- attribute vec2 for texture coordinates. //텍스쳐 좌표에 대한 속성
위 두요소를 4차원 배열에다가 합쳐서 넣는것이 가능하며, vertex shader는 두개로 분활할 수 있다고 함(아래 예제 보면 4차원에서 2차원 배열로 각자 나눠주는 것을 확인할 수 있음)
#version 120
attribute vec4 coord; //4차원 배열
varying vec2 texcoord; //2차원 배열
void main(void) {
gl_Position = vec4(coord.xy, 0, 1); // 포지션에 관한 정보는 4차원에서 x,y 값을 저장
texcoord = coord.zw; // 텍스쳐 좌료 값은 4차원에서 z,w 값을 저장
}
확실하지 않지만 alpha values를 가지는 텍스쳐를 사용하여 텍스트를 그리는 방법이 제일 좋다고 생각함
RGB 컬러는 모든 픽셀에 동일하게 적용됨. 알파값이 투명도 구만
- 알파값 1(opaque)이면 색상이 적용된 폰트가 보임, 0(transparent)이면 배경색이 보임, 당연히 1과 0 사이 알파값을 가지면 배경색과 폰트색이 혼합되서 나타남
그럼 fragment Shader 값은 다음과 같이 표현될 수 있음
#version 120
varying vec2 texcoord; // glyph 꼭지점 집합과 텍스쳐 좌표 저장버퍼
uniform sampler2D tex; // 샘플 2D tex
uniform vec4 color; // 컬러 4차원 배열
void main(void) {
gl_FragColor = vec4(1, 1, 1, texture2D(tex, texcoord).a) * color; // vec4( <-- 머야 이욘속!!!
//무튼 쉐이더의 색상 조각은 위와 같이 정의된다고 함
}
Fragment shader는 텍스트가 투명하게 보일수 있게 해 줌. 이 욘속은 다음의 OpenGL 함수와 짝짝꿍해야 함
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5. Rendering Lines of Text(텍스트 라인 그리기)
힘내 거의 다왔어 마지막이야
우선 해당 싸이트에서 언급한것들은 핵심에 대해서만 예기하고 있다 고로 사용된 예제 파일을 먼저 받아 보면서 이해 하고 필요한 헤더파일을 더 추가 시켜야 한다.
- http://sourceforge.net/projects/ogl-math/ (glm-0.9.5.3 다운)
- https://gitorious.org/wikibooks-opengl/modern-tutorials/source/0b75884b849e8144899b72097d48f7f034c6d4e4: (예제파일)
파일들은 언능 받는게 좋다. 왜냐면 링크가 언제 떨어질지 모르잖옹!! +_+
예제 파일 폴더
..............\wikibooks-opengl-modern-tutorials\text01_intro
여기가 사용된 파일인듯!!!
헤더 파일이 더 많이 사용되었는뎅
#include <GL/glew.h> // 요아이 셋팅
#include <GL/glut.h>
#include <glm/glm.hpp> // 요아이 셋팅
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <ft2build.h>
#include FT_FREETYPE_H
#include "../common/shader_utils.h" // 요아이 셋팅
요 아이들 먼저 포함시키자. 어떻게 하는지 알지? 느낌아니깐~~
C:\Program Files (x86)\Windows Kits\8.1\Include\um
나는 윈도우 8이니깐 위 폴더에 glm 폴더를 복사 해 넣는다.
glew 는 아래 블로거 선생님이 가르쳐 주셨다.
http://blog.naver.com/empirespony?Redirect=Log&logNo=30034286252
아마 보시면서 한숨 나올듯 폰트 하나 찍는데 너무 오래 걸린다. 줸장할 하루를 다 소비하는 듯한 느낌.
우선 소스 전체를 보자꾸낭(오픈 소스 올렸는데 저작권이 걸리라나 아시는 분 말씀해 주세요. ㅠㅠ)
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 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 | #include <stdio.h> #include <stdlib.h> #include <math.h> #include <GL/glew.h> #include <GL/glut.h> #include <glm/glm.hpp> #include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/type_ptr.hpp> #include <ft2build.h> #include FT_FREETYPE_H #include "../common/shader_utils.h" GLuint program; GLint attribute_coord; GLint uniform_tex; GLint uniform_color; struct point { GLfloat x; GLfloat y; GLfloat s; GLfloat t; }; GLuint vbo; FT_Library ft; FT_Face face; const char *fontfilename; int init_resources() { /* Initialize the FreeType2 library */ if (FT_Init_FreeType(&ft)) { fprintf(stderr, "Could not init freetype library\n"); return 0; } /* Load a font */ if (FT_New_Face(ft, fontfilename, 0, &face)) { fprintf(stderr, "Could not open font %s\n", fontfilename); return 0; } program = create_program("text.v.glsl", "text.f.glsl"); if(program == 0) return 0; attribute_coord = get_attrib(program, "coord"); uniform_tex = get_uniform(program, "tex"); uniform_color = get_uniform(program, "color"); if(attribute_coord == -1 || uniform_tex == -1 || uniform_color == -1) return 0; // Create the vertex buffer object glGenBuffers(1, &vbo); return 1; } /** * Render text using the currently loaded font and currently set font size. * Rendering starts at coordinates (x, y), z is always 0. * The pixel coordinates that the FreeType2 library uses are scaled by (sx, sy). */ void render_text(const char *text, float x, float y, float sx, float sy) { const char *p; FT_GlyphSlot g = face->glyph; /* Create a texture that will be used to hold one "glyph" */ GLuint tex; glActiveTexture(GL_TEXTURE0); glGenTextures(1, &tex); glBindTexture(GL_TEXTURE_2D, tex); glUniform1i(uniform_tex, 0); /* We require 1 byte alignment when uploading texture data */ glPixelStorei(GL_UNPACK_ALIGNMENT, 1); /* Clamping to edges is important to prevent artifacts when scaling */ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); /* Linear filtering usually looks best for text */ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); /* Set up the VBO for our vertex data */ glEnableVertexAttribArray(attribute_coord); glBindBuffer(GL_ARRAY_BUFFER, vbo); glVertexAttribPointer(attribute_coord, 4, GL_FLOAT, GL_FALSE, 0, 0); /* Loop through all characters */ for (p = text; *p; p++) { /* Try to load and render the character */ if (FT_Load_Char(face, *p, FT_LOAD_RENDER)) continue; /* Upload the "bitmap", which contains an 8-bit grayscale image, as an alpha texture */ glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, g->bitmap.width, g->bitmap.rows, 0, GL_ALPHA, GL_UNSIGNED_BYTE, g->bitmap.buffer); /* Calculate the vertex and texture coordinates */ float x2 = x + g->bitmap_left * sx; float y2 = -y - g->bitmap_top * sy; float w = g->bitmap.width * sx; float h = g->bitmap.rows * sy; point box[4] = { {x2, -y2, 0, 0}, {x2 + w, -y2, 1, 0}, {x2, -y2 - h, 0, 1}, {x2 + w, -y2 - h, 1, 1}, }; /* Draw the character on the screen */ glBufferData(GL_ARRAY_BUFFER, sizeof box, box, GL_DYNAMIC_DRAW); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); /* Advance the cursor to the start of the next character */ x += (g->advance.x >> 6) * sx; y += (g->advance.y >> 6) * sy; } glDisableVertexAttribArray(attribute_coord); glDeleteTextures(1, &tex); } void display() { float sx = 2.0 / glutGet(GLUT_WINDOW_WIDTH); float sy = 2.0 / glutGet(GLUT_WINDOW_HEIGHT); glUseProgram(program); /* White background */ glClearColor(1, 1, 1, 1); glClear(GL_COLOR_BUFFER_BIT); /* Enable blending, necessary for our alpha texture */ glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); GLfloat black[4] = { 0, 0, 0, 1 }; GLfloat red[4] = { 1, 0, 0, 1 }; GLfloat transparent_green[4] = { 0, 1, 0, 0.5 }; /* Set font size to 48 pixels, color to black */ FT_Set_Pixel_Sizes(face, 0, 48); glUniform4fv(uniform_color, 1, black); /* Effects of alignment */ render_text("The Quick Brown Fox Jumps Over The Lazy Dog", -1 + 8 * sx, 1 - 50 * sy, sx, sy); render_text("The Misaligned Fox Jumps Over The Lazy Dog", -1 + 8.5 * sx, 1 - 100.5 * sy, sx, sy); /* Scaling the texture versus changing the font size */ render_text("The Small Texture Scaled Fox Jumps Over The Lazy Dog", -1 + 8 * sx, 1 - 175 * sy, sx * 0.5, sy * 0.5); FT_Set_Pixel_Sizes(face, 0, 24); render_text("The Small Font Sized Fox Jumps Over The Lazy Dog", -1 + 8 * sx, 1 - 200 * sy, sx, sy); FT_Set_Pixel_Sizes(face, 0, 48); render_text("The Tiny Texture Scaled Fox Jumps Over The Lazy Dog", -1 + 8 * sx, 1 - 235 * sy, sx * 0.25, sy * 0.25); FT_Set_Pixel_Sizes(face, 0, 12); render_text("The Tiny Font Sized Fox Jumps Over The Lazy Dog", -1 + 8 * sx, 1 - 250 * sy, sx, sy); FT_Set_Pixel_Sizes(face, 0, 48); /* Colors and transparency */ render_text("The Solid Black Fox Jumps Over The Lazy Dog", -1 + 8 * sx, 1 - 430 * sy, sx, sy); glUniform4fv(uniform_color, 1, red); render_text("The Solid Red Fox Jumps Over The Lazy Dog", -1 + 8 * sx, 1 - 330 * sy, sx, sy); render_text("The Solid Red Fox Jumps Over The Lazy Dog", -1 + 28 * sx, 1 - 450 * sy, sx, sy); glUniform4fv(uniform_color, 1, transparent_green); render_text("The Transparent Green Fox Jumps Over The Lazy Dog", -1 + 8 * sx, 1 - 380 * sy, sx, sy); render_text("The Transparent Green Fox Jumps Over The Lazy Dog", -1 + 18 * sx, 1 - 440 * sy, sx, sy); glutSwapBuffers(); } void free_resources() { glDeleteProgram(program); } int main(int argc, char *argv[]) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGB); glutInitWindowSize(640, 480); glutCreateWindow("Basic Text"); if (argc > 1) fontfilename = argv[1]; else fontfilename = "FreeSans.ttf"; GLenum glew_status = glewInit(); if (GLEW_OK != glew_status) { fprintf(stderr, "Error: %s\n", glewGetErrorString(glew_status)); return 1; } if (!GLEW_VERSION_2_0) { fprintf(stderr, "No support for OpenGL 2.0 found\n"); return 1; } if (init_resources()) { glutDisplayFunc(display); glutMainLoop(); } free_resources(); return 0; } |
길다 폰트 하나 찍기 힘들구나 ㅎㅎ 그리고 OpenGL 2.0이라고 한다. 흠냐....난 그저 간단한 텍스쳐 매핑된 텍스트를 쓰고 싶었는데 간단한거면 좋았는데 ㅠㅠ
꼼꼼하게 뜯어 보면
GLuint tex; //
glActiveTexture(GL_TEXTURE0); //텍스쳐를 활성화 시킴
glGenTextures(1, &tex); // 텍스쳐 생성
glBindTexture(GL_TEXTURE_2D, tex); // 텍스쳐에 2D 텍스쳐를 묶어버림, 즉 2D 텍스쳐 할꼬얌
glUniform1i(uniform_tex, 0); // 단일 유니폼을 쓸꼬얌
텍스트를 랜더링 하기 전에 몇가지 초기화 해야 하는 일이 있다고 한다. 이것도 그 중에 하나로 단일 텍스쳐 오브렉트에 모든 glyphs를 렌더링 한다는 의미라고 한다.
문자가 픽셀 경계선에 정화하게 그려지지 않을경우 확실한 인공조형물(머 폰트겠지)을 보호하기 위해 우리는 edges에 텍스쳐를 묶어야 하며, 선형보간법을 허용해야 함
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); //엣지 묶음
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);//선형보간법
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
OpenGL에서 데이터와 텍스쳐를 업로딩 할때 사용하는 4byte alignment restrictions(정렬제한)은 기본값으로 설정되어 있는데 이것을 반드시 disable 시켜야 한다.
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); //GL_UNPACK_ALIGNMENT 하거라
다음으로 텍스쳐 좌표와 꼭지점 조합을 위해 꼭지점 버퍼 객체를 셋업함
GLuint vbo;
glGenBuffers(1, &vbo); //버퍼 만드려므나.
glEnableVertexAttribArray(attribute_coord); // 버텍스 속성 배열을 활성화 시키렴
glBindBuffer(GL_ARRAY_BUFFER, vbo); // 버텍스 배열을 묶어랏!
glVertexAttribPointer(attribute_coord, 4, GL_FLOAT, GL_FALSE, 0, 0);//좌표값을 가져오노라??
자 이제 텍스트를 출력하는 함수
void render_text(const char *text, float x, float y, float sx, float sy)
//문자열, (x,y) 좌표, (sx, sy) 스케일 매개변수
step 1: 먼저 확실한 수평 베이스라인과 포지션 커서를 가지고 시작
step 2: 처음 문자 읽기
step 3: 텍스쳐에 읽힌 문자 옵로드
step 4: 포지션에 정확하게 그리기
step 5: 그리고 다음 텍스쳐 텍스트를 위해 커서 이동
위를 반복하면서 문자열 출력
화면에 폰트를 그리기 위해 화면 픽셀에 일치하는 glyph 픽셀을 선택해야 함
void display() {
glClearColor(1, 1, 1, 1);//white 배경
glClear(GL_COLOR_BUFFER_BIT);
GLfloat black[4] = {0, 0, 0, 1}; //폰트 컬러 깜장색
glUniform4fv(uniform_color, 1, black);
float sx = 2.0 / glutGet(GLUT_WINDOW_WIDTH);
float sy = 2.0 / glutGet(GLUT_WINDOW_HEIGHT);
render_text("The Quick Brown Fox Jumps Over The Lazy Dog", //요게 정확한 좌표에 폰트 매핑
-1 + 8 * sx, 1 - 50 * sy, sx, sy);
render_text("The Misaligned Fox Jumps Over The Lazy Dog",//요건 불명확한 좌표에 폰트 매핑
-1 + 8.5 * sx, 1 - 100.5 * sy, sx, sy);
glutSwapBuffers();
}
결과를 보면 두번째 라인이 흐리게 보인다고 함
문자열 출력하는 부분을 자세히 보면 폰트 크기, 사이즈, 간격들이 어떻게 변화는지 확인할 수 있음
해보자!!!
흠... 이전 simple text 보다 훨씬 보기 좋다. 우선 예제 파일을 가지고 요리 저리 라이브러리 헤더파일 그리고 dll 파일을 설정해 주고 나서 컴파일 하면 화면이 나온다. 나 같은 경우는 검정화면이 떠서 왜 그러지... 생각해 보다 창의 window 사이즈와 갱신 관련 문제인듯한 예상에 창을 끌고 모니터 밖으로 끌었다가 다시 모니터 안으로 데려오니 역시나 출력이 되는 구나... 소스 잘만 응용하면 좋은 폰트로 사용할 수 있을듯 하다.
[1] http://en.wikibooks.org/wiki/OpenGL_Programming/Modern_OpenGL_Tutorial_Text_Rendering_01
'OpenGL' 카테고리의 다른 글
OpenGL: Very Simple Textured Text (1) | 2014.05.18 |
---|---|
Visual Studio: Setting FreeType Library (0) | 2014.05.16 |
OpenGL: Text in OpenGL (0) | 2014.05.15 |
OpenGL: Selection and Picking (0) | 2014.05.05 |
OpenGL: Normal Vector (0) | 2014.05.04 |
■ OpenGL: Text in OpenGL
OpenGL에서 기본적으로 텍스트를 표혆기 위한 3가지 방법이 존재함[1]
1. Raster Fonts.(래스터 폰트)
정의: 글자 크기에 해당하는 사각형 그리드의 픽셀에 1과 0으로 표현
사용함수: glBitmap or glDrawPixels
단점
가. 각 폰트를 묘사하는 데이터들이 CPU에서 그래픽 카드로 전송된다.(매 프레임의 모든 글자들에 대해)
- 이 것은 주요 대역폭에 도달할 수 있다. 즉, 활당된 대역폭을 모두 사용할 수 있다. 라는 의미?!
무한 스펙트럼 중에서 이 부분을 주요 스펙트럼(significant spectrum)이라 부르고 그 대역폭을 주요대역폭(significant bandwidth)이라 부른다.[2]
나. OpenGL 구현에서 래스터 폰트를 CPU와 프레임 버퍼 사이 이미지 데이터를 'swizzle' 해야한다. 즉, 래스터 폰트를 프레임 버퍼에서 CPU로 보내기 위해서 이미지데이터를 휘져야(가공해야)한다. 복잡해지겠징!
다. 많은 3D 그래픽 칩들은 모든 bitmap을 그리기 위해 설계되지 않았다.
- OpenGL 소프트웨어 드라이버는 3D 하드웨어가 폰트를 완벽하게 그릴때 까지 대기해야 함
라. Bitmaps과 Drawpixels는 스크린 edges에 평행으로 배치된다.
- 텍스트 회전은 불가능함
마. Bitmaps과 Drawpixels의 크기변환(Scaling)이 불가능함
장점:
가. 오직 소프트웨어 OpenGL 구현임(즉, 하드웨어 제어를 안함)
나. 다른 텍스트 표현 방법 보다 빠르다.
=============================================================
래스터 폰트(Raster Font 또는 Bitmap Font)
* 글자 크기에 해당하는 사각형 그리드의 픽셀에 1과 0으로 표현
* 메모리 내에서 비트맵에 대한 연산으로 처리하므로 출력 속도가 매우 빠르다
* 제작은 용이하나 확대하면 계단현상(Aliasing)
* 글자의 확대, 회전, 밀림 등 기하변환은 매우 어려우며 변환시 출력 품질 저하
http://ask.nate.com/qna/view.html?n=8363704
=============================================================
http://wordnetweb.princeton.edu/perl/webwn?s=raster+font&sub=Search+WordNet&o2=&o0=1&o8=1&o1=1&o7=&o5=&o9=&o6=&o3=&o4=&h=0
S: (n) screen font, raster font (the font that is displayed on a computer screen) "when the screen font resembles a printed font a document may look approximately the same on the screen as it will when printed"
=============================================================
위 그림과 같이 일반적으로 콘솔에서 나타는 폰트들이 래스터폰트이며, 사각형 그리드의 1과 0으로 폰트가 구성된다.
왜 레스터 폰트인가? 레스터란
[컴퓨터] 점방식 ((음극(선)관 등의 화면 위의 화상을 만드는 데 쓰이는 수평선의 집합))
즉, 점방식으로 이루어진 폰트이다.
2. Geometric Fonts.
지오메트릭 폰트란 기하학적 원형(Geometric Primitive) 선, 삼각형, whatever을 사용하여 만든 폰트를 말한다.
단점:
가. 때론 폰트를 만드는데 많은 수의 삼각형이 필요할 수 있다. 더 많은 기하학적인 원형을 쓰면 더 보기 좋은 폰트를 만들 수 있으나 그리기 위한 처리과정이 많아지기 떄문에 성능이 떨어진다.
나. 폰트를 디자인 하는 것이 어렵고 비용이 들어간다.
다. 폰트의 가장자리 색 넣기, 그림자 넣기 등은 위 두가지 문제점을 항상 동반한다.
장점:
가. 지오메트릭 변환가능: 회전, 크기변환, 위치변환 기타(twisted, morphed, extruded)
나. 폰트에 이쁜 장식을 할 수 있다. (fancy lighting models, environment mapping, texturing, etc.)
다. 3D 폰트를 만들게 되면 공간내 객체들간 폰트사이 충돌감지(collision detection) 가 가능함
라. 정밀하게 scale 가능. 폰트가 가변할때(커지거나 작아질때) 에일리어징 현상(aliasing artifacts)이 일어나지 않아 깨끗하게 보이며, 흐려지지 않는다.
3. Texture-Mapped Fonts.
텍스쳐-맵핑된 폰트란 말그대로 도형애 폰트를 입히는(텍스쳐) 것을 말한다.
모든 폰트들은 하나 또는 그 이상의 텍스쳐 멥에 매핑되고 각각의 폰트를 단일 사각형 안에 그려짐
단점:
가. 폰트를 표현하고자 하는 공간이 필요함.
- 만약 대소문자를 표현하기 위해서는 적당한 공간을 선언해야 이쁘게 보이는데 하드웨어에서 지원하는 텍스쳐 맵 크기는 제한되어 있음(eg 3Dfx Voodoo's can only render maps up to 256x256)
나. MIPmapping를 사용할 경우 크기변환한 폰트가 흐리게 보일 수 있음. 머 사용안해도 horribly aliasy하게 보임
장점:
가. 폰트에 모든 색상 적용이 가능함
나. 지오메트릭 변환 가능(회전, 크기변환, 위치 변환 등)
다. 3D 공간에서 그리게 되면 조명 빨도 받을 수 있음
라. 엄청 빠른 말그대로 그냥 도형에 폰트를 텍스쳐 하기 떄문에 다른 폰트들 보다 빠르다고 함.
That's probably an order of magnitude faster than either Raster or Geometric fonts. Since low-end 3D hardware is highly optimised to drawing simple textured polygons, speed is also enhanced because you are 'on the fast path' through the renderer. (CAVEAT: On software-only OpenGL's, textured fonts will be S-L-O-W.
결론: OpenGL에서 가장 좋은 Font를 선택하는 방법이 없음 때문에 입맛에 맞게 쓰는데 나는 Texture-Mapped Fonts 가 맘에 든다.
[1] http://sjbaker.org/steve/omniv/opengl_text.html
[2] http://book.naver.com/bookdb/text_view.nhn?bid=145783&dencrt=5NID6e%252BU%2539UharxJBk1jMf5urBnXk6DOMyT87AwM0%252BxY%253D&term=significant+bandwidth&query=significant+bandwidth
'OpenGL' 카테고리의 다른 글
Visual Studio: Setting FreeType Library (0) | 2014.05.16 |
---|---|
OpenGL: Modern OpenGL Tutorial Text Rendering 01 (0) | 2014.05.15 |
OpenGL: Selection and Picking (0) | 2014.05.05 |
OpenGL: Normal Vector (0) | 2014.05.04 |
OpenGL: Index of Vertex Array (0) | 2014.05.04 |
■ OpenGL: Selecting Object
사용자와 상호작용, 즉 인터랙티브한 효과가 필요함
- Selecting and Picking of Objects
OpenGL 의 강력한 기능 중 하나가 선택한 객체의 정보를 얻어 사용자에게 제공하고 그에 따른 반응을 할 수 있는 점
1. Selection(선택)
선택모드: 하나의 랜더링 모드, 프레임 버퍼에 픽셀이 복사되지 않음
- 기본 모델이 관측 공간내에 그려지며, 선택 버퍼 내에 히트 수가 만들어짐(정수 값을 가짐)
선택버퍼
- 물체나 모델 또는 그룹 구별하기 위해 선택버퍼를 설정해야 함
- 선택버퍼 설정 이후 해석하여 어떤 물체가 관층 공간 내에 있는지 검사 하면 됨
- 부호 없는 정수의 배열로, 각 히트 레코드는 적어도 네 개의 요소 자리를 차지 함
- 렌더링 과정에서 발생하는 히트 수를 기록하는데 사용됨
기본 모델의 이름
- 장면 내 모든 객체들의 이름을 짓는 것도 가능하지만 비효율적임
- 가장 많이 사용하는 방법은 그룹 식별(이름 목록)
- 이름 목록은 네임 스택에 저장됨
- 네임 스택 초기화 -> 이름 입력
- 선택과정에서 히트(hit)가 발생하면 현재 네임 스택에 있는 모든 이름들이 선택 버퍼 끝에 추가됨
step 1: 구분할 그룹 이름과 정수 정의
step 2: 네임 스택 초기화
step 3: 모델의 이름을 정하고 드로잉
객체를 선택하기 위해서는 랜더링 모드 변경을 해줘야 한다.
glRenderMode(GL_SELECTION); //선택모드로 변경
glRenderMode(GL_RENDER);//다시 드로잉 모드로 변경
선택버퍼
2. Picking
- 선택버퍼에서 어떤 물체가 클릭되었는지 확인
void gluPickMatrix(
GLdouble x, //Specify the center of a picking region in window coordinates.
GLdouble y,
GLdouble delX, //Specify the width and height, respectively, of the picking region in window coordinates.
GLdouble delY,
GLint * viewport //Specifies the current viewport
);
x, y 는 현재 사용자가 클릭한 공간이 되고, delX와 delY는 사용자가 클릭한 point에서 picking region이 된다. 그리고 viewport는 현재 화면 뷰포트의 포인터 변수가 된다. 여기서 사용되는 뷰 포트 정보를 가져 오기 위해 다음 함수를 사용한다.
The glGetIntegerv function returns the value or values of a selected parameter.
void WINAPI glGetIntegerv(
GLenum pname,//The parameter value to be returned. The following symbolic constants are accepted.
GLboolean *params//Returns the value or values of the specified parameter.
);
pname에 정해진 심볼을 사용한다. 이 심볼 중 GL_VIEWPORT를 사용할 경우 다음과 같다.
The params parameter returns four values: the x and y window coordinates of the viewport, followed by its width and height. See glViewport.
4개의 파라미터를 반환: x, y, width, height
즉 glGetIntegerv(GL_VIEWPORT, viewport)를 하게 되면 현재 뷰포트의 x, y, width, height 값을 viewport 변수에 리턴하게 된다.
http://msdn.microsoft.com/en-us/library/windows/desktop/ee872027(v=vs.85).aspx
즉 어떠한 객체를 picking하기 위해서는 먼저 뷰포트에 대한 정보를 가져오고 그 뷰포트 정보 중 선택된 좌료 값에 매칭되는 객체가 있는지 확인하는 과정을 가진다.
gluPickMatrix 함수를 사용하는 방법은 다음과 같다.
step 1: 현재 투영 행렬 상태 저장
step 2: glLoadIdentity 호출(단위 크기의 관측 공간 생성) - 변환된 회전이나 좌표의 행렬을 처음 상태로 돌려줌
step 3: gluPickMatrix 를 통해 관측 공간을 적절한 위치로 옴김
step 4: 원래 장면의 투영 방법을 적용
- 정확한 매핑이 안이루어 질 수 있다.
3. 정리 (객체를 선택하기 위한 단계)
step 1: 선택버퍼 선언
step 2: glSelectBuffer()함수로 선택 버퍼 할당
step 3: 현재 viewport 값 가져오기
step 4: 투영 모드 전환 및 배열 저장
step 5: 랜더링 모드 GL_SELECT 로 변환
step 6: 행렬 초기화 및 현재 마우스 클릭된 좌표의 객체 정보를 가져옴
step 7: 관점 설정 및 투영 시작
step 8: 다시 드로잉
step 9: 랜더링 모드 GL_RENDER 로 다시 돌아가면서 선택된 객체 index 값 받음
step 10: 투영 행렬 재저장
step 11: 정상 랜더링을 위한 모델 뷰로 돌아감
step 9에서 쓰이는 함수
glRenderMode(GL_RENDER)에서 어떻게 선택된 객체의 index 값을 받는가?
The call to glRenderMode(GL_RENDER) exits selection mode and returns the number of hit records stored in the selection buffer.
return:
GL_SELECT: The number of hit records transferred to the select buffer.
흠 그렇군 책에는 자세히 안써져 있다.
흣 작업 완료
ref
[1] Richard S. Wright. Jr. - Benjamin Lipchak 외 저(최연호 역), "OpenGL SuperBible", 정보문학사, pp. 651-680, 2005.
'OpenGL' 카테고리의 다른 글
OpenGL: Modern OpenGL Tutorial Text Rendering 01 (0) | 2014.05.15 |
---|---|
OpenGL: Text in OpenGL (0) | 2014.05.15 |
OpenGL: Normal Vector (0) | 2014.05.04 |
OpenGL: Index of Vertex Array (0) | 2014.05.04 |
OpenGL: Geometric and Vertex (0) | 2014.05.04 |