如何在渲染循环中运行繁重的模拟时刷新图形用户界面画面?

dy1byipe  于 2022-09-26  发布在  其他
关注(0)|答案(1)|浏览(117)

我正在尝试创建一个应用程序,在那里用户可以运行一个(耗时的)后端物理模拟与按下一个按钮。但与此同时,我希望图形用户界面的其余部分保持正常工作,在模拟结束之前不要“冻结”。现在我知道在OpenGL中组合多个线程来渲染并不是一个好主意,所以我的想法很简单:1)使用一个线程(我假设是默认线程)来运行除物理之外的所有东西。2)使用另一个线程,只运行我已经限制在一个函数中的物理,正如你将看到的。但即使这样,整个图形用户界面仍然“冻结”,因此在物理结束之前它是毫无用处的。我如何才能解决这个问题?

下面是我认为它可以工作的代码。它呈现了一个“测试按钮”,以检查我是否可以在物理运行时按下它,以及“运行物理”按钮,该按钮会触发繁重的计算。


# include"imgui.h"

# include"imgui_impl_glfw.h"

# include"imgui_impl_opengl3.h"

# include<GL/glew.h>

# include<GLFW/glfw3.h>

# include<cstdio>

# include<cmath>

# include<thread>

//Hypothetical "heavy" computation
void run_physics()
{
    for (double z = 0.0; z < 10000.0; z += 0.001)
    {
        double y = exp(sin(sqrt(z*abs(z)+ cos(z))));
    }
    return;
}

int main()
{
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    GLFWwindow *window = glfwCreateWindow(800,600, "Test", NULL, NULL);
    if (window == NULL)
    {
        printf("Failed to open a glfw window. Exiting...n");
        return 0;
    }

    glfwMakeContextCurrent(window);

    glewExperimental = GL_TRUE;
    if (glewInit() != GLEW_OK)
    {
        printf("Failed to initialize glew. Exiting...n");
        return 0;
    }

    IMGUI_CHECKVERSION();
    ImGui::CreateContext();
    ImGuiIO &io = ImGui::GetIO();
    (void)io;
    ImGui::StyleColorsDark();
    ImGui_ImplGlfw_InitForOpenGL(window, true);
    ImGui_ImplOpenGL3_Init("#version 330");

    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    while (!glfwWindowShouldClose(window))
    {
        glClear(GL_COLOR_BUFFER_BIT);

        ImGui_ImplOpenGL3_NewFrame();
        ImGui_ImplGlfw_NewFrame();
        ImGui::NewFrame();
        ImGui::Begin("Test");
        ImGui::Button("Test button");
        if (ImGui::Button("Run physics"))
        {
            //This pauses the render loop until run_physics is done. Good.
            //run_physics();

            //This also pauses the render loop. Why?
            std::thread thr(run_physics);
            thr.join();
        }
        ImGui::End();
        ImGui::Render();
        ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());

        glfwSwapBuffers(window);
        glfwPollEvents();
    }
    ImGui_ImplOpenGL3_Shutdown();
    ImGui_ImplGlfw_Shutdown();
    ImGui::DestroyContext();
    glfwTerminate();
    return 0;
}
zpf6vheq

zpf6vheq1#

问题在于thr.join()调用,它将被“阻塞”,直到线程退出。

有几种方法可以解决这个问题。例如,您可以创建在渲染线程中轮询的原子状态标志。当线程完成时,它在退出之前设置标志。如果主呈现线程看到它设置的标志,那么它会调用join调用并获取结果,这应该会很快发生。

相关问题