目次

imguiを使ってみる(1)
imguiを使ってみる(2)
imguiを使ってみる(3)


前回、imguiの中で三角形をレンダリングしてみた。

imgui triangle

今回はスライダーを追加して三角形の色を変化させてみる。前回のコードを流用すれば簡単にできる。

まず前回のプロジェクトをコピーする:

前回の実行ファイルは消してしまおう。

$ cp -r imgui-triangle imgui-slider
$ cd imgui-slider
$ rm imgui-triangle

main.cppを編集する:

変えるのはMyScene::render関数とmain関数だけである。前回の該当する関数は消してしまって以下のコードをコピペする。

MyScene::renderglBufferSubDataで色情報を更新するところを追加しただけである。

void MyScene::render()
{
    glBindFramebuffer(GL_FRAMEBUFFER, this->framebuffer);
    glDrawBuffers(1, &this->drawbuffer);

    glClearColor(0.0, 0.0, 0.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glViewport(0,0, this->width, this->height);

    // glOrtho(-1.0,1.0, -1.0,1.0, -1.0,1.0) と同じ行列
    const GLfloat mvp[] = {1.0f,0.0f,0.0f,0.0f,
                           0.0f,1.0f,0.0f,0.0f,
                           0.0f,0.0f,-1.0f,0.0f,
                           0.0f,0.0f,0.0f,1.0f};
    
    glUseProgram(this->program);
    glUniformMatrix4fv(this->mvp, 1, GL_FALSE, mvp);

    glBindVertexArray(this->vao);

    glBindBuffer(GL_ARRAY_BUFFER, this->vbo[0]);
    glBindBuffer(GL_ARRAY_BUFFER, this->vbo[1]);
    glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(triangleColor), triangleColor);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    
    glDrawArrays(GL_TRIANGLES, 0, 3);

    glBindVertexArray(0);
    glUseProgram(0);
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
}

main関数はSliderとButtonを追加しただけ。

int main(int, char**)
{
    // Setup window
    glfwSetErrorCallback(error_callback);
    if (!glfwInit())
        return 1;
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#if __APPLE__
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
    GLFWwindow* window = glfwCreateWindow(1280, 720, "ImGui Slider", NULL, NULL);
    glfwMakeContextCurrent(window);
    glfwSwapInterval(1); // Enable vsync
    gl3wInit();

    // Setup ImGui binding
    ImGui_ImplGlfwGL3_Init(window, true);

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

    myScene = MyScene(500,500);
    
    // Main loop
    while (!glfwWindowShouldClose(window))
    {
        glfwPollEvents();
        ImGui_ImplGlfwGL3_NewFrame();

        // mySceneをフレームバッファに描画してimguiにテクスチャ画像として渡す
        { 
            const int W_MARGIN = 16, H_MARGIN = 36;
            ImGui::SetNextWindowSize(ImVec2(myScene.width+W_MARGIN, myScene.height+H_MARGIN));

            // 右下のリサイズ用のグリップが邪魔なのでリサイズ不可にした窓を作る
            ImGui::Begin("triangle", NULL, ImGuiWindowFlags_NoResize);
            {
                ImVec2 pos = ImGui::GetCursorScreenPos();
                myScene.render();
                ImGui::GetWindowDrawList()->AddImage((void*)myScene.texture,
                                                     ImVec2(pos.x,pos.y),
                                                     ImVec2(pos.x+myScene.width, pos.y+myScene.height),
                                                     ImVec2(0,1),
                                                     ImVec2(1,0));
            }
            ImGui::End();
        }

        // SliderとButtonを試す
        {
            ImGui::SetNextWindowSize(ImVec2(200,150));
            ImGui::SetNextWindowPos(ImVec2(600,50));

            ImGui::Begin("controller");
            {
                ImGui::SliderFloat("red", &triangleColor[0], 0.0f, 1.0f, "%.3f");
                ImGui::SliderFloat("green", &triangleColor[4], 0.0f, 1.0f, "%.3f");
                ImGui::SliderFloat("blue", &triangleColor[8], 0.0f, 1.0f, "%.3f");

                for (int i=0; i<5; i++) ImGui::Spacing(); // vertical spacing x 5

                // Button
                if (ImGui::Button("Quit")) break; // exit main loop
            }
            ImGui::End();
        }

        // Rendering
        int display_w, display_h;
        glfwGetFramebufferSize(window, &display_w, &display_h);
        glViewport(0, 0, display_w, display_h);
        glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w);
        glClear(GL_COLOR_BUFFER_BIT);
        ImGui::Render();
        glfwSwapBuffers(window);
    }

    // Cleanup
    ImGui_ImplGlfwGL3_Shutdown();
    glfwTerminate();

    return 0;
}

これでスライダーをいじれば色が変わるはずである。Quitボタンを押せばウィンドウが閉じる。

imgui slider

これでGUIのコントローラーと自分のレンダリングを結びつけることができた。

まとめ

imguiをちょっと触ってみたが、かなり簡単にGUIが使えることがわかった。

面倒なのは前回やった自分のシーンのレンダリングの部分くらいであろうか。それも一度やってしまえば大したことはないので今後はOpenGLでGUIといえばimguiを使うことになりそうである。

自分が使うには十分というか十分過ぎるくらいの機能がある。ゲームなど作る人にとってどうなのかは分からないがちょっとしたプロトタイプを作ったりするには便利なのではないだろうか。

問題はドキュメントがあまり無いということだと思う。現状ではimgui.cppのコメントを読んだりimgui_demo.cppを覗いて名前から類推してコピペして試してみたりするのが良いと思う。

imgui自体C++で書かれているが、STLすら使っていないのでちょっと驚いた。やたらと外部のライブラリに頼ったりするとコンパイルが通らなくて断念するということもあるので良い判断だと思われる。

ともあれimguiは素晴らしいものである。ocornut氏に賛辞を贈りたい。