添加额外的渲染调用时,GLFW会挂起

时间:2014-12-12 15:34:03

标签: c++ c opengl glfw

所以我一直在尝试学习如何编程openGL过去一段时间,虽然它在很多时候一直在弯曲我认为我已经开始深入了解它是如何工作的。

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

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

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

每当我删除调用以绘制简单的2-D矩形时,此挂起就会消失,窗口会按预期立即关闭。有没有人有任何想法为什么会出现这种情况?


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

rect.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

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

如果我没有提供任何相关代码,请告诉我。我认为这涵盖了可能解决问题的所有必要条件,但如果不是,我会很乐意添加任何内容。

1 个答案:

答案 0 :(得分:3)

你的draw_rect()函数每帧都分配一个新的顶点缓冲区,永远不会释放它。似乎在运行主循环很短的时间后,足够的这些VBO已经建立起来,当程序终止时会释放它们需要相当长的时间。这应该是导致挂起的原因。

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