¿Cómo dibujar mientras se cambia el tamaño de la ventana GLFW?

Resuelto Craig asked hace 7 años • 0 respuestas

Cada vez que cambio el tamaño de una ventana GLFW, no se dibuja mientras cambio el tamaño de la ventana. La parte recién expuesta de la ventana solo se dibuja después de que termino de cambiar el tamaño de la ventana. Puedes verlo por ti mismo en la siguiente imagen:

imagen

Aquí está el código de mi aplicación. Estoy ejecutando Windows 10 en Visual Studio 2015

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

void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow *window);
void get_resolution(int* window_width, int* window_height);
void initGlfwSettings();
GLFWwindow* initGlfwWindow();
void initGlad();

// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;

int main()
{
    initGlfwSettings();

    GLFWwindow* window = initGlfwWindow();

    initGlad();

    // glad: load all OpenGL function pointers
    // ---------------------------------------


    // render loop
    // -----------
    while (!glfwWindowShouldClose(window))
    {
        int width, height;
        glfwGetWindowSize(window, &width, &height);


        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
        // input
        // -----
        processInput(window);

        // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
        // -------------------------------------------------------------------------------
        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    // glfw: terminate, clearing all previously allocated GLFW resources.
    // ------------------------------------------------------------------
    glfwTerminate();
    return 0;
}

// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
// ---------------------------------------------------------------------------------------------------------
void processInput(GLFWwindow *window)
{
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
        glfwSetWindowShouldClose(window, true);
}

// glfw: whenever the window size changed (by OS or user resize) this callback function executes
// ---------------------------------------------------------------------------------------------
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
    // make sure the viewport matches the new window dimensions; note that width and 
    // height will be significantly larger than specified on retina displays.
    glViewport(0, 0, width, height);
}

void get_resolution(int* window_width, int* window_height) {
    const GLFWvidmode * mode = glfwGetVideoMode(glfwGetPrimaryMonitor());

    *window_width = mode->width;
    *window_height = mode->height;
}

void initGlfwSettings()
{
    // glfw: initialize and configure
    // ------------------------------
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);


    #ifdef __APPLE__
        glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X
    #endif
}

GLFWwindow* initGlfwWindow()
{
    /*GLFWmonitor* monitor = glfwGetPrimaryMonitor();
    int width;
    int height;

    get_resolution(&width, &height);*/



    GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "learning opengl", NULL, NULL);
    if (window == NULL)
    {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        exit(1);
    }

    glfwMakeContextCurrent(window);
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
    glfwSwapInterval(1);

    return window;
}

void initGlad()
{
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    {
        std::cout << "Failed to initialize GLAD" << std::endl;
        exit(1);
    }
}

Explique cualquier solución a este problema.

Craig avatar Aug 25 '17 18:08 Craig
Aceptado

El procesamiento de eventos ( glfwPollEvents) se detiene cada vez que se cambia el tamaño de la ventana, pero mientras lo hace, emite constantemente eventos de cambio de tamaño, que se procesan sobre la marcha mediante la devolución de llamada de cambio de tamaño que ya utiliza. Puedes volver a dibujar tu escena desde allí y llamar glfwSwapBufferspara renderizar incluso cuando estés en formato glfwPollEvents. En términos prácticos, esto se puede lograr mediante el siguiente código:

void draw()
{
    // Rendering code goes here
    glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    glfwSwapBuffers(window);
}

void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
    // make sure the viewport matches the new window dimensions; note that width and 
    // height will be significantly larger than specified on retina displays.
    glViewport(0, 0, width, height);
    // Re-render the scene because the current frame was drawn for the old resolution
    draw();
}

y mueva su renderizado ( glClearColor, glCleary glfwSwapBuffers) del bucle principal a draw. Deje una llamada a drawen su bucle principal y cree windowuna variable global o pásela drawcuando la llame; de ​​lo contrario, estará fuera del alcance de drawdonde es necesaria glfwSwapBuffers.

Eso solo funciona cuando el usuario mueve el mouse mientras lo mantiene presionado; simplemente mantener presionado el botón izquierdo en la parte de cambio de tamaño de la ventana aún se detiene. Para solucionarlo, debes renderizar en un hilo separado además de este. (No, no puedes hacer eso sin subprocesos. Lo siento, así es como funciona GLFW, nadie excepto ellos puede cambiarlo).

Kotauskas avatar Jun 15 '2019 20:06 Kotauskas

Me sorprende que nadie haya mencionado la devolución de llamada de actualización de ventana , que es el método documentado por GLFW para este problema específico, en la documentación del glfwPollEvents() enlace :

En algunas plataformas, mover una ventana, cambiar su tamaño o realizar una operación de menú provocará que se bloquee el procesamiento de eventos. Esto se debe a cómo está diseñado el procesamiento de eventos en esas plataformas. Puede utilizar la devolución de llamada de actualización de ventana para volver a dibujar el contenido de su ventana cuando sea necesario durante dichas operaciones.

Para ser justos, está un poco enterrado y yo mismo no pude encontrarlo hace un tiempo.

void window_refresh_callback(GLFWwindow *window)
{
    render();
    glfwSwapBuffers(window);
    glFinish(); // important, this waits until rendering result is actually visible, thus making resizing less ugly
}

tenga en cuenta que para que esto funcione correctamente glViewport()se debe llamar a algún lugar

void framebuffer_size_callback(GLFWwindow *window, int width, int height)
{
    glViewport(0, 0, width, height);
}

en su código de configuración GLFW:

// rest of code
glfwSetWindowRefreshCallback(window, window_refresh_callback);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
// rest of code

con ediciones anteriores descubrí que cambiar el tamaño es más estable, incluso más estable que renderizar en la devolución de llamada de cambio de tamaño de la ventana, incluso con glFinish allí, también puedes comparar el comportamiento de tu aplicación con software como Blender

También tengo lo siguiente en mi código de inicialización de GLFW según las instrucciones de la documentación de GLFW para reducir el desgarro: https://www.glfw.org/docs/latest/quick.html#quick_swap_buffers

glfwSwapInterval(1);
Iyad Ahmed avatar Dec 29 '2023 13:12 Iyad Ahmed