Rendu de police OpenGL en utilisant Freetype2
j'essaie de rendre une police freetype en utilisant OpenGL, en suivant L'exemple affiché à http://en.wikibooks.org/wiki/OpenGL_Programming/Modern_OpenGL_Tutorial_Text_Rendering_02 .
j'ai été capable de générer un atlas de texture à partir de la police, en créant des shaders et en créant des quads. Ce qui me bloque, semble-t-il, c'est de passer la texture au shader et/ou d'obtenir les UV corrects pour mes quads. Des difficultés depuis un bon moment maintenant et vraiment besoin l'aide.
ce qui suit est la structure que j'utilise pour créer mon Atlas de texture.
struct FontCharacter
{
float advanceX;
float advanceY;
float bitmapWidth;
float bitmapHeight;
float bitmapLeft;
float bitmapTop;
float uvOffsetX;
float uvOffsetY;
};
struct FontTextureAtlas
{
GLuint texture;
GLuint textureUniform;
int width;
int height;
FontCharacter characters[128];
FontTextureAtlas(FT_Face face, int h, GLuint tUniform)
{
FT_Set_Pixel_Sizes(face, 0, h);
FT_GlyphSlot glyphSlot = face->glyph;
int roww = 0;
int rowh = 0;
width = 0;
height = 0;
memset(characters, 0, sizeof(FontCharacter));
for (int i = 32; i < 128; i++)
{
if (FT_Load_Char(face, i, FT_LOAD_RENDER))
{
std::cout << "Loading character %c failedn", i;
continue;
}
if (roww + glyphSlot->bitmap.width + 1 >= MAX_WIDTH)
{
width = std::fmax(width, roww);
height += rowh;
roww = 0;
rowh = 0;
}
roww += glyphSlot->bitmap.width + 1;
rowh = std::fmax(rowh, glyphSlot->bitmap.rows);
}
width = std::fmax(width, roww);
height += rowh;
glGenTextures(1, &texture);
if (glGetError() != GL_NO_ERROR)
{
std::cout << "glGenTextures failedn";
}
glActiveTexture(GL_TEXTURE0 + texture);
if (glGetError() != GL_NO_ERROR)
{
std::cout << "glActiveTexture failedn";
}
glBindTexture(GL_TEXTURE_2D, texture);
if (glGetError() != GL_NO_ERROR)
{
std::cout << "glBindTexture failedn";
}
glUniform1i(tUniform, 0);
textureUniform = tUniform;
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, 0);
if (glGetError() != GL_NO_ERROR)
{
std::cout << "glTexImage2D failedn";
}
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
if (glGetError() != GL_NO_ERROR)
{
std::cout << "glPixelStorei failedn";
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
if (glGetError() != GL_NO_ERROR)
{
std::cout << "glTexParameteri failedn";
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
if (glGetError() != GL_NO_ERROR)
{
std::cout << "glTexParameteri failedn";
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
if (glGetError() != GL_NO_ERROR)
{
std::cout << "glTexParameteri failedn";
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
if (glGetError() != GL_NO_ERROR)
{
std::cout << "glTexParameteri failedn";
}
int ox = 0;
int oy = 0;
rowh = 0;
for (int i = 32; i < 128; i++)
{
if (FT_Load_Char(face, i, FT_LOAD_RENDER))
{
std::cout << "Loading character %c failedn", i;
continue;
}
if (ox + glyphSlot->bitmap.width + 1 >= MAX_WIDTH)
{
oy += rowh;
rowh = 0;
ox = 0;
}
glTexSubImage2D(GL_TEXTURE_2D, 0, ox, oy, glyphSlot->bitmap.width, glyphSlot->bitmap.rows, GL_RED, GL_UNSIGNED_BYTE, glyphSlot->bitmap.buffer);
if (glGetError() != GL_NO_ERROR)
{
std::cout << "BORKED AGAINn";
}
characters[i].advanceX = glyphSlot->advance.x >> 6;
characters[i].advanceY = glyphSlot->advance.y >> 6;
characters[i].bitmapWidth = glyphSlot->bitmap.width;
characters[i].bitmapHeight = glyphSlot->bitmap.rows;
characters[i].bitmapLeft = glyphSlot->bitmap_left;
characters[i].bitmapTop = glyphSlot->bitmap_top;
characters[i].uvOffsetX = ox / (float)width;
characters[i].uvOffsetY = oy / (float)height;
rowh = std::fmax(rowh, glyphSlot->bitmap.rows);
ox += glyphSlot->bitmap.width + 1;
}
std::cout << "Generated a " << width << "x " << height << " (" << width * height / 1024 << " kb) texture atlas.n";
}
~FontTextureAtlas()
{
glDeleteTextures(1, &texture);
}
variables locales et têtes de fonction utilisées dans le renderer
class RenderCore
{
FT_Library library;
FT_Face face;
FontTextureAtlas* a48;
FontTextureAtlas* a24;
FontTextureAtlas* a12;
GLuint vbo;
GLuint vao;
GLuint m_posUV;
GLuint m_colorIN;
GLuint m_texture;
int InitFT();
void RenderText(const char* text, FontTextureAtlas* atlas, float x, float y, float sx, float sy);
}
C'est ici que je charge mes polices.
int RenderCore::InitFT()
{
if (FT_Init_FreeType(&library))
{
std::cout << "Could not Initialize freetype library.n";
return 0;
}
/* Load a font */
if (FT_New_Face(library, "assets/Fonts/arialbd.ttf", 0, &face))
{
std::cout << "Could not open font assets/Fonts/DentonBeta2.ttfn";
return 0;
}
m_shaderManager->CreateProgram("Text");
m_shaderManager->LoadShader("shaders/Text.vertex", "TextVS", GL_VERTEX_SHADER);
m_shaderManager->LoadShader("shaders/Text.fragment", "TextFS", GL_FRAGMENT_SHADER);
m_shaderManager->AttachShader("TextVS", "Text");
m_shaderManager->AttachShader("TextFS", "Text");
m_shaderManager->LinkProgram("Text");
m_shaderManager->UseProgram("Text");
m_shaderManager->UseProgram("Text");
m_colorIN = m_shaderManager->GetUniformLocation("Text", "inputColor");
m_texture = m_shaderManager->GetUniformLocation("Text", "texture");
// Create the vertex buffer object
glGenBuffers(1, &vbo);
glGenVertexArrays(1, &vao);
/* Create texture atlasses for several font sizes */
a48 = new FontTextureAtlas(face, 48, m_texture);
a24 = new FontTextureAtlas(face, 24, m_texture);
a12 = new FontTextureAtlas(face, 12, m_texture);
}
fonction de rendu.
void RenderCore::RenderText(const char* text, FontTextureAtlas* atlas, float x, float y, float sx, float sy)
{
m_shaderManager->UseProgram("Text");
const unsigned char* p;
std::vector<glm::vec4> coords;
int c = 0;
for (p = (const unsigned char*)text; *p; p++)
{
float x2 = x + atlas->characters[*p].bitmapLeft * sx;
float y2 = -y - atlas->characters[*p].bitmapTop * sy;
float w = atlas->characters[*p].bitmapWidth * sx;
float h = atlas->characters[*p].bitmapHeight * sy;
x += atlas->characters[*p].advanceX * sx;
y += atlas->characters[*p].advanceY * sy;
if (!w || !h)
continue;
coords.push_back(
glm::vec4(
x2,
-y2,
atlas->characters[*p].uvOffsetX,
atlas->characters[*p].uvOffsetY)
);
coords.push_back(
glm::vec4(
x2 + w,
-y2,
atlas->characters[*p].uvOffsetX + atlas->characters[*p].bitmapWidth / atlas->width,
atlas->characters[*p].uvOffsetY)
);
coords.push_back(
glm::vec4(
x2,
-y2 - h,
atlas->characters[*p].uvOffsetX,
atlas->characters[*p].uvOffsetY + atlas->characters[*p].bitmapHeight / atlas->height)
);
coords.push_back(
glm::vec4(
x2 + w,
-y2,
atlas->characters[*p].uvOffsetX + atlas->characters[*p].bitmapWidth / atlas->width,
atlas->characters[*p].uvOffsetY)
);
coords.push_back(
glm::vec4(
x2,
-y2 - h,
atlas->characters[*p].uvOffsetX,
atlas->characters[*p].uvOffsetY + atlas->characters[*p].bitmapHeight / atlas->height)
);
coords.push_back(
glm::vec4(
x2 + w,
-y2 - h,
atlas->characters[*p].uvOffsetX + atlas->characters[*p].bitmapWidth / atlas->width,
atlas->characters[*p].uvOffsetY + atlas->characters[*p].bitmapHeight / atlas->height)
);
}
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glActiveTexture(GL_TEXTURE0 + atlas->texture);
glUniform1i(atlas->textureUniform, 0);
glBindTexture(GL_TEXTURE_2D, atlas->texture);
m_shaderManager->SetUniform(1, glm::vec4(0, 0, 1, 1), m_colorIN);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, coords.size() * sizeof(glm::vec4), coords.data(), GL_DYNAMIC_DRAW);
//Generate VAO
glBindVertexArray(vao);
//Position
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(glm::vec4), (void*)0);
glBindVertexArray(vao);
glDrawArrays(GL_TRIANGLE_STRIP, 0, coords.size());
glDisableVertexAttribArray(0);
m_shaderManager->ResetProgram();
}
Vertex shader
#version 440
in vec4 pos_uv;
out vec2 uv;
void main()
{
gl_Position = vec4(pos_uv.xy, 0, 1);
uv = pos_uv.zw;
}
Fragment shader
#version 440
in vec2 uv;
uniform sampler2D texture;
uniform vec4 inputColor;
out vec4 color;
void main()
{
color = vec4(inputColor.rgb, texture2D(texture, uv).a);
}
à l'Aide de gDebugger je peux voir l'atlas de texture ayant été généré correctement et le VBO semble très bien aussi. Le résultat est juste un tas de carrés à l'écran cependant et je n'ai vraiment aucune idée pourquoi. Je pense que ça pourrait être un problème de passer la texture au shader, tous les canaux sauf le canal alpha est vide et l'alpha est toujours 1.
1 réponses
a réussi à résoudre le problème, au lieu de glacitivetexture (gl_texture0 + texture); il aurait dû être seulement glacitivetexture (GL_TEXTURE0);
je suppose que l'extension glaciaire se lie à un index spécifique dans un programme et pas pour toutes les textures.