OpenGL Glfw 分辨率独立渲染

时间:2021-03-24 08:36:06

标签: c++ opengl glfw

我刚刚开始研究使用 OpenGL 和 GLFW C++ 库创建 2D 游戏,目前我有游戏循环使用 freetype 在屏幕上渲染一些文本。但我注意到,如果我在视图的某个位置渲染文本,并且如果窗口被调整大小,它会移动,这是有道理的。

所以现在我试图创建一个特定大小/维度的屏幕外纹理,游戏中的所有内容都将被渲染到该屏幕外纹理,然后该屏幕外纹理将被渲染到窗口并根据需要向上/向下缩放。

现在我已经编写了我认为大部分代码的内容,但似乎无法使其正常工作。

glCheckFramebufferStatus 通过这意味着正确设置了帧缓冲区。

glGenFramebuffers(1, &m_frame_buffer);
glBindFramebuffer(GL_FRAMEBUFFER, m_frame_buffer);

glGenTextures(1, &m_texture);
glBindTexture(GL_TEXTURE_2D, m_texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, m_width, m_height, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

// The depth buffer
GLuint depthrenderbuffer;
glGenRenderbuffers(1, &depthrenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, depthrenderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, m_width, m_height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthrenderbuffer);

glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texture, 0);

// Set the list of draw buffers.
GLenum DrawBuffers[1] = { GL_COLOR_ATTACHMENT0 };
glDrawBuffers(1, DrawBuffers); // "1" is the size of DrawBuffers

if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
{
    std::cout << "FrameBuffer is busted" << std::endl;
}

然后在渲染循环期间,我首先切换我刚刚使用此代码创建的帧缓冲区。

glBindFramebuffer(GL_FRAMEBUFFER, m_virtual_render_target.getFrameBuffer());
glViewport(0, 0, m_virtual_render_target.getWidth(), m_virtual_render_target.getHeight());

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

然后我照常做我的渲染代码,这只是一些使用 FreeType 的文本渲染,如下所示。

在游戏循环开始初始化 Front 以呈现文本之前调用一次加载字体。

void TextManager::loadFont()
{
    // Configure VAO / VBO for textures
    glGenVertexArrays(1, &m_VAO);
    glGenBuffers(1, &m_VBO);
    glBindVertexArray(m_VAO);
    glBindBuffer(GL_ARRAY_BUFFER, m_VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 4, NULL, GL_DYNAMIC_DRAW);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);

    // If we can load the font face
    if (FT_New_Face(m_font_lib, "fonts/arial.ttf", 0, &m_font_face))
    {
        // Failed to load
        std::cout << "ERROR::FREETYPE: Failed to load font" << std::endl;
        return;
    }

    // set size to load glyphs as
    FT_Set_Pixel_Sizes(m_font_face, 0, 48);

    // disable byte-alignment restriction
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

    // load first 128 characters of ASCII set
    for (unsigned char c = 0; c < 128; c++)
    {
        // Load character glyph 
        if (FT_Load_Char(m_font_face, c, FT_LOAD_RENDER))
        {
            std::cout << "ERROR::FREETYTPE: Failed to load Glyph" << std::endl;
            continue;
        }

        // generate texture
        unsigned int texture;
        glGenTextures(1, &texture);
        glBindTexture(GL_TEXTURE_2D, texture);
        glTexImage2D(
            GL_TEXTURE_2D,
            0,
            GL_RED,
            m_font_face->glyph->bitmap.width,
            m_font_face->glyph->bitmap.rows,
            0,
            GL_RED,
            GL_UNSIGNED_BYTE,
            m_font_face->glyph->bitmap.buffer
        );

        // set texture options
        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);

        // now store character for later use
        TextCharacter character = TextCharacter(
            texture,
            glm::ivec2(m_font_face->glyph->bitmap.width, m_font_face->glyph->bitmap.rows),
            glm::ivec2(m_font_face->glyph->bitmap_left, m_font_face->glyph->bitmap_top),
            static_cast<unsigned int>(m_font_face->glyph->advance.x)
        );

        m_characters.insert(std::pair<char, TextCharacter>(c, character));
    }

    glBindTexture(GL_TEXTURE_2D, 0);

    // destroy FreeType once we're finished
    FT_Done_Face(m_font_face);
    FT_Done_FreeType(m_font_lib);
}

然后在每个循环中,这是实际渲染文本的代码

void TextManager::renderText(Shader* shader, std::string text, float x, float y, float scale, glm::vec3 color)
{
    // activate corresponding render state  
    shader->use();
    glUniform3f(glGetUniformLocation(shader->getProgramID() , "textColor"), color.x, color.y, color.z);
    glActiveTexture(GL_TEXTURE0);
    glBindVertexArray(m_VAO);

    // iterate through all characters
    std::string::const_iterator c;
    for (c = text.begin(); c != text.end(); c++)
    {
        TextCharacter ch = m_characters[*c];

        float xpos = x + ch.getBearing().x * scale;
        float ypos = y - (ch.getSize().y - ch.getBearing().y) * scale;

        float w = ch.getSize().x * scale;
        float h = ch.getSize().y * scale;

        // update VBO for each character
        float vertices[6][4] = {
            { xpos,     ypos + h,   0.0f, 0.0f },
            { xpos,     ypos,       0.0f, 1.0f },
            { xpos + w, ypos,       1.0f, 1.0f },

            { xpos,     ypos + h,   0.0f, 0.0f },
            { xpos + w, ypos,       1.0f, 1.0f },
            { xpos + w, ypos + h,   1.0f, 0.0f }
        };

        // render glyph texture over quad
        glBindTexture(GL_TEXTURE_2D, ch.getTextureID());
        // update content of VBO memory
        glBindBuffer(GL_ARRAY_BUFFER, m_VBO);
        glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices); // be sure to use glBufferSubData and not glBufferData

        glBindBuffer(GL_ARRAY_BUFFER, 0);
        // render quad
        glDrawArrays(GL_TRIANGLES, 0, 6);
        // now advance cursors for next glyph (note that advance is number of 1/64 pixels)
        x += (ch.getAdvance() >> 6) * scale; // bitshift by 6 to get value in pixels (2^6 = 64 (divide amount of 1/64th pixels by 64 to get amount of pixels))
    }
    glBindVertexArray(0);
    glBindTexture(GL_TEXTURE_2D, 0);
}

然后我使用此代码将所有内容渲染回 GLFW 窗口。

// Switch back to default frame buffer
glBindFramebuffer(GL_FRAMEBUFFER, 0);

// 4. RENDER FULLSCREEN QUAD
glViewport(0, 0, m_viewport_width, m_viewport_height);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

auto windowShader = m_shader_manager->getShader("WindowShader");
GLuint texID = windowShader->getUniformLocation("renderedTexture");
GLuint timeID = windowShader->getUniformLocation("time");

glUseProgram(windowShader->getProgramID());

//glActiveTexture(GL_TEXTURE0);
//glBindTexture(GL_TEXTURE_2D, m_virtual_render_target.getTexture());

glUniform1i(texID, 0);
//glUniform1f(timeID, glfwGetTime() * 10.0f);

glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, m_quad_model);

glVertexAttribPointer(
    0,                  // attribute 0. No particular reason for 0, but must match the layout in the shader.
    3,                  // size
    GL_FLOAT,           // type
    GL_FALSE,           // normalized?
    0,                  // stride
    (void*)0            // array buffer offset
);

// Draw the triangles !
glDrawArrays(GL_TRIANGLES, 0, 6); // 2*3 indices starting at 0 -> 2 triangles

glDisableVertexAttribArray(0);

这是四边形模型的顶点数据。

// The fullscreen quad's FBO
static const GLfloat quadVertexBufferData[] = {
    -1.0f, -1.0f, 0.0f,
     1.0f, -1.0f, 0.0f,
    -1.0f,  1.0f, 0.0f,
    -1.0f,  1.0f, 0.0f,
     1.0f, -1.0f, 0.0f,
     1.0f,  1.0f, 0.0f,
};

GLuint quadVertexBuffer;
glGenBuffers(1, &quadVertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, quadVertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertexBufferData), quadVertexBufferData, GL_STATIC_DRAW);

return quadVertexBuffer;

在所有这些之后,GLFW 只是空白/与之前使用的 clear 命令相同的颜色。为什么会发生这种情况?我知道这是一篇很长的文章,但 OpenGL 代码似乎总是很长。

旁注,如果我取出切换帧缓冲区的代码并只运行渲染代码,视图仍然是空白的,但是如果我删除生成帧缓冲区和纹理生成的代码,我的文本会再次渲染,所以也许问题就在这里。

感谢您的帮助

谢谢

0 个答案:

没有答案