c++ - 添加额外的渲染调用时 GLFW 在关闭时挂起

标签 c++ c opengl glfw

因此,在过去的一段时间里,我一直在尝试学习如何对 openGL 进行编程,尽管很多时候它都令人费解,但我认为我开始对它的工作原理有了深入的了解。

我一直在使用 GLFW 进行窗口处理和基本输入,并使用 GLEW 访问扩展方法。

我也一直在关注 www.learnopengl.com 上的教程这非常有用。不过,最近,我一直在花一些时间尝试创建一些用于在屏幕上绘图的基本抽象。当我抽象出教程提供的一些代码时,一切都很顺利(我仍然在“入门”的坐标系部分)。

在这样做之后,我决定模拟一个简单的 UI 叠加层会很好,我只有一个函数可以在 2-D 屏幕上绘制一个矩形而不是 3-D 并且只是漂浮在屏幕上的其他所有内容之上.最终我得到了一些可以使用不同着色器的 UI 和 3-D 对象。它成功地在屏幕上的所有其他内容之上绘制了一个彩色矩形,但不幸的是,每当我尝试通过将 glfwSetWindowShouldClose 调用设置为 true 来关闭窗口时,窗口都会无限期地挂起。

每当我删除绘制简单二维矩形的调用时,这个挂起就会消失,窗口会按预期立即关闭。有谁知道为什么会出现这种情况?


main.cpp

// GLEW
#define GLEW_STATIC
#include <GL/glew.h>

// GLFW
#include <GLFW/glfw3.h>

// GL includes
#include "shader.h"

// GLM Mathemtics
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

// Other Libs
#include <SOIL.h>
#include "glfw_x360_button_mappings.h"
#include "cube.h"
#include "texture.h"

// Function prototypes
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode);
void handleControllerInput(GLFWwindow* window);

// GLOBALS!!!
const unsigned int MONITOR_WIDTH = 1920;
const unsigned int MONITOR_HEIGHT = 1080;
const unsigned int SCREEN_WIDTH = 800;
const unsigned int SCREEN_HEIGHT = 600;
float camera_z = -3.0f;
float camera_x = 0.0f;

// The MAIN function, from here we start our application and run our Game loop
int main()
{
    // Init GLFW
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);

    GLFWwindow* window = glfwCreateWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "LearnOpenGL", nullptr, nullptr); // Windowed
    // TODO: Make window position adapt to any sized window.
    glfwSetWindowPos(window, (MONITOR_WIDTH / 2) - (SCREEN_WIDTH / 2), (MONITOR_HEIGHT / 2) - (SCREEN_HEIGHT / 2));
    glfwMakeContextCurrent(window);

    // Set the required callback functions
    glfwSetKeyCallback(window, key_callback);

    // Initialize GLEW to setup the OpenGL Function pointers
    glewExperimental = GL_TRUE;
    glewInit();

    // Define the viewport dimensions
    glViewport(0, 0, 800, 600);

    // Setup OpenGL options
    glEnable(GL_DEPTH_TEST);

    // Setup and compile our shaders
    GLuint vert_id = buildShader("shader.vert", GL_VERTEX_SHADER);
    GLuint frag_id = buildShader("shader.frag", GL_FRAGMENT_SHADER);
    GLuint shader_program_id = buildProgram(vert_id, frag_id);

    glDeleteShader(vert_id);
    glDeleteShader(frag_id);

    vert_id = buildShader("shader_ui.vert", GL_VERTEX_SHADER);
    frag_id = buildShader("shader_ui.frag", GL_FRAGMENT_SHADER);
    GLuint ui_shader_program_id = buildProgram(vert_id, frag_id);

    glDeleteShader(vert_id);
    glDeleteShader(frag_id);

    // World space positions of our cubes
    glm::vec3 cubePositions[] = {
        glm::vec3(0.0f, 0.0f, 0.0f),
        glm::vec3(2.0f, 5.0f, -15.0f),
        glm::vec3(-1.5f, -2.2f, -2.5f), 
        glm::vec3(-3.8f, -2.0f, -12.3f), 
        glm::vec3(2.4f, -0.4f, -3.5f), 
        glm::vec3(-1.7f, 3.0f, -7.5f), 
        glm::vec3(1.3f, -2.0f, -2.5f), 
        glm::vec3(1.5f, 2.0f, -2.5f),
        glm::vec3(1.5f, 0.2f, -1.5f),
        glm::vec3(-1.3f, 1.0f, -1.5f) 
    };

    // Load and create a texture
    GLuint texture1 = create_texture("container.jpg");
    GLuint texture2 = create_texture("awesomeface.png");

    glm::mat4 view_matrix;
    glm::mat4 view_matrix_origin;
    glm::mat4 projection_matrix;

    view_matrix_origin = glm::translate(view_matrix, glm::vec3(0.0f, 0.0f, 0.0f));
    projection_matrix = glm::perspective(45.0f, (float) 512 / (float) 512, 0.1f, 1000.0f);

    GLint view_matrix_location = glGetUniformLocation(shader_program_id, "view");
    GLint projection_matrix_location = glGetUniformLocation(shader_program_id, "projection");

    glUseProgram(shader_program_id);
    glUniformMatrix4fv(projection_matrix_location, 1, GL_FALSE, glm::value_ptr(projection_matrix));

    Cube test_cube;
    init_cube(&test_cube, cube_vertices, sizeof(cube_vertices));

    // Game loop
    while(!glfwWindowShouldClose(window))
    {
        // Check and call events
        glfwPollEvents();
        handleControllerInput(window);

        // Clear the colorbuffer
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        glUseProgram(shader_program_id);

        // Bind Textures using texture units
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, texture1);
        glUniform1i(glGetUniformLocation(shader_program_id, "ourTexture1"), 0);
        glActiveTexture(GL_TEXTURE1);
        glBindTexture(GL_TEXTURE_2D, texture2);
        glUniform1i(glGetUniformLocation(shader_program_id, "ourTexture2"), 1);

        glUniform1f(glGetUniformLocation(shader_program_id, "time"), glfwGetTime());

        view_matrix = glm::translate(view_matrix_origin, glm::vec3(camera_x, 0.0f, camera_z));
        glUniformMatrix4fv(view_matrix_location, 1, GL_FALSE, glm::value_ptr(view_matrix));

        /* THIS IS THE OFFENDING DRAW CALL
         * IF REMOVED THE WINDOW STOPS HANGING ON CLOSE */
        draw_rect(ui_shader_program_id, glm::vec2(0.0f, 0.0f));

        for (GLuint i = 0; i < 10; i++)
        {
            GLfloat angle = glfwGetTime() * 25.0f;
            draw_cube(&test_cube, shader_program_id, cubePositions[i], angle);
        }

        // Swap the buffers
        glfwSwapBuffers(window);
    }

    glfwTerminate();
    return 0;
}

// Is called whenever a key is pressed/released via GLFW
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode)
{
    std::cout << key << std::endl;
    if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
    {
        glfwSetWindowShouldClose(window, GL_TRUE);
    }
}

void handleControllerInput(GLFWwindow* window)
{
    if (glfwJoystickPresent(GLFW_JOYSTICK_1))
    {
        int size;
        const unsigned char* results = glfwGetJoystickButtons(GLFW_JOYSTICK_1, &size);

        if (get_current_button_pressed(results, size) == X360_DPAD_DOWN)
        {
            camera_z += 0.001f;
        }
        else if (get_current_button_pressed(results, size) == X360_DPAD_UP)
        {
            camera_z -= 0.001f;
        }

        if (get_current_button_pressed(results, size) == X360_DPAD_LEFT)
        {
            camera_x -= 0.001f;
        }
        else if (get_current_button_pressed(results, size) == X360_DPAD_RIGHT)
        {
            camera_x += 0.001f;
        }

        if (get_current_button_pressed(results, size) == X360_B_BUTTON)
        {
            camera_z = -3.0f;
            camera_x = 0.0f;
        }

        if (get_current_button_pressed(results, size) == X360_BACK_BUTTON)
        {
            glfwSetWindowShouldClose(window, true);
        }
    }
}

矩形.h

#ifndef RECT_H
#define RECT_H

#include <GL/glew.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

const GLfloat rect_vertices[] = {
     0.75f,  0.5f, 1.0f, 0.7f, 0.0f,
     0.75f, -0.5f, 1.0f, 0.7f, 0.0f,
    -0.75f,  0.5f, 1.0f, 0.7f, 0.0f,

    -0.75f,  0.5f, 1.0f, 0.7f, 0.0f,
    -0.75f, -0.5f, 1.0f, 0.7f, 0.0f,
     0.75f, -0.5f, 1.0f, 0.7f, 0.0f,
};

void draw_rect(GLuint shader_program_id, glm::vec2 position);

#endif

矩形.cpp

#include "rect.h"

void draw_rect(GLuint shader_program_id, glm::vec2 position)
{
    glUseProgram(shader_program_id);
    GLuint vao, vbo;
    glGenVertexArrays(1, &vao);
    glGenBuffers(1, &vbo);

    glBindVertexArray(vao);

    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(rect_vertices), rect_vertices, GL_STATIC_DRAW);

    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*) 0);
    glEnableVertexAttribArray(0);

    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(2 * sizeof(GLfloat)));
    glEnableVertexAttribArray(1);

    //glm::mat4 model;
    //glm::mat4 view;
    //glm::mat4 projection;

    //model = glm::translate(model, glm::vec3(position, 0.0f));
    //glUniformMatrix4fv(glGetUniformLocation(shader_program_id, "model"), 1, GL_FALSE, glm::value_ptr(model));

    //view = glm::translate(view, glm::vec3(0.0f, 0.0f, -3.0f));
    //glUniformMatrix4fv(glGetUniformLocation(shader_program_id, "view"), 1, GL_FALSE, glm::value_ptr(view));

    //projection = glm::ortho(0, 800, 0, 600, 1, 1000);
    //glUniformMatrix4fv(glGetUniformLocation(shader_program_id, "projection"), 1, GL_FALSE, glm::value_ptr(projection));

    glBindVertexArray(vao);
    glDrawArrays(GL_TRIANGLES, 0, 6);
    glBindVertexArray(0);
}

shader_ui.vert

#version 330 core

layout (location = 0) in vec2 position;
layout (location = 1) in vec3 color;

out vec3 fragColor;

void main()
{
    gl_Position = vec4(position, 0.0f, 1.0f);
    fragColor = color;
}

shader_ui.frag

#version 330 core

in vec3 fragColor;
out vec4 color;

void main()
{
    color = vec4(fragColor, 1.0f);
}

如果我未能提供任何相关代码,请告诉我。我认为这涵盖了可能剖析问题所在的所有必要内容,但如果没有,我很乐意添加任何内容。

最佳答案

您的 draw_rect() 函数每帧都分配一个新的顶点缓冲区,并且从不释放它。似乎在运行主循环一小段时间后,已经建立了足够多的 VBO,以至于在程序终止时释放它们需要花费大量时间。这应该是导致挂起的原因。

要解决这个问题,只需在初始化时创建一个 VBO 并在调用 glDrawArrays() 之前绑定(bind)它。您可以在程序使用 glDeleteBuffers() 终止时释放它。

关于c++ - 添加额外的渲染调用时 GLFW 在关闭时挂起,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27446951/

相关文章:

C 宏串联创建结构体

performance - 在 OpenGL 中不断向 GPU 上传新纹理的开销是多少?

c++ - emplace_back() 未按预期运行

c++ - 为什么这段代码中的 static_cast on time(0)

c - "int k = ((int)i)"有什么作用?

c - 为什么 fork() 返回值是 -1,为什么 wait() 退出状态不是 0?

java - 添加灯光后,环境光变得更亮(OpenGL、法线贴图)

c - OpenGL - 在不使用 GLUT 的情况下添加文本

c++ - 按值(value)返回总是常量吗?

c++ - 调试当前项目启动的进程