¿Cómo dibujar mientras se cambia el tamaño de la ventana GLFW?
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:
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.
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 glfwSwapBuffers
para 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
, glClear
y glfwSwapBuffers
) del bucle principal a draw
. Deje una llamada a draw
en su bucle principal y cree window
una variable global o pásela draw
cuando la llame; de lo contrario, estará fuera del alcance de draw
donde 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).
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);