DirectXTKに「Dear ImGui」を導入するお話
こんにちは。えあると申します。
今回はゲーム開発の効率化に最適な、強力なライブラリである「Dear ImGui」(以下ImGui)の導入についてお話していこうと思います。
「ImGui」とは
ImGuiとはDirectXやOpenGLなどの環境で利用可能な、GUIライブラリです。
扱い方もとても簡単で、短いコードでGUIを構築することができる、非常に強力なライブラリです。
下の画像は私の作品における使用例です。
まるでUnityのようなGUIですが、これらはImGuiによって作られています。
1. DirectXTK をセットアップする
まずは、DirectXTKのセットアップを行います。
今回の環境は以下のとおりです。
・OS : Windows 11
・IDE : Visual Studio 2022
1-1. DirectXTKのテンプレートプロジェクトをインストールする
上記GitHubのページ内にあるリンクより、.vsixファイルをダウンロードします。
1-2. テンプレートプロジェクトにDirectXTKをインストールする
テンプレートプロジェクトが正しくインストールできると、Visual Studio 2022のプロジェクト作成画面に、画像のようなテンプレートが追加されます。
今回は、DirectX11、Win32、DeviceResourcesを使用するため、「Direct3D Win32 Game DR」を選択し、プロジェクトを作成します。
この作成したプロジェクトに対して、DirectXTKをインストールします。
メニューバーより、「プロジェクト」→「NuGetパッケージの管理」を選択します。
「参照」を選択して、検索ボックスに「DirectXTK」と入力します。
検索結果の中から「directxtk_desktop_2019」を選択し、インストールします。
インストールの際に、ライセンスへの同意が求められます。「同意する」を選択してインストールを続行してください。
正常にインストールが完了すれば、実行することで、真っ青なウィンドウが表示されると思います。
これにてDirectXTKのセットアップが完了です。
2.ImGuiをセットアップする
続いて、ImGuiをプロジェクトに追加し、セットアップの準備を始めていきます。
2-1. ImGui をプロジェクトに追加する
GitHubのリポジトリをクローン、もしくはzipファイルでダウンロードします。zipファイルでダウンロードした場合は、解凍しておきます。
そして、プロジェクトのフォルダに新しいフォルダを作成し、その中に以下のファイルを追加します。
・ルートフォルダ内の.hファイルと.cppファイル
・backendsフォルダ内の「imgui_impl_dx11.h」「imgui_impl_dx11.cpp」「imgui_impl_win32.h」「imgui_impl_win32.cpp」
・MITライセンスの記載されたLICENSE.txt(念の為入れていますが、入れなくても動作はします)
その後、Visual Studioに追加します。
この時点でビルドしようとすると、プリコンパイル済みヘッダーによるエラーが発生します。
これを解消するため、追加した.cppファイルのプロパティより、「C/C++」→「プリコンパイル済みヘッダー」→「プリコンパイル済みヘッダーを使用しない」に変更します。
ShiftやCtrlを使用して一度に選択することで、同時に設定を変更することもできます。
設定が完了したら、ビルドを実行します。
正常にビルドできれば、プロジェクトへの追加が完了です。
2-2. 必要なコードを記述する
続いてアプリケーションにImGuiを組み込んでいきます。
まずは「Game.cpp」を開き、以下のヘッダーファイルをインクルードします。
(ImGuiのフォルダーへのパスは、「追加のインクルードディレクトリ」の設定を変更し、省略しています)
#include "imgui.h"
#include "imgui_impl_win32.h"
#include "imgui_impl_dx11.h"
その後、約28行目の「Initialize関数」内の一番下に、以下の初期化処理を記述します。
// ImGuiの初期化処理
{
// バージョンの確認
IMGUI_CHECKVERSION();
// コンテキストの作成
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO();
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // キーボードによるナビゲーションの有効化
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // コントローラーによるナビゲーションの有効化
// Win32用の初期化
ImGui_ImplWin32_Init(window);
// DirectX11用の初期化
ID3D11Device* device = m_deviceResources->GetD3DDevice();
ID3D11DeviceContext* context = m_deviceResources->GetD3DDeviceContext();
ImGui_ImplDX11_Init(device, context);
}
続いて、約67行目の「Tick関数」内の一番上に、以下の更新処理を記述します。
// 新フレームの開始(メインループの一番上に記述)
ImGui_ImplDX11_NewFrame();
ImGui_ImplWin32_NewFrame();
ImGui::NewFrame();
// デモウィンドウの描画
ImGui::ShowDemoWindow();
さらに、約98行目の「Render関数」内、「Present関数」の上に以下の描画処理を記述します。
// ImGuiの描画処理
ImGui::Render();
ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
続いてGameクラスのデストラクタを作成し、終了処理を記述します。
注意としてGameクラスのデストラクタは、default指定されているため、ヘッダに記述されたdefaultを削除し、cppにデストラクタを実装する必要があります。
Game::~Game()
{
ImGui_ImplDX11_Shutdown();
ImGui_ImplWin32_Shutdown();
ImGui::DestroyContext();
}
そして、「Main.cpp」に以下のインクルードを追加します。
#include "imgui_impl_win32.h"
最後に約116行目の「WndProc関数」内の一番上に以下の処理を記述します。
// ImGuiのメッセージ処理
extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
if (ImGui_ImplWin32_WndProcHandler(hWnd, message, wParam, lParam))
return true;
以上をすべて入力したら、実行します。
正常にセットアップできていれば、以下のようなデモウィンドウが表示されると思います。
このデモウィンドウでは、ImGuiの基本的な機能を一通り触ることができますので、ぜひいろいろ試してみてください。
以上でセットアップは完了です。
2-3. ImGuiでHello, worldしてみる
続いて、オリジナルのウィンドウを表示してみようと思います。
「Game.cpp」を開き、「Update関数」内に以下の処理を記述します。
// 新しいウィンドウの作成
ImGui::Begin("TestWindow");
{
// テキストの表示
ImGui::Text("Hello, world!!");
}
ImGui::End();
そして実行すると、画像のようなウィンドウが表示されます。
このように、「ImGui::Begin(…)」から「ImGui::End()」で囲った中にウィンドウの処理を書くことで、任意のウィンドウを作ることができます。
他にも、ボタンは以下のように実装することができます。
if (ImGui::Button("TestButton"))
{
// ボタンを押されたときの処理
}
またチェックボックスは以下のように実装できます。
ImGui::Checkbox("TestToggle", &m_toggle);
if (m_toggle)
{
// チェックがついているときの処理
}
実際に実装してみると以下のような感じです。
このようなシンプルな記述で、ウィンドウを作り、操作することができるという、本当に強力なライブラリーだと思います。
まとめ
ここまで「Dear ImGui」のセットアップについて紹介してきました。
とにかくシンプルなコードで、GUIを表示する事ができる、とても強力なライブラリーです。
ステージエディターなどのツール制作はもちろん、FPSや座標の表示といったデバッグ用の機能としても活用する事ができます。
ぜひImGuiを使用して、効率的なゲーム開発をしてください。
おまけ
ImGuiのリポジトリには「docking」というブランチが存在します。
このブランチのソースを使ってセットアップすることで、複数のウィンドウを一つに固める「ドッキング機能」を使うことができます。
私も普段からこちらを使用しています。
注意として初期化時に以下のフラグを追加する必要があります。
// コンテキストの作成
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO();
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // キーボードによるナビゲーションの有効化
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // コントローラーによるナビゲーションの有効化
// ※追加
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // ドッキングを有効化
これによって以下のgifのようにウィンドウをくっつけたり、複数のタブで使用することができます。
こちらのほうが便利ですが、今後変更したい箇所が多いためmainにマージされていないとのことです。今後、急に変更になる可能性もありますが、この機能はかなり便利なので積極的に使用したいところです。