📝

Unityのための新RuntimeIMGUIの提案

2023/03/28に公開

個人で開発中のZimGuiというものの紹介。
正直飽きてしまいましたが、絶対需要があるので、誰かに作って欲しいので、未完成でも公開して解説記事を作ることにしました。
レポジトリ
先に例を出します。

例(Gif)

基本的使い方

this.MethodButton(nameof(DoSomething)); 
IM.BoolField("boolValue", ref boolValue);
this.ViewField("SomeField");
if (IM.Vector3Field("Scale",transform.localScale, out var  scale)) {
    Target.localScale = scale;
}

概要

ZimGuiはZero allocation Immediate Mode GUI の略です。この名前は同じくアロケーションを抑えるライブラリであるZStringを参考にしました。
毎フレーム描画をし直すが、だからこそアロケーションはしないようにしたライブラリです。

背景

UnityにはuGUIの前からIMGUIというものがあり、Immediate Mode GUIの略です。RuntimeにもEditorにも使える便利なGUIで、コードのみで完結し単純なUIに向いています。UIToolkitが出て久しいですがEditorではまだしばらく使われていくでしょう。そして私はDebug用にGame内でInspectorのようなものを作りたいと考えました。しかし大きな問題があります。
毎要素GC Allocし、Pass Callするためパフォーマンスが悪い。Span対応がないという点です。
UnityではC++とのやり取りでSpan対応(特に文字列)が全くと言っていいほどされていません。
これでは使い物になりません。ということで、自作することにしました。基本的な書き方はIMGUIとあまり変わりません。

描画方法

使っているUnityの機能はTextMeshPro、AdvancedMeshApiです。
TextMeshProのSDFテクスチャを独自のMaterialのTextureに設定し、Glyphデータ(文字の配置の仕方とuv座標)を用いて、各要素の頂点データを計算し、フレームの最後にAdvancedMeshApiでメッシュを作り、Graphics.DrawMeshするという流れです。なので、メッシュは1つのみ、PassCall も基本的1回です。
長方形や円は●を使っています。

Zero allocationの実現方法

これは意外と簡単で、文字列の場合はReadOnlySpan<char>を受け取る、数値の場合は2021から使えるTryFormatメソッドを用いて内部バッファに書き込んでいます。ZStringと同じですね。

さいごに

まだまだ未完成ですし、この記事自体も(入力システムなど)加筆しないといけないですが、基本的なところは単純です。
Debug用に頻繁に更新されるGUIを作る場合、現状これだと言えるライブラリを他に知りません。初めて最新のUnity/C#の技術を使ったIMGUI実装だと思うので、これを参考にしたライブラリが出てくるといいですね。

Discussion