Search Unity

[In Development] NImGui, a 1 Draw Call Immediate Mode GUI for Unity

Discussion in 'Assets and Asset Store' started by psuong, Sep 18, 2021.

  1. psuong


    Jun 11, 2014
    NImGui stands for Nimble Immediate Mode General User Interface and is designed to be a replacement library to Unity's runtime ImGui.

    I have always found Unity’s runtime ImGui solution to be lackluster and displaying any kind of widgets on runtime is just too annoying to get it setup easily. Similarly, with Unity’s UGUI solution, there’s too much set up required in order to display some information or set up widgets to tweak values in your game. While Debug.Log is extremely useful, when debugging many pieces of information it can be difficult to search through and contextualize information.

    This framework was designed with performance and simplicity in mind, so you can focus on drawing widgets to interact/display/debug information while developing your game.

    • Supports builtin render pipeline and URP
      • Built for Windows, Mac, Linux, & WebGL
    • Simple immediate static API to draw widgets
      • Draw Scopes via using pattern to begin and end areas (see the API Example below!)
      • Write GUI naturally in MonoBehaviour.Update() and DOTS’ SystemBase.OnUpdate()
    • High performance
      • Utilizes C# Job System & Burst Compiler
    • A library of built widgets
      • Box
      • Button
      • Collapsible Area
      • Dropdown Menu
      • Label
      • Line
      • Pane
      • Progress Bar
      • Toggle Button
      • Scroll Area
      • Slider (float & int)
    • Static APIs cannot be called from separate threads simultaneously
    • Static APIs cannot be called from LateUpdate as this will throw a warning in the rendered UI
    • Static APIs can be called from FixedUpdate but will only appear for a frame as UI gets updated every frame and FixedUpdate does not
    • Does not support the new InputSystem yet

    NImGui can process 250 widgets in 1 millisecond on the main thread in the Editor. On a build, you can expect it to take 0.4 millisecond instead. This is achieved via multithreading using Unity’s Job System and Burst Compiler.

    These stats were recorded on an Intel Core i7-7700HQ @ 2.8 GHz. More stats will be collected across varying hardware and operating systems.

    Versions Supported
    • Unity 2020.3 LTS
    • Unity 2021.1
    • Unity 2021.2 beta
    • Unity Collections
    • Unity Jobs
    • TextMeshPro
    API Style

    The API follows an immediate mode style. Here is an example of the API you would be writing:

    Code (csharp):
    2. using (ImPane pane = new ImPane("Sample Pane", new float2(500), new float2(500))) {
    3.    if (pane.IsVisible) {
    4.        var t = Mathf.PingPong(Time.time * 0.5f, 1f);
    5.        ImGui.Label("Here's an example of drawing panes and widgets");
    6.        ImGui.ProgressBar(t);
    7.        ImGui.Dropdown("Dropdown", options);
    9.        if (ImGui.Button("Click me to toggle")) {
    10.            showMsg = !showMsg;
    11.        }
    13.        if (showMsg) {
    14.            ImGui.Label("Message shown!");
    15.        }
    17.        ImGui.Slider("Int Slider", 0, 10);
    19.        using (new ImScrollArea("Scroll Area")) {
    20.            using (ImCollapsibleArea group = new ImCollapsibleArea("Group")) {
    21.                if (group.IsVisible) {
    22.                    if (ImGui.Toggle("Show Box")) {
    23.                        ImGui.Box(300,, true);
    24.                    }
    25.                }
    26.            }
    27.        }
    28.    }
    29. }
    This would produce an output like so:


    The demo can be tested at the following link on

    Immediate Roadmap

    The first version of NImGui is expected to be released at the end of 2021/early 2022 as there are few things that I need to finish such as:
    • escape characters support in the Label API (for new line and tabs)
    • Textfield API
    • Support Unity’s new Input System
    • a browsable API / docs website
    • LateUpdate support for drawing widgets
    • One draw call UI (right now each widget drawn will issue between 1 to a few draw calls)
      • This may also allow me to shift away from using TextMeshPro materials as it is a current dependency
    Longer Term Goals
    • RTL language support
    • Complex text layout support (e.g. support for Arabic, Khmer, Thai, etc)
    • Command Buffer like API for dynamic widgets and panes & multithreading support
    • Stateful FixedUpdate support (e.g if you need to debug netcode which will run on a Fixed Timestep, it will make sense to store and display the information until the next Fixed Timestep)
    Initial feedback and questions are welcomed! Feel free to comment in this thread below.
    Last edited: Oct 2, 2021
  2. psuong


    Jun 11, 2014
    Thought I'd post a new update since it's been two weeks since the last time I made this post (I can't guarantee that I'll be posting an update every 2 weeks but I'll try).

    I decided to remove my dependency on TextMeshPro. TextMeshPro is great but there were some problems I ran into:
    • TextMeshPro materials had to be dilated in order to remove jaggedness (there's some setting that I haven't figured out and going through TextMeshPro source code is a pain).
    • TextMeshPro did not generate glyphs for certain characters despite the Font actually supporting the character
      • This made it almost impossible for me to aim for a 1 draw call UI.
    So what replaces TextMeshPro?

    NimGui has its own SDF Font Texture generator and is based off of the AntiAliased Euclidean Distance formula by Stefan Gustavson: (MIT license will be included in the source file where it's used).

    See the sdf_texture.jpg attachment below for an example.

    With the underlining font rendering system replaced, what are the limitations that come with it?
    • Unfortunately, this means that you cannot load new fonts and render multiple fonts. You can only have 1 font loaded in at a time as the shader is extremely simple and only takes in a single texture.
    • The SDF texture generated by NimGui takes up more space than TextMeshPro. There is no texture packer to make the texture more compressed.
    • Loading in custom images will no longer be supported.
    However, despite these downsides, I am now able to render everything in 1 draw call, which reduces the complexity in building the mesh as well the command buffer that will render the content.

    1 Draw Call UI

    However, with these changes, I cannot take advantage of hardware scissoring so scroll views will need to be reworked such that content is interpolated and clipped if it is out of bounds. This will be my immediate step after finishing converting widgets such as Sliders.

    Attached Files:

    Last edited: Oct 2, 2021
  3. psuong


    Jun 11, 2014
    Hey all, another update!

    With the change to a 1 draw call UI, hardware scissoring was no longer supported. This meant that I had to write my own "software" scissor technique which allowed me to cull content that is out of view (which is very useful for scroll areas).

    Right now the implementation is based off interpolating UVs to the correct value when vertices are culled out of view. This ensures that glyphs that are rendered are not compressed in a limited space which would cause each glyph to look distorted.

    For performance stats, I'll need to optimize software based scissoring, right now for 6k vertices, software scissoring takes 0.5ms on a Core i3-8100 @3.6GHz. Without software scissoring, the job takes 0.15ms to run, so we can see that software scissoring makes the job run 3x longer.

    As for next steps, I'll continue and move onto implementing Textfield.
    Last edited: Oct 11, 2021 at 2:37 PM
    exiguous likes this.