OpenGL-Schriftwiedergabe mit Freetype2

Ich versuche, eine Freetype-Schriftart mit OpenGL zu rendern, wie im Beispiel unter beschriebenhttp://en.wikibooks.org/wiki/OpenGL_Programming/Modern_OpenGL_Tutorial_Text_Rendering_02.

Ich konnte einen Texturatlas aus der Schriftart erstellen, Shader erstellen und Quads erstellen. Anscheinend stecke ich fest, indem ich die Textur an den Shader weitergebe und / oder die richtigen UVs für meine Quads erhalte. Kämpfe jetzt schon eine Weile und brauche wirklich die Hilfe.

Das Folgende ist die Struktur, mit der ich meinen Texturatlas erstelle.

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 failed\n", 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 failed\n";
            }

            glActiveTexture(GL_TEXTURE0 + texture);

            if (glGetError() != GL_NO_ERROR)
            {
                std::cout << "glActiveTexture failed\n";
            }

            glBindTexture(GL_TEXTURE_2D, texture);

            if (glGetError() != GL_NO_ERROR)
            {
                std::cout << "glBindTexture failed\n";
            }

            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 failed\n";
            }

            glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

            if (glGetError() != GL_NO_ERROR)
            {
                std::cout << "glPixelStorei failed\n";
            }

            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);

            if (glGetError() != GL_NO_ERROR)
            {
                std::cout << "glTexParameteri failed\n";
            }

            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

            if (glGetError() != GL_NO_ERROR)
            {
                std::cout << "glTexParameteri failed\n";
            }

            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

            if (glGetError() != GL_NO_ERROR)
            {
                std::cout << "glTexParameteri failed\n";
            }

            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

            if (glGetError() != GL_NO_ERROR)
            {
                std::cout << "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))
                {
                    std::cout << "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)
                {
                    std::cout << "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::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);
        }

Lokale Variablen und Funktionsköpfe, die im Renderer verwendet werden

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

Hier lade ich meine Schriften.

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.ttf\n";
        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);
}

Rendering-Funktion.

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

Mit gDebugger kann ich sehen, dass der Texturatlas ordnungsgemäß generiert wurde und der VBO ebenfalls in Ordnung zu sein scheint. Das Ergebnis ist jedoch nur ein paar Quadrate auf dem Bildschirm und ich habe wirklich keine Ahnung warum. Ich denke, es könnte ein Problem mit der Übergabe der Textur an den Shader sein, alle Kanäle mit Ausnahme des Alphakanals sind leer und das Alpha ist immer 1.

Antworten auf die Frage(1)

Ihre Antwort auf die Frage