0

I have an application which renders a 3d object using OpenGL, allowing the user to rotate and zoom and inspect the object. Currently, this is driven directly by received mouse messages (it's a Windows MFC MDI application). When a mouse movement is received, the viewing matrix is updated, and the scene re-rendered into the back buffer, and then SwapBuffers is called. For a spinning view, I start a 20ms timer and render the scene on the timer, with small updates to the viewing matrix each frame. This is OK, but is not perfectly smooth. It sometimes pauses or skips frames, and is not linked to vsync. I would love to make it smoother and smarter with the rendering.

It's not like a game where it needs to be rendered every frame though. There are long periods where the object is not moved, and does not need to be re-rendered.

  • I have come across GLFW library and the glfwSwapInterval function. Is this a commonly used solution?
  • Should I create a separate thread for the render loop, rather than being message/timer driven?
  • Are there other solutions I should investigate?
  • Are there any good references for how to structure a suitable render loop? I'm OK with all the rendering code - just looking for a better structure around the rendering code.
genpfault
  • 51,148
  • 11
  • 85
  • 139
user1961169
  • 783
  • 6
  • 17

1 Answers1

-1

So, I consider you are using GLFW for creating / operating your window.

If you don't have to update your window on each frame, suggest using glfwWaitEvents() or glfwWaitEventsTimeout(). The first one tells the system to put this process (not window) on sleep state, until any event happens (mouse press / resize event etc.). The second one is similar, but you can specify a timeout for the sleep state. The function will wait till any event happens OR till specified time runs out.

What's for the glfwSwapInterval(), this is probably not the solution you are looking for. This function sets the amount of frames that videocard has to skip (wait) when glfwSwapBuffers() is called.

If you, for example, use glfwSwapInterval(1) (assuming you have valid OpenGL context), this will sync your context to the framerate of your monitor (aka v-sync, but I'm not sure if it is valid to call it so).

If you use glfwSwapInterval(0), this will basicly unset your syncronisation with monitor, and videocard will swap buffers with glfwSwapBuffers() instanly, without waiting.

If you use glfwSwapInterval(2), this will double up the time that glfwSwapBuffers() waits after (or before?) flushing framebuffer to screen. So, if you have, for instance, 60 fps on your display, using glfwSwapInterval(2) will result in 30 fps in your program (assuming you use glfwSwapBuffers() to flush framebuffer).

The glfwSwapInterval(3) will give you 20 fps, glfwSwapInterval(4) - 15 fps and so on.

As for separate render thread, this is good if you want to divide your "thinking" and rendering processes, but it comes with its own advantages, disadvantages and difficulties. Tip: some window events can't be handled "properly" without having separate thread (See this question).

The usual render loop looks like this (as far as I've learned from learnopengl lessons):

// Setup process before...

while(!window_has_to_close) // <-- Run game loop until window is marked "has to
                            // close". In GLFW this is done using glfwWindowShouldClose()
                            // https://www.glfw.org/docs/latest/group__window.html#ga24e02fbfefbb81fc45320989f8140ab5
{
    // Prepare for handling input events (e. g. callbacks in GLFW)
    prepare();

    // Handle events (if there are none, this is just skipped)
    glfwPollEvents(); // <-- You can also use glfwWaitEvents()

    // "Thinknig step" of your program
    tick();

    // Clear window framebuffer (better also put this in separate func)
    glClearColor(0.f, 0.f, 0.f, 1.f);
    glClear(GL_COLOR_BUFFER_BIT);

    // Render everything
    render();

    // Swap buffers (you can also put this in separate function)
    glfwSwapBuffers(window); // <-- Flush framebuffer to screen
}

// Exiting operations after...

See this ("Ready your engines" part) for additional info. Wish you luck!

  • Thanks for your reply. The weblink at the end is a great resource that I will study in detail. I wish I found that three years ago - it would have saved me a lot of work at the time. :) – user1961169 Mar 02 '22 at 06:25