ImGuiサンプル解説

ヘッダーファイルエリア

#include <GLFW/glfw3.h>Code language: plaintext (plaintext)

GLFWウィンドウライブラリのヘッダーを読み込みます。ウィンドウ作成、マウス/キーボード入力処理、OpenGLコンテキスト管理、ウィンドウメッセージループを担当します。

GLFWはウィンドウの作成・管理に特化したC言語製ライブラリです。ImGuiに属するライブラリではなく独立していますが、ImGuiの動作に必須なためインクルードする必要があります。前回の講座でプロジェクトフォルダへダウンロードし、プロジェクトに統合設定済みのはずです。

#include "imgui.h"Code language: plaintext (plaintext)

ImGuiのコアヘッダーファイルで、各種UIウィジェット、コンテキスト、スタイル、描画基礎APIなどすべてが定義されています。

#include "backends/imgui_impl_glfw.h"Code language: plaintext (plaintext)

ImGuiとGLFWを連携させるブリッジ層で、GLFWから取得したウィンドウ情報、マウス、キーボード、ウィンドウサイズなどの情報をImGuiへ転送します。

#include "backends/imgui_impl_opengl3.h"Code language: plaintext (plaintext)

ImGui OpenGL3レンダリングバックエンド適応層。OpenGLシェーダー、頂点バッファを生成し、ImGuiのUI描画データをGPUへ渡して描画させます。

#include <cstdio>Code language: plaintext (plaintext)

C++標準C入出力ライブラリで、printfを使ってエラーログ出力に利用します。


int main()Code language: plaintext (plaintext)

プログラムのエントリーポイント、説明は不要でしょう。

GLFW初期化処理

    // Initialize GLFW
    if (!glfwInit())
    {
        printf("GLFW initialization failed\n");
        return -1;
    }Code language: plaintext (plaintext)

glfwInit():グラボ、ウィンドウドライバ、入力デバイスなどGLFWのグローバルリソースを初期化します。

初期化に失敗した場合、エラーメッセージを出力して-1を返しプログラムを異常終了させます。OS側がこの終了コードを検知します。

OpenGLバージョン設定

    // OpenGL 3.3
    const char* glsl_version = "#version 330";Code language: plaintext (plaintext)

GLSLシェーダーのバージョン文字列を定義。OpenGL3.3にはGLSL 330が対応します。

glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);Code language: plaintext (plaintext)

OpenGLメジャーバージョンを3に指定

glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);Code language: plaintext (plaintext)

OpenGLマイナーバージョンを3に指定

 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);Code language: plaintext (plaintext)

コアプロファイル(Core Profile)を使用

ウィンドウ作成

    // Create window
    GLFWwindow* window = glfwCreateWindow(1000, 600, "ImGui Minimal Demo (VS2022)", nullptr, nullptr);Code language: plaintext (plaintext)

ウィンドウ解像度は幅1000×高さ600、タイトルは「ImGui Minimal Demo (VS2022)」。4番目の引数nullptrは標準ウィンドウモード、5番目はOpenGLコンテキストを共有するウィンドウ指定、nullptrで共有無しとなります。

戻り値はウィンドウハンドルポインタGLFWwindow*です。

 if (!window)
    {
        glfwTerminate();
        return -1;
    }Code language: plaintext (plaintext)

上記のウィンドウ作成に失敗するとwindow変数はnullptrとなります。

glfwTerminate()でGLFWが確保した全リソースを破棄します。

その後-1を返し、OSへプログラム異常終了を通知します。

glfwMakeContextCurrent(window);Code language: plaintext (plaintext)

現在のウィンドウをOpenGL描画コンテキストとして紐付け、以降のOpenGL描画命令は全てこのウィンドウに反映されます。

glfwSwapInterval(1);Code language: plaintext (plaintext)

垂直同期を有効化。引数1はディスプレイのリフレッシュにフレームを同期し画面ティアリングを防止。0にすると垂直同期オフでフレームレート制限が無くなります。

この設定は非常に重要で、有効にしないとGLFW描画とディスプレイ更新のタイミングがズレ画面が乱れる原因になります。

ImGuiグローバル初期化

IMGUI_CHECKVERSION(); // ヘッダーとバックエンドのバージョン整合性を検証、不一致時アサートエラー発生
ImGui::CreateContext(); // ImGuiグローバルコンテキストを作成、UI実行状態を一括管理
ImGuiIO& io = ImGui::GetIO(); // IO設定オブジェクトを取得、入力・フォント・グローバルスイッチを制御
ImGui::StyleColorsDark(); // 公式ダークテーマUIカラーを適用Code language: plaintext (plaintext)

GLFW+OpenGLバックエンド紐付け

ImGui_ImplGlfw_InitForOpenGL(window, true);Code language: plaintext (plaintext)

第2引数をtrueにするとImGuiがマウス・キーボード全入力イベントを専有し、入力がゲーム下位層へ透過しないよう遮断します。

 ImGui_ImplOpenGL3_Init(glsl_version);Code language: plaintext (plaintext)

OpenGL3レンダリングバックエンドを初期化。GLSLバージョン文字列を渡し、UI描画用頂点/フラグメントシェーダーのコンパイル、GPUバッファ作成を実行します。

float slider_value = 0.5f;    // スライダー連携数値
int click_count = 0;          // ボタンクリック回数カウンター
bool show_full_demo = false;  // ImGui公式デモウィンドウ表示フラグCode language: plaintext (plaintext)

上記変数は各ウィジェットの値を保持するためのもの。フレーム更新毎に読み書きされ、フレームをまたいで値が維持されます。

メインレンダリングループ

プログラムの中核処理、毎秒数十~百回程度繰り返し実行されます。

while (!glfwWindowShouldClose(window))Code language: plaintext (plaintext)

右上の×ボタンクリックやAlt+F4などウィンドウ終了シグナルが届くまで描画処理をループ実行します。

glfwPollEvents();Code language: plaintext (plaintext)

マウス操作、キー入力、ウィンドウリサイズ、終了イベントなどOSのウィンドウメッセージを一括取得します。

 ImGui_ImplOpenGL3_NewFrame();Code language: plaintext (plaintext)

OpenGLバックエンドのフレーム前処理。描画リソースをリセットし、次フレームの描画バッファを準備します。

ImGui_ImplGlfw_NewFrame();Code language: plaintext (plaintext)

GLFWバックエンドのフレーム前処理。現在のマウス座標、キー状態、ウィンドウサイズを読み取りImGui IOへ反映します。

ImGui::NewFrame();Code language: plaintext (plaintext)

新しいフレームのUIレイアウト計算を開始。すべてのImGui::xxx()ウィジェットコードより先に記述必須。内部で前フレームの描画命令を消去し、今フレームのUIデータ収集を準備します。

UIウィジェットデータ構築処理

// Draw custom UI panel
ImGui::Begin("Control Panel");                // カスタムコントロールパネルウィンドウを起動
ImGui::Text("Hello ImGui + VS2022");          // 静的テキスト出力
ImGui::SliderFloat("Slider Value", &slider_value, 0.f, 1.f); // 浮動小数点スライダー、数値変数と連携

if (ImGui::Button("Click to Count"))          // クリック用ボタン作成、押下時trueを返却
    click_count++;                            // ボタンクリックでカウンター加算
ImGui::SameLine();                            // 次のウィジェットを同一行に配置
ImGui::Text("Click Count: %d", click_count);  // ボタンクリック回数表示

ImGui::Checkbox("Show Full ImGui Demo Window", &show_full_demo); // チェックボックスでデモウィンドウ表示切替
ImGui::End();                                 // 現在のカスタムウィンドウ描画を終了

if (show_full_demo)
    ImGui::ShowDemoWindow(&show_full_demo);    // ImGui公式完全デモウィンドウを起動Code language: plaintext (plaintext)

このブロックはループ毎にUIを描画し、ボタンクリックを検知してカウントを増加、回数を画面に表示する処理です。

実際の描画出力処理

// Render ImGui draw data
ImGui::Render();                                        // 今フレームのUI頂点描画データを生成
int width, height;
glfwGetFramebufferSize(window, &width, &height);        // ウィンドウ実描画解像度を取得
glViewport(0, 0, width, height);                       // OpenGL描画ビューポートをウィンドウ全域に設定
glClearColor(0.12f, 0.12f, 0.12f, 1.f);                // ウィンドウクリア色を濃いグレーに指定
glClear(GL_COLOR_BUFFER_BIT);                           // 画面のカラーバッファを消去
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());// OpenGLでImGuiの全UIを描画

glfwSwapBuffers(window);                                // フロント/バックバッファを交換、描画結果を画面表示Code language: plaintext (plaintext)

終了後リソース解放処理

以下はユーザーがプログラムを終了した際、使用したリソースを全てクリーンアップするコードです。

// Cleanup resources
ImGui_ImplOpenGL3_Shutdown();  // OpenGLレンダリングバックエンドリソース(シェーダー・バッファ等)解放
ImGui_ImplGlfw_Shutdown();     // GLFWウィンドウ連携バックエンドリソース解放
ImGui::DestroyContext();       // ImGuiグローバルコンテキスト破棄、UI使用メモリ解放
glfwDestroyWindow(window);     // GLFWウィンドウを閉じ、ウィンドウハンドル破棄
glfwTerminate();               // GLFWライブラリを完全アンロード、グローバルウィンドウ/入力リソース解放
return 0;                      // プログラム正常終了、成功コード0を返却Code language: plaintext (plaintext)

リソース破棄順序は初期化と完全に逆にすることで、メモリリークやリソース残存を防ぎます。

以上で前回講座のサンプル解説は完了です。不明な点があれば下部コメント欄に質問してください。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です