imgui でこんなのを実現したいときはどうしたらいいかしらん... のメモです.
対象 ImGui version
1.71(or 1.72 WIP)
Docking window にしたい.
ImGui はデフォルトではフリーレイアウトです.
docking
branch でドッキング対応が作業中です. 使っている感じではほぼ問題なく動いています.
ImGuiConfigFlags_DockingEnable
を指定すると自動でドッキングが有効になります.
ImGui::CreateContext();
auto& io = ImGui::GetIO();
// Enable docking(available in imgui `docking` branch at the moment)
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
など外部の docking 対応機能も試しましたが, 不都合が多いでした(ので, ImGui docking
branch がおすすめです)
ノードエディタがほしい
C++14 になりますが, imgui-node-editor
がいい感じです.
3D ギズモがほしい
Maya とか Blender とかで, translate/rotate/scale で出てくるマニピュレータです.
ImGuizmo でいけます.
カラーピッカーのカラースペースは?
現状 ImGui は degamma/ガンマ補正などは考慮していないようです.
レンダラ用の UI を作る場合. sRGB/Linear 対応などを自前対応が必要になります.
文字に背景色を指定したい
直接背景色を指定する API はありません.
AddRectFilled() などで一旦矩形を描画したのち, 文字を描画します.
ImVec2 bmin = //テキストの描画位置. ImGui::GetCursorScreenPos() などで取得
ImVec2 text_size = ImGui::CalcTextSize(buf);
ImVec2 fill_bmin = ImVec2(bmin.x - 4, bmin.y - 4);
ImVec2 fill_bmax =
ImVec2(bmin.x + text_size.x + 4, bmin.y + text_size.y + 4);
// Draw quad for background color
ImGui::GetWindowDrawList()->AddRectFilled(
fill_bmin, fill_bmax,
ImGui::GetColorU32(ImVec4(0.2f, 0.2f, 0.2f, 0.4f * alpha)),
/* rounding */ 4.0f);
ImGui::SetCursorScreenPos(bmin);
ImGui::TextColored(ImVec4(0.8f, 0.8f, 0.8f, alpha), "%s", buf);
フォントをソースコードに埋め込みたい
.ttf
ファイルを読み込んでだと, ファイルの探索に失敗したりとかで管理が面倒なのでバイナリに埋め込みたい.
こちらでフォントデータを unsigned int の配列にしてくれます. 圧縮/非圧縮選べます.
io.Fonts->AddFontFromMemoryCompressedTTF(roboto_mono_compressed_data,
roboto_mono_compressed_size,
default_font_scale, &roboto_config);
などとしてメモリからフォントデータを読み込みます.
形状を描画したい.
Sphere, line, etc.. など.
DrawList を取得して, AddRect()
などを呼びます.
より複雑な形状を描画したり, antialiased line が欲しければ NanoVG あたりを使うのがよいかもれません.
大量のオブジェクトを描画したい
Imgui ではデフォルトでは頂点インデックスは 16bit のため, 大量にオブジェクトを描画するとインデックスが足りない assert が出たりします.
@syoyo Hello! About "大量のオブジェクトを描画したい" in https://t.co/AM5OOwvkcR, since 1.71 most default back-ends support ImDrawCmd::VtxOffset which allow larger single-window contents with 16-bit indices, see: https://t.co/55za53P06x
— Omar (@ocornut) July 16, 2019
Omar 先生からアドバイスいただきました. ありがとうございます.
1.71 から実装された VtxOffset feature を使うと 16bit index でも大量プリミティブを描画できるようになります. example の GL3 backend では VtxOffset 機能がデフォルトで有効になっています(glDrawElementsBaseVertex()
を使っている)
OpenGL 2.x や, GLES では, glDrawElementsBaseVertex
相当を CPU 実装することで対応できるでしょう.
他に, imconfig.h でインデックスを 32bit にしたり, 自前描画や NanoVG を使うのも考えてみましょう.
画像を表示したい
ImGui::Image
でいけます.
OpenGL で描画する場合, たとえば 8K 画像を一旦 GL テクスチャにするところでかなり時間がかかったりします(e.g. ドライバ内部とか).
サムネイル表示ができればよいのであれば, 一度画像を縮小してからテクスチャを作るのがよいです.
画像だけスクロールさせたい
画像が大きかったり, 拡大表示したいので Window に入りきらない.
デフォルトでは Window 全体にスクロールバーがつくので, 他の text や button などもスクロールしてしまう.
Window に画像(Image)をいれ, Image だけスクロールバーをつけたい.
=> ChildWindow
でとりあえずできはしますが, macOS だと拡大が大きくなるとおかしくなるのを観測しました. 安定を求めるのであれば, 現状は画像ごとに Window を作るしかなさそうです.
InputFloat などで, リターン打ったときのみアップデートしたい.
デフォルトでは数値を入力するたびに return true(update)になります.
たとえばカメラ位置などを扱っているばあい,
1.0
->
0
->
0.5
みたいに値を削って 0.5 にしたいときに 0.0 の状態でもアップデート要求がでて, レンダーし直しになって面倒です.
InputTextFlags で
ImGuiInputTextFlags_EnterReturnsTrue
を指定することで, リターンを打ったときのみ true が帰るようにできます.
ただ, decimal precision も指定する必要がでてきますので注意です.
オシャンティな progress 表示したい
Table で Cell に値を入力したい
Table 自体は Canvas なため, text や button など埋め込むことができます.
したがって InputFloat など埋め込めば値入力が可能になります.
値を入力できるようにするには以下のような感じにします.
InputFloat の Label 文字列が同じだとおかしくなってしまうので, PushID/PopID で一意になるようします.
(もしくは, 一意になるような文字列を割り当てるかでしょうか)
##
をつけると非表示のラベルになります.
if (ImGui::BeginTable("table1", 3))
{
for (int row = 0; row < 4; row++)
{
ImGui::TableNextRow();
for (int column = 0; column < 3; column++)
{
ImGui::TableSetColumnIndex(column);
//ImGui::Text("Row %d Column %d", row, column);
ImGui::PushID(row * 3 + column);
ImGui::InputFloat("##v", &values[row][column]);
ImGui::PopID();
}
}
ImGui::EndTable();
}
Voila!
(TODO: InputFloat の background color を消す)
グラフのプロットをしたい
implot があります!
3D グラフはでも無いので, 自前で頑張るしかないかも.
その他 UI component 集(awesome list)
でいろいろ見つかります