Text not rendering correctly - OpenGL using FreeType2

匿名 (未验证) 提交于 2019-12-03 01:18:02

问题:

Almost exact duplicate question: OpenGL font rendering using Freetype2.

I am trying to render text in my OpenGL program using FreeType2 (2.5.3), based on this tutorial: http://en.wikibooks.org/wiki/OpenGL_Programming/Modern_OpenGL_Tutorial_Text_Rendering_02, using the same structs as Bentebent did in his question (above).

I am having the same problem he was having with rectangles showing up instead of legible characters (even using the correct GL_TEXTURE0 parameter for glActiveTexture())

For example, rendering green strings "Hello" and "World" below it gives me this:



As with Bentebent, using gDebugger I can see that my textures are generated fine. I have scoured google/stackoverflow, tried different parameters for glTexImage2D, different formulas for color in my fragment shader, etc, but no luck. Been stuck for a while now. Any help is appreciated.

Structs to create texture atlas:

//DrawTestOpenGLWnd.h struct FontCharacter {     float advanceX;     float advanceY;      float bitmapWidth;     float bitmapHeight;      float bitmapLeft;     float bitmapTop;      float uvOffsetX;     float uvOffsetY; };  struct FontTextureAtlas {     GLuint texture;     GLint textureUniform;      int width;     int height;      FontCharacter characters[128];      FontTextureAtlas(FT_Face face, int h, GLint 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 bitmap.width + 1 >= MAX_WIDTH)             {                 width = std::max(width, roww);                 height += rowh;                 roww = 0;                 rowh = 0;             }              roww += glyphSlot->bitmap.width + 1;             rowh = std::max(rowh, glyphSlot->bitmap.rows);         }          width = std::max(width, roww);         height += rowh;          glGenTextures(1, &texture);          if (glGetError() != GL_NO_ERROR){             TRACE("glGenTextures failed\n");         }          glActiveTexture(GL_TEXTURE0);          if (glGetError() != GL_NO_ERROR){             TRACE("glActiveTexture failed\n");         }          glBindTexture(GL_TEXTURE_2D, texture);          if (glGetError() != GL_NO_ERROR){             TRACE("glBindTexture failed\n");         }          glUniform1i(tUniform, 0);         textureUniform = tUniform;          glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, 0);          if (glGetError() != GL_NO_ERROR){             TRACE("glTexImage2D failed\n");         }          glPixelStorei(GL_UNPACK_ALIGNMENT, 1);          if (glGetError() != GL_NO_ERROR){             TRACE("glPixelStorei failed\n");         }          glPixelStorei(GL_PACK_ALIGNMENT, 1);          if (glGetError() != GL_NO_ERROR){             TRACE("glPixelStorei failed\n");         }          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);          if (glGetError() != GL_NO_ERROR){             TRACE("glTexParameteri failed\n");         }          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);          if (glGetError() != GL_NO_ERROR){             TRACE("glTexParameteri failed\n");         }          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);          if (glGetError() != GL_NO_ERROR){             TRACE("glTexParameteri failed\n");         }          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);          if (glGetError() != GL_NO_ERROR){             TRACE("glTexParameteri failed\n");         }           int ox = 0;         int oy = 0;          rowh = 0;          for (int i = 32; i 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) {                 TRACE("BORKED AGAIN\n");             }              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::max(rowh, glyphSlot->bitmap.rows);             ox += glyphSlot->bitmap.width + 1;         }          TRACE("Generated a %d x %d (%d kb) texture atlas.\n", width, height, width * height / 1024);     }      ~FontTextureAtlas()     {         glDeleteTextures(1, &texture);     } }; 

InitFreeType function:

void DrawTestOpenGLWnd::InitFreeType(char * strFontFilePath) {      m_error = FT_Init_FreeType(&m_library);     if (m_error) {         TRACE("An error occurred during library initialization");     }      m_error = FT_New_Face(m_library, strFontFilePath, 0, &m_face);     if (m_error == FT_Err_Unknown_File_Format) {         TRACE("Font file could be opened and read, but it appears that its font format is unsupported");     }     else if (m_error) {         TRACE("Font file could not be opened or read. Or it's broken.");     }      m_program_text = LoadShaders("TextVertexShader.vertexshader", "TextFragmentShader.fragmentshader");     glUseProgram(m_program_text);      m_uniform_texture = glGetUniformLocation(m_program_text, "texture");     m_uniform_textColor = glGetUniformLocation(m_program_text, "textColor");      glGenVertexArrays(1, &vao_text);     glBindVertexArray(vao_text);      glGenBuffers(1, &vbo_text);     //glBindBuffer(GL_ARRAY_BUFFER, vbo_text);      a48 = new FontTextureAtlas(m_face, 48, m_uniform_texture);     a24 = new FontTextureAtlas(m_face, 24, m_uniform_texture);     a12 = new FontTextureAtlas(m_face, 12, m_uniform_texture); } 

RenderText function:

void DrawTestOpenGLWnd::RenderText(char * text, FontTextureAtlas * atlas, float x, float y, float sx, float sy) {     glUseProgram(m_program_text);     const unsigned char* p;      std::vector<: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)             );     }      glBindVertexArray(vao_text);     glEnable(GL_BLEND);     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);      glActiveTexture(GL_TEXTURE0);     glUniform1i(atlas->textureUniform, 0);     glBindTexture(GL_TEXTURE_2D, atlas->texture);      GLfloat textColor[4] = {0.0, 1.0, 0.0, 0.}; //green     glUniform4fv(m_uniform_textColor, 1, textColor);      glBindBuffer(GL_ARRAY_BUFFER, vbo_text);     glBufferData(GL_ARRAY_BUFFER, coords.size() * sizeof(glm::vec4), coords.data(), GL_DYNAMIC_DRAW);      //Position     glEnableVertexAttribArray(0);     glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(glm::vec4), (void*)0);      glDrawArrays(GL_TRIANGLES, 0, coords.size());      glDisableVertexAttribArray(0);      glBindVertexArray(0);     glUseProgram(0); } 

TextVertexShader.vertexshader:

#version 330 core  layout(location = 0) in vec4 pos_uv; out vec2 uv;  void main(void) {   gl_Position = vec4(pos_uv.xy, 0, 1);   uv = pos_uv.zw; } 

TextFragmentShader.fragmentshader:

#version 330 core  in vec2 uv; uniform sampler2D texture; uniform vec4 textColor;  out vec4 color;  void main(void) {   color = vec4(textColor.rgb, texture2D(texture, uv).a); } 

回答1:

Your texture format is R8, so it contains R channel only. Your shader seams to use A channel. Compare these 2 lines of code:

glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, width, height, 0, GL_RED,               GL_UNSIGNED_BYTE, 0);  ... glTexSubImage2D(GL_TEXTURE_2D, 0, ox, oy, glyphSlot->bitmap.width,                 glyphSlot->bitmap.rows, GL_RED, ... 

vs

color = vec4(textColor.rgb, texture2D(texture, uv).a); 

I'd suggest to change GL_R8 & GL_RED to GL_ALPHA8 & GL_ALPHA if your OpenGL texture2D(texture, uv).a to texture2D(texture, uv).r otherwise.



回答2:

OP here. This is my working code, as per Anonymous' suggestion:

In struct FontCharacterAtlas:

glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, width, height, 0, GL_RED,               GL_UNSIGNED_BYTE, 0);  ... glTexSubImage2D(GL_TEXTURE_2D, 0, ox, oy, glyphSlot->bitmap.width, glyphSlot->bitmap.rows,                  GL_RED, GL_UNSIGNED_BYTE, glyphSlot->bitmap.buffer); 

In TextFragmentShader.fragmentshader:

color = vec4(textColor.rgb, texture2D(texture, uv).r); 

Text renders, albeit not very nicely (some characters' sides are slightly cut off, and when using a24 or a12 atlas the font is quite messy) but that's another story.



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!