You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用GLFW、GLAD与ImGui无法渲染三角形的问题求助

问题

开发结合ImGui与现代OpenGL 3的3D图形程序,基于GLFW(Mac平台静态库libglfw3.a),通过GLAD加载OpenGL函数,使用ImGui的imgui_impl_opengl3_loader.h等后端文件。程序主窗口正常显示,但点击"Show Figure"按钮弹出的窗口无法渲染三角形,而相同绘制逻辑脱离ImGui环境可正常运行,怀疑是ImGui与OpenGL渲染流程冲突。

简化版代码:

#include <iostream>
#include "imgui.h"
#include "glad.h"
#include "imgui_impl_glfw.h"
#include "imgui_impl_opengl3.h"
#define GL_SILENCE_DEPRECATION
#if defined(IMGUI_IMPL_OPENGL_ES2)
#include <GLES2/gl2.h>
#endif
#include "glfw3.h"

// Vertex shader source
const char *vertexShaderSource = "#version 330 core\n"
                                 "layout (location = 0) in vec3 aPos;\n"
                                 "void main()\n"
                                 "{\n"
                                 "   gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
                                 "}\0";

// Fragment shader source
const char *fragmentShaderSource = "#version 330 core\n"
                                   "out vec4 FragColor;\n"
                                   "void main()\n"
                                   "{\n"
                                   "    FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
                                   "}\0";

int main()
{
    // Initiate GLFW
    glfwInit();  

    // Decide GL+GLSL versions
#if defined(IMGUI_IMPL_OPENGL_ES2)
    const char *glsl_version = "#version 100";
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
    glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
#elif defined(__APPLE__)
    const char *glsl_version = "#version 150";
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#else
    const char *glsl_version = "#version 130";
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
#endif

    GLFWwindow *window = glfwCreateWindow(1280, 720, "TestWindow1", NULL, NULL);
    if (window == NULL)
    {
        std::cout << "ERROR" << std::endl;
        return -1;
    }

    glfwMakeContextCurrent(window);
    glfwSwapInterval(1);

    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    {
        std::cout << "Failed to initialize GLAD" << std::endl;
        return -1;
    }
    
    IMGUI_CHECKVERSION();
    ImGui::CreateContext();
    ImGuiIO &io = ImGui::GetIO();
    io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
    io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;

    ImGui::StyleColorsLight();

    ImGui_ImplGlfw_InitForOpenGL(window, true);
    ImGui_ImplOpenGL3_Init(glsl_version);

    ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
    bool showFigure = false;

    // Compile and link shaders
    unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
    glCompileShader(vertexShader);
    int success;
    char infoLog[512];
    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
    }

    unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
    glCompileShader(fragmentShader);
    glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
    }

    unsigned int shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);
    glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
    if (!success)
    {
        glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER_PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
    }

    unsigned int VAO;
    glGenVertexArrays(1, &VAO);
    glBindVertexArray(VAO);
    float vertices[] = {
        -0.5f, -0.5f, 0.0f,
        0.5f, -0.5f, 0.0f,
        0.0f, 0.5f, 0.0f};
    unsigned int vertexBuffer0;
    glGenBuffers(1, &vertexBuffer0);
    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer0);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *)0);
    glEnableVertexAttribArray(0);

    while (!glfwWindowShouldClose(window))
    {
        glfwPollEvents();

        ImGui_ImplOpenGL3_NewFrame();
        ImGui_ImplGlfw_NewFrame();
        ImGui::NewFrame();

        ImVec2 mainWindowSize = ImVec2(1000, 600);
        ImGui::SetNextWindowSize(mainWindowSize);
        ImGui::Begin("TestGui");

        if (ImGui::Button("Show Figure"))
        {
            showFigure = true;
        }
        
        if (showFigure == true)
        {
            showFigure = false;
            GLFWwindow *figureWindow = glfwCreateWindow(500, 500, "Figure", NULL, NULL);
            glfwMakeContextCurrent(figureWindow);
            glfwSwapInterval(1);

            while (!glfwWindowShouldClose(figureWindow))
            {
                glClearColor(0.2, 0.3, 0.3, 1.0);
                glClear(GL_COLOR_BUFFER_BIT);

                glUseProgram(shaderProgram);
                glBindVertexArray(VAO);
                glDrawArrays(GL_TRIANGLES, 0, 3);

                glfwSwapBuffers(figureWindow);
                glfwPollEvents();
            }
            glfwDestroyWindow(figureWindow);
            glfwMakeContextCurrent(window);
        }

        ImGui::End();

        ImGui::Render();
        int display_w, display_h;
        glfwGetFramebufferSize(window, &display_w, &display_h);
        glViewport(0, 0, display_w, display_h);
        glClearColor(clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w);
        glClear(GL_COLOR_BUFFER_BIT);
        ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
        glfwSwapBuffers(window);
    }
    
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &vertexBuffer0);
    glDeleteProgram(shaderProgram);
    ImGui_ImplOpenGL3_Shutdown();
    ImGui_ImplGlfw_Shutdown();
    ImGui::DestroyContext();

    glfwDestroyWindow(window);
    glfwTerminate();
    return 0;
}

编译命令:

gcc -std=c++17 -I/INCLUDE...PATH/ -c Test.cpp imgui.cpp imgui_widgets.cpp imgui_tables.cpp imgui_impl_opengl3.cpp imgui_impl_glfw.cpp imgui_draw.cpp imgui_demo.cpp
gcc -c glad.c
gcc -L/LIBRARY...PATH/ -lglfw3 -std=c++17 -lstdc++ -framework Carbon -framework Cocoa -framework OpenGL -framework IOKit -o aTest.out Test.o imgui.o imgui_widgets.o imgui_tables.o imgui_impl_opengl3.o imgui_impl_glfw.o imgui_draw.o imgui_demo.o glad.o
排查建议
  • OpenGL上下文资源不共享:GLFW默认创建的新窗口不会共享原上下文的VAO、VBO、着色器程序等资源,你在主窗口上下文创建的shaderProgram、VAO无法在新窗口上下文直接使用。解决方法是创建新窗口时指定主窗口为共享上下文:

    GLFWwindow *figureWindow = glfwCreateWindow(500, 500, "Figure", NULL, window);
    
  • GLAD未在新上下文初始化:GLAD加载的函数指针与当前上下文绑定,切换到新窗口上下文后必须重新初始化GLAD。在glfwMakeContextCurrent(figureWindow);后添加:

    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    {
        std::cout << "Failed to initialize GLAD for figure window" << std::endl;
        glfwDestroyWindow(figureWindow);
        glfwMakeContextCurrent(window);
        return -1;
    }
    
  • 嵌套事件循环阻塞主窗口:当前代码点击按钮后进入新窗口的while循环,会完全阻塞主窗口的事件处理与渲染,导致主窗口假死。正确做法是将新窗口逻辑整合到主循环中,用变量跟踪窗口状态:

    // 定义变量跟踪窗口状态
    GLFWwindow *figureWindow = nullptr;
    
    // 主循环内处理窗口创建
    if (showFigure == true)
    {
        showFigure = false;
        figureWindow = glfwCreateWindow(500, 500, "Figure", NULL, window);
        glfwMakeContextCurrent(figureWindow);
        if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
        {
            // 错误处理逻辑
        }
        glfwSwapInterval(1);
    }
    
    // 主循环内处理新窗口渲染
    if (figureWindow != nullptr && !glfwWindowShouldClose(figureWindow))
    {
        glfwMakeContextCurrent(figureWindow);
        glClearColor(0.2, 0.3, 0.3, 1.0);
        glClear(GL_COLOR_BUFFER_BIT);
        glUseProgram(shaderProgram);
        glBindVertexArray(VAO);
        glDrawArrays(GL_TRIANGLES, 0, 3);
        glfwSwapBuffers(figureWindow);
        // 切回主窗口上下文继续渲染ImGui
        glfwMakeContextCurrent(window);
    }
    else if (figureWindow != nullptr)
    {
        glfwDestroyWindow(figureWindow);
        figureWindow = nullptr;
    }
    
  • ImGui状态污染OpenGL上下文:ImGui渲染会修改OpenGL状态(如混合、深度测试等),切换到新窗口渲染前需重置这些状态。在新窗口渲染循环中添加:

    glDisable(GL_BLEND);
    glDisable(GL_DEPTH_TEST);
    // 根据绘制需求调整其他状态
    
  • 着色器版本不匹配:新窗口创建时未设置与主窗口一致的OpenGL版本提示,可能导致上下文版本不兼容,着色器无法运行。创建新窗口前复用主窗口的版本配置逻辑,确保上下文版本一致。

内容的提问来源于stack exchange,提问作者Christ Liu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 04:53:13