2014-12-11 5 views
3

거의 정확한 중복 질문 : OpenGL font rendering using Freetype2.텍스트가 올바르게 렌더링되지 않음 - FreeType2를 사용하는 OpenGL

저는이 튜토리얼을 기반으로 FreeType2 (2.5.3)를 사용하여 OpenGL 프로그램에서 텍스트를 렌더링하려고합니다 : http://en.wikibooks.org/wiki/OpenGL_Programming/Modern_OpenGL_Tutorial_Text_Rendering_02. Bentebent와 동일한 구조체를 사용하여 위의 질문에 답했습니다. 나는 그가 사각형 녹색 문자열 "Hello"와 그 아래 "World" 렌더링, 예를 들어

(심지어 glActiveTexture()에 대한 올바른 GL_TEXTURE0 매개 변수를 사용하여) 대신 읽기 쉬운 문자까지 보여주는 가진 것과 동일한 문제가 있습니다

나에게이 있습니다 : 내 텍스처가 잘 생성되는 것을 볼 수 있습니다 gDEBugger를를 사용 Bentebent와 마찬가지로

Rendering 'Hello' and 'World'

. 나는 google/stackoverflow를 샅샅이 조사하고 glTexImage2D, 내 조각 쉐이더 등 color에 대한 다른 수식을 시도했지만 행운이 없습니다. 지금 당분간 붙어있어. 어떤 도움을 주셔서 감사합니다.

구조체 텍스처 아틀라스를 만들려면

//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 < 128; i++) 
     { 
      if (FT_Load_Char(face, i, FT_LOAD_RENDER)) 
      { 
       TRACE("Loading character %c failed\n", i); 
       continue; 
      } 

      if (roww + glyphSlot->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 < 128; i++) 
     { 
      if (FT_Load_Char(face, i, FT_LOAD_RENDER)) { 
       TRACE("Loading character %c failed\n", 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) { 
       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 기능 :

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 기능 :

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<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) 
      ); 
    } 

    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); 
} 
+0

이 예는 유망 해 보입니다. https://github.com/rougier/freetype-gl보다 일반적인 질문 : http://stackoverflow.com/questions/8847899/opengl-how-to-draw-text-using-only -opengl-methods –

+0

그게 무슨 소리 죠? 이 글꼴 렌더링은 괜찮아 보입니다! – Andrew

답변

4

귀하의 텍스처 형식은 R8은, 그래서 그것은 단지 R 채널이 포함되어 있습니다. 채널을 사용하는 쉐이더 이음새. 나는 3.0 < 당신의 OpenGL을 경우 GL_R8 & GL_RED-GL_ALPHA8 & GL_ALPHA을 변경하거나 texture2D(texture, uv).r-texture2D(texture, uv).a을 변경하는 게 좋을 것

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, ... 

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

대 : 는 이러한 코드 2 개 라인을 비교.

+0

오른쪽! 정말 고맙습니다! 내 멍청한 실수. 튜토리얼은 유효하지 않은'GL_ALPHA'를 사용했습니다. (OpenGL 3.3을 사용하고 있습니다.) 그래서'glTexImage2D'와'glTexSubImage2D'를'GL_RED'로 변경했을 때 셰이더를 잊어 버렸습니다. 나는 쉐이더를'texture2D (texture, uv) .r'로 바꿨고 텍스트는 올바르게 렌더됩니다. – Tur1ng

+0

@ Tur1ng "GL_ALPHA is invalid"로 무엇을 의미합니까? –

+1

@ UB-GL_ALPHA는 유효하지만 알파 채널을 포함하지 않는 텍스처에서 그러한 채널을 샘플링하면 0. – Anonymous

3

여기 OP '(

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

텍스트가없는 아주 멋지게이기는하지만, 렌더링 일부 문자 : TextFragmentShader.fragmentshader에서

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); 

: 구조체 FontCharacterAtlas에서

제안'이 익명에 따라, 내 작업 코드 옆면이 약간 자르고 a24 또는 a12 아틀라스를 사용하는 경우 글꼴이 지저분합니다.)하지만 그건 또 다른 이야기입니다.

+0

가 반환됩니다. 텍스처 필터가 GL_LINEAR이므로, (GL_LINEAR 필터는 가장 가까운 4 개의 텍셀을 샘플링하고 가중 평균을 사용한다). 이것은'GL_LINEAR' 필터링이 아닌'GL_NEAREST'를 사용할 때 나타나는 대부분의 문제를 해결할 것입니다. 당신이 따라 온 튜토리얼을 보면, 글리프를 단단히 묶으려고 시도하고 있는데 그것은'GL_LINEAR' 필터링에 적절하지 않습니다. –

+0

@ AndonM.Coleman 귀하의 의견을 보내 주셔서 감사합니다. 1 텍셀 테두리로 글리프를 패킹하는 방법은 무엇입니까? – Tur1ng

관련 문제