Как создать текстуру растрового шрифта в opengl? - PullRequest
0 голосов
/ 04 июня 2019

Итак, я пытался изучить OpenGL из learnopengl.com, и сейчас я занимаюсь темой рендеринга текста, и я подумал о том, чтобы объединить текстуры масштабируемых шрифтов в моей программе в одну большую текстуру, но по какой-то причине я получаю исключение до н.э. glCopyImageSubData(...).

Сначала я пытаюсь измерить, насколько большой должна быть текстура, а затем копирую текстуры, которые я уже создал, в одну большую текстуру, и я довольно долго играл с этой функцией, но не могу найти решение.

Вот оригинальный код с текстурой, используемой для каждого лица.

Я пытался создать fbo и прикрепить к нему текстуру, но после исследования я обнаружил, что эта функция мне гораздо понятнее, поэтому я решил использовать ее вместо этого.

Итак, я добавил xoffset в структуру символов:

struct Character {
    GLuint      textureID;
    glm::ivec2  size;
    glm::ivec2  bearing;
    GLuint      advance;
    GLuint      xoffset;
};

Я добавляю это смещение к каждой грани в первом цикле for:

    Character character = {
                texture,
                glm::ivec2(face->glyph->bitmap.width, face->glyph->bitmap.rows),
                glm::ivec2(face->glyph->bitmap_left, face->glyph->bitmap_top),
                face->glyph->advance.x,
                font_texture_width
            };
            font_texture_width += character.size.x;
            characters.insert(std::pair<GLchar, Character>(c, character));

А потом я пытаюсь вставить каждую текстуру лица в fontTexture:

glGenTextures(1, &fontTexture);
    glBindTexture(GL_TEXTURE_2D, fontTexture);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RED,
font_texture_width, 100, 0, GL_RED, GL_UNSIGNED_BYTE, NULL);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    std::cout << glGetError();
    for (GLubyte c = 0; c < 128; ++c)
        glCopyImageSubData( characters[c].textureID, GL_TEXTURE_2D, 0, 0, 0, 0,
                            fontTexture, GL_TEXTURE_2D, 0, characters[c].xoffset, 0, 0,
                            characters[c].size.x, characters[c].size.y, 0);

Вот модифицированная функция renderText:

void renderText(Shader &s, std::string text, GLfloat x, GLfloat y, GLfloat scale, glm::vec3 color)
{
    s.use();
    s.setVec3("textColor", color);
    glActiveTexture(GL_TEXTURE0);
    glBindVertexArray(VAO);
    std::string::const_iterator c;
    glBindTexture(GL_TEXTURE_2D, fontTexture);
    for (c = text.begin(); c != text.end(); ++c)
    {
        Character ch = characters[*c];
        GLfloat xpos = x + ch.bearing.x * scale;
        GLfloat ypos = y - (ch.size.y - ch.bearing.y) * scale;
        GLfloat w = ch.size.x * scale;
        GLfloat h = ch.size.y * scale;
        GLfloat vertices[6][4] = {
            { xpos + characters[*c].xoffset,        ypos + h,   0.0, 0.0 },
            { xpos + characters[*c].xoffset,        ypos,       0.0, 1.0 },
            { xpos + w + characters[*c].xoffset,    ypos,       1.0, 1.0 },
            { xpos + characters[*c].xoffset,        ypos + h,   0.0, 0.0 },
            { xpos + w + characters[*c].xoffset,    ypos,       1.0, 1.0 },
            { xpos + w + characters[*c].xoffset,    ypos + h,   1.0, 0.0 }
        };
        glBindBuffer(GL_ARRAY_BUFFER, VBO);
        glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
        glBindBuffer(GL_ARRAY_BUFFER, 0);
        glDrawArrays(GL_TRIANGLES, 0, 6);
        x += (ch.advance >> 6) * scale;
    }
    glBindVertexArray(0);
    glBindTexture(GL_TEXTURE_2D, 0);
}

Исключение выдается там, где я звоню glCopyImageSubData

Вот вся моя программа: https://pastebin.com/vAeeX3Xh

EDIT:

Теперь я понял, что было бы лучше использовать glTexSubImage2D, а не так, как это выглядит (вместо этого блока кода с glCopyImageSubData:

glGenTextures(1, &fontTexture);
glBindTexture(GL_TEXTURE_2D, fontTexture);
glTexImage2D(
    GL_TEXTURE_2D,
    0,
    GL_RED,
    face->glyph->bitmap.width * 250,
    face->glyph->bitmap.rows * 250,
    0,
    GL_RED,
    GL_UNSIGNED_BYTE,
    NULL
);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
for (GLubyte c = 0; c < 128; ++c)
{
    if (FT_Load_Char(face, c, FT_LOAD_RENDER))
    {
        std::cout << "ERROR::FREETYPE: Failed to load Glyph" << std::endl;
        continue;
    }
    glTexSubImage2D(GL_TEXTURE_2D, 0, characters[c].xoffset, 0, characters[c].size.x, characters[c].size.y, GL_RED, GL_UNSIGNED_BYTE, face->glyph->bitmap.buffer);
}

Теперь, когда я рендерил эту текстуру, она выглядит так: https://imgur.com/a/A0gDy6T

...