Advertisement

Slow update of GUI elements on window resize

Started by November 13, 2022 03:33 PM
3 comments, last by joakim.wennergren@databeams.se 2 years, 1 month ago

Hello Gamedev!

I'm currently working on a project which utilize opengl to render a GUI.

Now when i'm resizing the window i want to resize the gui elements with it. But when i do all elements seem to lag behind. See video.

Why is this?

My framebuffer size callback:

void framebuffer_size_callback(GLFWwindow *window, int width, int height)
{
    glViewport(0, 0, width, height);
    Window::Render(window);
    Services::Get<CameraService>()->cameras[0].screenSize = {width, height};
}
void Window::Render(GLFWwindow *w)
{
    float currentFrame = glfwGetTime();
    static int lastFrame;
    static int deltaTime = currentFrame - lastFrame;
    lastFrame = currentFrame;

    glClear(GL_COLOR_BUFFER_BIT);

    RendererService *rendererService = Services::Get<RendererService>();

    auto renderers = rendererService->renderers;

    for (auto renderer : renderers)
    {
        renderer->Render();
    }


    glfwSwapBuffers(w);
}

And for example, a rounded rectangle looks like this:


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

#include "Rectangle.h"
#include "stb_image.h"

Rectangle::Rectangle()
{

    shader = new OpenGL::Core3::Shader();

    std::string vertexShaderSource = R"END(
        
        #version 330 core
        layout (location = 0) in vec3 aPos;

        uniform mat4 model;
        uniform mat4 view;
        uniform mat4 projection;
        uniform vec2 pos;
        uniform vec3 rectColor;
        uniform vec2 rectSize;
        uniform float radius;

        out vec2 position;
        out vec3 RectColor;
        out vec2 RectSize;
        out float Radius;

        void main()
        {
            RectColor = rectColor;
            RectSize = rectSize;
            position = pos;
            Radius = radius;
            gl_Position = projection * view * model * vec4(aPos, 1.0f);
        }

        )END";

    std::string fragmentShaderSource = R"END(
        
        #version 330 core
        out vec4 FragColor;

        in vec2 position;
        in vec3 RectColor;
        in vec2 RectSize;
        in float Radius;

        // from https://iquilezles.org/articles/distfunctions
        float roundedBoxSDF(vec2 CenterPosition, vec2 Size, float Radius) {
            return length(max(abs(CenterPosition)-Size+Radius,0.0))-Radius;
        }

        void main() {

            // the pixel space location of the rectangle.
            vec2 location = position;

            // How soft the edges should be (in pixels). Higher values could be used to simulate a drop shadow.
            float edgeSoftness  = 1.0f;
            
            // The radius of the corners (in pixels).
            float radius = Radius;
            
            // Calculate distance to edge.   
            float distance 		= roundedBoxSDF(gl_FragCoord.xy - location - (RectSize/2.0f), RectSize / 2.0f, radius);
            
            // Smooth the result (free antialiasing).
            float smoothedAlpha =  1.0f-smoothstep(0.0f, edgeSoftness * 2.0f,distance);
            
            // Return the resultant shape.
            vec4 quadColor		= mix(vec4(1.0f, 1.0f, 1.0f, 0.0), vec4(RectColor, smoothedAlpha), smoothedAlpha);
            
            // Apply a drop shadow effect.
            float shadowSoftness = 30.0f;
            vec2 shadowOffset 	 = vec2(0.0, 0.0);
            float shadowDistance = roundedBoxSDF(gl_FragCoord.xy - location + shadowOffset - (RectSize/2.0f), RectSize / 2.0f, radius);
            float shadowAlpha 	 = 1.0f-smoothstep(-shadowSoftness, shadowSoftness, shadowDistance);
            vec4 shadowColor 	 = vec4(1.0f, 1.0f, 1.0f, 0.6f);
            FragColor 			 = mix(quadColor, shadowColor, shadowAlpha - smoothedAlpha);

        }
         
        )END";

    shader->Compile(vertexShaderSource.c_str(), fragmentShaderSource.c_str());

    float vertices[] = {
        // first triangle
        0.5f,  0.5f, 0.0f,  // top right
        0.5f, -0.5f, 0.0f,  // bottom right
        -0.5f,  0.5f, 0.0f,  // top left 
        // second triangle
        0.5f, -0.5f, 0.0f,  // bottom right
        -0.5f, -0.5f, 0.0f,  // bottom left
        -0.5f,  0.5f, 0.0f   // top left
    }; 

    unsigned int VBO, VAO;
    glGenVertexArrays(1, &vao);
    glGenBuffers(1, &VBO);
    // bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s).
    glBindVertexArray(vao);

    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);

    // note that this is allowed, the call to glVertexAttribPointer registered VBO as the vertex attribute's bound vertex buffer object so afterwards we can safely unbind
    glBindBuffer(GL_ARRAY_BUFFER, 0); 

    // You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, but this rarely happens. Modifying other
    // VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs (nor VBOs) when it's not directly necessary.
    glBindVertexArray(0); 

    addElement(this);
}

void Rectangle::Draw(float deltaTime)
{
    // Activate shader
    shader->Activate();

    // @todo Do something about mainCamera and following cameras.. Active camera?
    Camera mainCamera = Services::Get<CameraService>()->cameras[0];

    
    // @todo this is fine me thinks for now!
    auto openglShader = static_cast<OpenGL::Core3::Shader *>(shader);

    glm::mat4 projection = glm::perspective(glm::radians(mainCamera.Zoom), (float)mainCamera.screenSize.x / (float)mainCamera.screenSize.y, 0.2f, 100.0f);
    glm::mat4 view = mainCamera.GetViewMatrix();
    glm::mat4 model = glm::mat4(1.0f);

    view = glm::translate(view, glm::vec3(0.0f, 0.0f, 0.0f));
    view = glm::rotate(view, glm::radians(0.0f), glm::vec3(0.0f, 0.0f, 1.0f));
    // model = glm::translate(model, glm::vec3(0.0f, 0.0f, 0.0f));
    model = glm::scale(model, glm::vec3(10.0f, 10.0f, 0.0f));

    openglShader->setMat4("projection", projection);
    
    openglShader->setMat4("view", view);
    
    openglShader->setMat4("model", model);

    openglShader->setFloat("radius", transform.dimension.radius);
    
    openglShader->setVec2("pos", glm::vec2{transform.position.x, transform.position.y});
    
    openglShader->setVec2("rectSize", glm::vec2{transform.dimension.width, transform.dimension.height});

    openglShader->setVec3("rectColor", glm::vec3{style.Background.r, style.Background.g, style.Background.b});

    glBindVertexArray(vao);

    glDrawArrays(GL_TRIANGLES, 0, 6);
}

Thanks for help,

Joakim Wennergren

None

joakim.wennergren@databeams.se said:
Why is this?

I'm speculating here a bit but based on the code you shared I would expect this behavior. Did you try putting the Window::Render call as the last call in your size callback? To me it looks like you are updating the camera last after you already rendered, and should be 1 frame at least behind. And does the rendering happen in it's own thread? I've read that when you are using GLFW and not doing the rendering in it's own thread it can cause slowdown/lag issues.

Here is a post with an adjecent problem and I think it will help, since the events from the message pump are not reliable enough to get smooth resizing. Basically you need to poll it in a loop. It's better explained with a fix in this post: https://discourse.glfw.org/t/when-responses-to-window-refresh-take-too-long/1899/2

“It's a cruel and random world, but the chaos is all so beautiful.”
― Hiromu Arakawa

Advertisement

@Ultraporing Thanks for your reply, Ultraporing.

Did you try putting the Window::Render call as the last call in your size callback?

Yes have tried this.


I've been messing around with the code and what i believe it boils down to is the resize events.

I have tried putting the resizing of elements in a seperate thread. Though this causes more problems. ?

I will look into that thread and see if i can pump the eventmessages somehow!

None

@joakim.wennergren@databeams.se

I think i solved it now.

I replaced glfwPollEvents with glfwWaitEvents().

and replaced my cameralogic and passed the window to the draw functions again!

Voilá:

None

This topic is closed to new replies.

Advertisement