为什么文本呈现为四边形?

时间:2018-05-26 18:17:48

标签: c++ opengl fonts freetype

我使用freetype和freetype-gl来渲染文本。 不幸的是我的文字呈现为四边形。

我就是这样做的:

enum
{
    //Max num of objects
    MAX_SPRITES = 60000,
    //Max num of indices
    //One sprite got 6 indices
    MAX_INDICES = MAX_SPRITES * 6,

    //Once sprite got 4 vertices
    SPRITE_SIZE = sizeof(Vertex) * 4,

    //Max num of GL_TEXTUREX => X -> int <0; 32>
    MAX_TEXTURES = 32
};

enum BUFFER_SIZE
{
    VERTEX = SPRITE_SIZE * MAX_SPRITES,
    INDEX = MAX_INDICES * sizeof(GLuint),
};

enum SHADER_OUT
{
    POSITION = 0,
    COLOR = 1,
    UV = 2,
    TEXTURE = 3,
};

class Renderer2D
{
public:
    Renderer2D() = default;
    ~Renderer2D();

    void Create();

    void RenderClear();
    void DrawString(const std::string& text, const Vector2& position, const Color& color);
    void Render();

private:
    Uint vao = 0,
         vbo = 0,
         ebo = 0,
         indexCount = 0,
         drawCalls = 0;

    ftgl::texture_atlas_t* textureAtlas = nullptr;
    ftgl::texture_font_t* font = nullptr;

    std::vector<MiUint> textureSlots;

    Vertex* mappedVertex = nullptr;

    void End();
    Uint* SetIndices();
    float FindTexture();
};

Renderer2D::~Renderer2D()
{
    glDeleteBuffers(1, &vbo);
    glDeleteBuffers(1, &ebo);
    glDeleteVertexArrays(1, &vao);

    ftgl::texture_atlas_delete(textureAtlas);
    ftgl::texture_font_delete(font);

    textureSlots.clear();
}

void Renderer2D::Create()
{
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);

    glGenBuffers(1, &vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, BUFFER_SIZE::VERTEX, nullptr, GL_DYNAMIC_DRAW);

    glEnableVertexAttribArray(SHADER_OUT::POSITION);
    glEnableVertexAttribArray(SHADER_OUT::COLOR);
    glEnableVertexAttribArray(SHADER_OUT::UV);
    glEnableVertexAttribArray(SHADER_OUT::TEXTURE);

    glVertexAttribPointer(SHADER_OUT::POSITION, 2, GL_FLOAT,         GL_FALSE, sizeof(Vertex), (const void*)offsetof(Vertex, position));
    glVertexAttribPointer(SHADER_OUT::COLOR,    4, GL_UNSIGNED_BYTE, GL_TRUE,  sizeof(Vertex), (const void*)offsetof(Vertex, color));
    glVertexAttribPointer(SHADER_OUT::UV,       2, GL_FLOAT,         GL_FALSE, sizeof(Vertex), (const void*)offsetof(Vertex, uv));
    glVertexAttribPointer(SHADER_OUT::TEXTURE,  1, GL_FLOAT,         GL_FALSE, sizeof(Vertex), (const void*)offsetof(Vertex, texID));

    glGenBuffers(1, &ebo);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, BUFFER_SIZE::INDEX, nullptr, GL_STATIC_DRAW);
    glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, NULL, BUFFER_SIZE::INDEX, SetIndices());

    glBindVertexArray(0);

    textureAtlas = ftgl::texture_atlas_new(512, 512, 1);
    font = ftgl::texture_font_new_from_file(textureAtlas, 50, "Media/arial.ttf");
}

void Renderer2D::RenderClear()
{
    textureSlots.clear();
    mappedVertex = nullptr;
    mappedVertex = (Vertex*)glMapNamedBufferRange(vbo, NULL, BUFFER_SIZE::VERTEX, GL_MAP_WRITE_BIT);
}

void Renderer2D::DrawString(const std::string& text, const Vector2& position, const Color& color)
{
    using namespace ftgl;

    float ts = FindTexture(),
          x = position.x;

    for (MiUint i = 0; i < text.length(); i++) {
        char c = text[i];

        texture_glyph_t* glyph = texture_font_get_glyph(font, c);

        if (glyph != nullptr) {
            if (i > 0) {
                float kerning = texture_glyph_get_kerning(glyph, text[i - 1]);
                x += kerning;
            }

            float x0 = x + glyph->offset_x,
                  x1 = x0 + glyph->width,
                  y0 = position.y + glyph->offset_y,
                  y1 = y0 - glyph->height,

                  u0 = glyph->s0,
                  u1 = glyph->s1,
                  v0 = glyph->t0,
                  v1 = glyph->t1;

            mappedVertex->position = Vector3(x0, y0, 0.0f);
            mappedVertex->uv = Vector2(u0, v0);
            mappedVertex->texID = ts;
            mappedVertex->color = color;
            mappedVertex++;

            mappedVertex->position = Vector3(x0, y1, 0.0f);
            mappedVertex->uv = Vector2(u0, v1);
            mappedVertex->texID = ts;
            mappedVertex->color = color;
            mappedVertex++;

            mappedVertex->position = Vector3(x1, y1, 0.0f);
            mappedVertex->uv = Vector2(u1, v1);
            mappedVertex->texID = ts;
            mappedVertex->color = color;
            mappedVertex++;

            mappedVertex->position = Vector3(x1, y0, 0.0f);
            mappedVertex->uv = Vector2(u1, v0);
            mappedVertex->texID = ts;
            mappedVertex->color = color;
            mappedVertex++;

            indexCount += 6;

            x += glyph->advance_x;
        }
    }
}

void Renderer2D::Render()
{
    End();
    drawCalls = 0;
    for (int i = 0; i < (int)textureSlots.size(); ++i) {
        glActiveTexture(GL_TEXTURE0 + i);
        glBindTexture(GL_TEXTURE_2D, textureSlots[i]);
    }

    glBindVertexArray(vao);
    glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, nullptr);
    glBindVertexArray(0);

    ++drawCalls;

    indexCount = 0;
    textureSlots.clear();

    mappedVertex = nullptr;
    glDisable(GL_BLEND);
}

void Renderer2D::End()
{
    glUnmapNamedBuffer(vbo);

    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}

MiUint* Renderer2D::SetIndices()
{
    MiUint* indices = new MiUint[BUFFER_SIZE::INDEX],
            offset = 0;
    for (int i = 0; i < BUFFER_SIZE::INDEX; i += 6) {
        indices[i]     = offset;
        indices[i + 1] = offset + 1;
        indices[i + 2] = offset + 2;
        indices[i + 3] = offset + 2;
        indices[i + 4] = offset + 3;
        indices[i + 5] = offset;

        offset += 4;
    }

    return indices;
}

float Renderer2D::FindTexture()
{
    float result = 0.0f;
    bool found = false;
    for (MiUint i = 0; i < (MiUint)textureSlots.size(); i++) {
        if (textureSlots[i] == textureAtlas->id) {
            result = (float)(i + 1);
            found = true;
            break;
        }
    }

    if (!found) {
        if (textureSlots.size() >= MAX_TEXTURES)
        {
            Render();
            RenderClear();
        }
        textureSlots.push_back(textureAtlas->id);
        result = (float)(textureSlots.size());
    }
    return result;
}

我的主要是在主循环renderer.Create,d clear rendererrawString("STRING", Vector2(0.0f, 0.0f), Color(255, 0, 0, 255))中设置一个二维摄像机(正交矩阵等),renderer render。< / p>

结果如:enter image description here

如何解决?我经历了drawString方法,看起来好像完美无缺。是什么导致它像这样呈现?

@ Rabbid76

只需

顶点:

#version 460 core

layout (location = 0) in vec2 a_position;
layout (location = 1) in vec4 a_color;
layout (location = 2) in vec2 a_uv;
layout (location = 3) in float a_texID;

out vec2 v_fragmentUV;
out vec4 v_fragmentColor;
out vec2 v_fragmenPosition;
out float v_texID;

uniform mat4 u_camera;

void main()
{
    gl_Position = u_camera * vec4(a_position, 0.0, 1.0);

    v_fragmenPosition = a_position;
    v_fragmentColor = a_color;
    v_texID = a_texID;
    v_fragmentUV = vec2(a_uv.x, 1 - a_uv.y);
}

像素:

#version 460 core

out vec4 outColor;

in vec2 v_fragmentUV;
in vec4 v_fragmentColor;
in vec2 v_fragmenPosition;
in float v_texID;

layout (location = 0) uniform sampler2D u_textureSampler[32];

void main()
{
    int texID = int(v_texID - 0.5);
    outColor = texture(u_textureSampler[texID], v_fragmentUV);
}

我将tetxure采样器设置为主体均匀。当我像玩家一样渲染纹理时,渲染效果非常好。只有文字问题。

Wher do you use glUniform* to set the texture unit index to the texture sampler uniform? 也许我应该只展示我的主要课程

App2D::App2D()
{
    window.Init(4, 6);
    window.Create("w", 1280, 720, WINDOW_RESIZABLE);

    camera.Projection(0.0f, 1280.0f, 0.0f, 720.0f);

    SetupShaders();
    renderer2D.Create();

    glClearColor(0.5, 0.5, 0.5, 1.0);

    /*short textureIDS[] = {
        texture.LoadFromFile("Media/MenuImage.png"),
        texture.LoadFromFile("Media/image1.png"),
        texture.LoadFromFile("Media/image2.png"),
    };

    for (int y = 0; y < 720; y += 4.) {
        for (int x = 0; x < 1280; x += 4.) {
            sprite.push_back(new Sprite2D(Rect(x, y, 4.0f), Rect(0.0f, 0.0f, 1.0f, 1.0f), rand() % 3 + 1));
        }
    }

    std::cout << sprite.size() << std::endl;*/
}

void App2D::MainLoop()
{
    int frames = 0;
    float time = 0.0f;

    while (!quit) {
        timer.Reset();
        while (SDL_PollEvent(&event)) {
            if (event.type == SDL_QUIT) {
                ExitGame();
            }

            UpdateInput();
        }

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        SetupCameraShader();

        camera.Update();

        Update(1.0f);
        renderer2D.RenderClear();

        renderer2D.DrawString("STRING", Vector2(0.0f, 0.0f), Color(255, 0, 0, 255));

        renderer2D.Render();

        window.SwapBuffers();

        frames++;
        if (timer.Elapsed() - time > 1.0f) {
            time++;

            Log("FPS: " + std::to_string(frames) + "\n");
            frames = 0;
        }
    }
}

void App2D::SetupShaders()
{
    shader.Free();
    GLuint shaders[2] = {
        shader.CreateShader("vertex.shader", GL_VERTEX_SHADER),
        shader.CreateShader("fragment.shader", GL_FRAGMENT_SHADER)
    };  shader.CreateAndUseProgram(shaders, 2);

    GLint textures[] = {
        0, 1, 2, 3, 4, 5, 6, 7, 8, 9
    };
    glUniform1iv(0, 10, textures);
}

void App2D::SetupCameraShader()
{
    GLint u_camera = shader.GetUniformLocation("u_camera");
    Mat4 cameraMatrix = Mat4(1.0f);
    cameraMatrix = camera.getCameraMatrix();
    //cameraMatrix = textCamera.getCameraMatrix();
    glUniformMatrix4fv(u_camera, 1, GL_FALSE, &(cameraMatrix[0][0]));
}

0 个答案:

没有答案