[Released] NimGui, a 1 Draw Call Immediate Mode GUI for Unity

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.

Asset Store Link
Grab it on the Asset Store.

Features

  • 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)

Limitations

  • 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

Performance

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

Dependencies

  • Unity Collections
  • Unity Jobs

API Style

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

using (ImPane pane = new ImPane("Sample Pane", new float2(500), new float2(500))) {
   if (pane.IsVisible) {
       var t = Mathf.PingPong(Time.time * 0.5f, 1f);
       ImGui.Label("Here's an example of drawing panes and widgets");
       ImGui.ProgressBar(t);
       ImGui.Dropdown("Dropdown", options);

       if (ImGui.Button("Click me to toggle")) {
           showMsg = !showMsg;
       }

       if (showMsg) {
           ImGui.Label("Message shown!");
       }

       ImGui.Slider("Int Slider", 0, 10);

       using (new ImScrollArea("Scroll Area")) {
           using (ImCollapsibleArea group = new ImCollapsibleArea("Group")) {
               if (group.IsVisible) {
                   if (ImGui.Toggle("Show Box")) {
                       ImGui.Box(300, Color.red, true);
                   }
               }
           }
       }
   }
}

This would produce an output like so:
personalsatisfiedcutworm

Demo

The demo can be tested at the following link on itch.io:
__**https://initialprefabs.itch.io/nimgui**__

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)

Documentation

Initial feedback and questions are welcomed! Feel free to comment in this thread below.

7 Likes

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: https://weber.itn.liu.se/~stegu/edtaa/ (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

https://vimeo.com/620826371

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.

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.

liquidpersonalcub

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.

1 Like

Hey all,

Here are some updates with ImGui. First and foremost:

Optimization
For 6k vertices, software scissoring originally took 0.5ms to run. Without software scissoring, the job originally takes 0.15ms to run. This is pretty much a 3x performance lost. To improve the performance, after some optimizations on the Bursted Job, it now takes approximately 0.35ms to perform software scissoring on all vertices.

Some further optimizations I can do include:

  • Only scissor vertices when scissor rects are introduced
  • Use an approximation of the sqrt to produce fewer assembly instructions when interpolating

If software scissoring is not an option, I’ll consider offloading it the GPU, however I would like to keep the SDF shader extremely simple.

Textfield
The Textfield API is pretty much functional with western based languages. RTL and complex text layout is not supported yet and is on my todo list in the near future.

You can input text via keyboard and press or hold backspace to delete text. See the gif below:

dangeroustalkativeeastsiberianlaika

Next Steps
The Textfield API needs some cleanup and additional features such that you can move the cursor and insert characters in the middle of the textfield and be able to highlight. I’ll also explore complex text layout such that I can plan for additional changes to the logic / API.

After that the base API is pretty much done, so I’ll be updating the documentation and demo.

4 Likes

New updates from the recent week.

TextField API

TextFields are primarily done and backspace detection is done using Unity’s **Input.inputString**. (Instead of using Input.GeyKey(KeyCode.Backspace) variants, I check for a **\b** to see if the user has pressed backspace.) To help GC load with string generation, I’m considering that instead of returning a string type, the TextField will write to an allocated StringBuilder. This will have a lighter load to C#'s garbage collector.

Project Cleanup

TextMeshPro is finally removed from the library! This means NimGui officially uses its own SDF texture generation & SDF shader. The SDF shader is kept as simple as possible therefore it does not implement all features presently found in TextMeshPro.

Documentation

Documentation is updated to reflect an additional step in the installation process. This involves opening the Setup Wizard and clicking the Add Shader button, which will add the SDF shader to your graphics settings’ Always Included Shaders.

The Setup Wizard attached below, although extremely simple for now, will also include a hyperlink to the documentation.

Next Steps

  • Switch TextField to take in StringBuilder that the developer allocates themselves to lighten the GC Load
  • Update the Setup wizard to include a link to the documentation
  • Allow the Setup wizard to appear on project open & provide users with a way to disable the auto popup after start.
  • Update documentation on workflow when introducing new fonts & the limitations that it has.
  • Begin researching into complex text layout

7615861--946528--setup-wizard.jpg

1 Like

Hi all another update.

I’ve been busy doing some clean up to the amount of padding widgets have and migrating the documentation from originally, mdbook to DocFX because generating the XML API documentation to work with mdbook wasn’t a good idea.

The link to where the documentation currently lives here.

Inline code documents will be picked up in your IDE of choice, although inline code examples vary in how they are rendered per IDE. (Please see the attached image below.)

The screenshot above is based on the following snippet

/// <summary>
/// Returns the current state of the Toggle box. If the box is checked, then
/// the state is true, otherwise returns false.
/// <remarks>
/// The control ID is useful for pruning cached global states. You only need to
/// prune when you are no longer using the Toggle functionality.
/// </remarks>
/// <code>
/// class UIBehaviour {
///     uint toggleID;
///     // Gets called once per frame.
///     void Update() {
///         if (ImGui.Toggle(out toggleID)) {
///             ...
///         }
///     }
///
///     ~UIBehaviour() {
///         // Internally this will remove the cached Toggle state from
///         // it's internal hashmap, when this Object is destroyed.
///         ImGui.PruneToggle(toggleID);
///     }
/// }
/// </code>
/// </summary>

Next Steps

Over the next few weeks, I will be continuing updating the documentation by swapping some still images with gifs (as I think gifs will get the purpose across better with interactive widgets), updating docStrings with code examples, and cleaning out the API.

I’ll also need to start prepping for asset store and itch.io release.

1 Like

Hi all,

It’s been roughly 3 weeks since I’ve last posted and there are a few updates I can provide:

WebGL Issue
I have disabled WebGL builds at itch.io temporarily until I can solve the the performance degradation on WebGL. Before making NimGui 1 draw call I have been exclusively using bursted IJob.Run() to build the UI. I may have to write preprocessor defines to make sure that WebGL exclusively uses IJob.Run() instead of IJob.Schedule().

I have provided demo builds for Windows, Linux (Ubuntu 20.04), macOS (Intel only) on the itch.io page. Please feel free to download them and test out the UI. Initial feedback is welcomed!

Itch Link: NimGui, A 1 draw call UI by initialPrefabs

TextField
I forgot to add text slicing on textfields so I will need to address that and add it in before finally pushing it to the asset store. This means that you can continuously type and the text will wrap to the next line, which is not desired behavior.

Overall, I think I can say I’m 85% done with the first major release of NimGui. Documentation is updated and currently reflects the most up to date information on how widgets are used.

Documentation: Home

Hi all,

Another week, another update. :slight_smile:

Textfield Fixes
Textfields properly slice off characters that are off screen. This means as you keep typing many characters, the textfield will not show the characters at the beginning of the field.

terriblecloudyfirefly

Documentation

  • Documentation for Textfield has been updated to define limitations.
  • Broken links within the documentation site has been fixed.
  • Added information about pruning and cleaning up internal cached IDs.

Documentation Link

1 Like

Apologies for the month long silence. Post 2021 end of year break had me pretty busy and I didn’t have enough time to wrap up the documentation and finishing up the asset store release.

Some minor things I had done since the past month is migrate the current documentation over to a new site, nimgui.initialprefabs.com. I’ll need to grab statistics and create a more public facing demo hosted on Github (which will involve me using BoatAttack to demo what NimGui can be used for). This won’t be embedded in the unity package as the package will just have a NimGui widget gallery showing all the available widgets currently supported.

7811406--987924--gallery.png

2 Likes

Apologies for the lack of updates, I’ve been pretty busy with work so I haven’t had the time to update NimGui outside of a few minor bug fixes.

Hey all,

Here are some updates to NimGui which have been put off during my 2 month hiatus. First, the collapse and close buttons are clickable relative to the order of the pane being rendered. In the video below, if the Stats pane is rendered on top, then the collapse and close buttons are clickable, instead of the Widgets Gallery window.

https://vimeo.com/687632477

Input System
NimGui now supports Unity’s Input System. If your project uses Input System as its backend, then NimGui will strictly use it for all inputs. If you use the old Input Manager, then NimGui uses the Input Manager and polls the inputs each frame. If you happen to use both, then the Input Manager will be the default input backend.

Post Processing
Any post processing that will cause a Final Blit Post Processing pass in SRP will ultimately affect NimGui. Using the BoatAttack demo as a baseline when creating a demo made this painfully obvious. One possible solution is for me to create a derivative of URP that is backwards compatible and introduce a new RenderPass + Subpass that composites NimGui as the final image. I had asked around the forums to see if this was possible but I haven’t gotten much of a response so I will try to solve this issue sometime in the future.

Ultimately, introducing a new RenderPass/SubPass would allow me to separate NimGui’s rendering from the main render loop, similar to how UI Toolkit and UGUI are rendered.

That said, I will look into hosting binaries on Github which will provide a demo of the Widget gallery instead of integrating NimGui into BoatAttack.

Documentation
Documentation for the Input System can be found in the Installation section, which details the same info above.

Next Steps
With these minor fixes, I will be moving onto grabbing screenshots and filling out the Asset store info. The same info will be submitted to itch io also. Once that is done - I’ll make a forum post on when it’s submitted.

Happy deving and thanks for the patience.

4 Likes

With Entities 0.50 released on the package manager, I’ll be on the look out for the other dependency updates and see how it affects NimGui in the coming weeks.

1 Like

NimGui is compatible with Entities 0.50. Although the static API works nicely with SystemBase’s OnUpdate, if you’re looking for Bursted System support, that won’t come until the future. There are still managed object that need to be accessed with NimGui, but I can look into a fully Bursted API if there is enough need for that (the priority right now is just really low).

WebGL

Some additional updates I’d like to point out is: WebGL build will also work, however to achieve a higher frame rate you must validate your memory allocation settings in your player settings. Current settings I am using in the screenshot below are:

  • Initial Memory Size: 32
  • Memory Growth Mode: Linear
  • Maximum Memory Size: 2048
  • Linear Memory Growth Step: 16

Your mileage may vary, however these are the settings that I found worked as the problem I had to debug was more of a memory allocation problem more so than a runtime performance operation.

More Fixes
Some more fixes that will be in the initial release of NimGui are:

  • Added a Linear to Gamma color conversion as NimGui was built with Gamma Color Space initially. This will prevent a washed out color if you happen to use Linear color space. NimGui will automatically convert the color space depending on the QualitySettings.activeColorSpace. See the screenshot below.
    7991853--1026957--colorspace-comparison.jpg

  • Dropdown menus will respect that it is overlapping an element so that interactable widgets behind the menu will not be interacted with. (Similar to the collapse/close bug).
    7991853--1026960--dropdown-fixed.jpg

Thanks for the patience everyone!

Everything has been submitted to the Asset Store! The NimGui Itch page is live, however once the Asset store listing goes live, I will list the Itch version also.

2 Likes

Hi all!

NimGui has been approved and released to the Asset Store and Itch! Thanks so much for your patience, I’ll be continuing to support NimGui for a while as it is my active daily GUI I’m using as I build things out in Unity Entities, so I’ll be fielding for feedback.

I’ll have some external demos in the coming weeks of other integrations I will be doing with Entities and NimGui that I’ve been slowly working on in the background.

2 Likes

Hey all,

Immediate Steps

I’ve got some early feedback in making the setup for NimGui much easier which I’ve posted an issue here:


While the setup and installation process is all documented here it’s worth making the setup extremely obvious per supported render pipeline.

This will be an editor only check to not affect a built game’s runtime.

Next Major Steps

The next major feature I would like to work on is world to screen space drawing so you can reference a point in world space but draw it within the screen. This would be great for widgets such as the Label and Progress Bar (think of a health bar or displaying some some values next to a character or object. As always I’ll try to post screenshots of update to this thread.

If you have any requests for this feature let me know, so I can consider it and figure out how to architecture it.

1 Like

Hey all,

NimGui 1.0.1 is released which provides a 1 click setup for all of your URP RenderPipeline Assets. You will still need to add URP_ENABLED to your scripting define.

For an example of the 1 click setup please see the video below.

https://vimeo.com/697703732

Documentation has also been updated and can be viewed online here or in the PDF when downloading the package. For visbility, the issue can be viewed here: https://github.com/InitialPrefabs/nimgui/issues/2

I am currently working on issue 3 & 4 which is due to some initialization issues with Domain Reload & how Unity initializes the InputSystem.

With DOTS 0.51 out - I’ll be updating NimGui to support it. :slight_smile:

4 Likes

Changes to NimGui to support Collections 1.3.1 and 2021.3 LTS have been submitted for review to the Asset store. :slight_smile: