[Source Code] DotsUI - open source UI framework for DOTS

This is the first release of the DOTS UI system ([Showcase] Pure DOTS UI system (detailed description + feedback) - Unity Engine - Unity Discussions). The source code is released under MIT license, so you can do anything you want with it. It’s still very early development stage so don’t be disappointed with lack of features and bugs. Remember, it started as a learning project and some parts of code are very ugly (strange class names, etc.).

Link to the repository:
https://github.com/supron54321/DotsUI

I’d really like work full time on this project, but right now I can spend only 1-2 hours per day. That’s why it took almost 2 months to publish this project, after my first post. I have rewritten the core from scratch a few times. Now I really like current design. It’s fast, multithreaded and can be easily extended with new primitives and high-level controls.
There is still A LOT of work to do before it will be production-ready. Check list of known issues and roadmap.

Because of bugs in ConvertToEntity, the system is completely detached from this workflow and uses its own converters. In this version, the only “easy” way to work on UI is to convert Canvas hierarchy and prefabs through classes in DotsUI.Hybrid namespace. There is no high-level API for spawning pure UI Entities. I strongly recommend to convert unity prefabs to DotsUIPrefab and instantiate them form systems. Breaking changes in the core are pushed in almost every commit.

Canvas render-mode must be set to “Screen-space camera”. Conversion pipeline automatically adds a component to the camera (OnRenderImage hook).

Design

DotsUI is trying to convert UnityEngine.UI hierarchy to pure DOTS representation. Due to performance reasons, I removed rotation from RectTransform component. Scale will be implemented in future releases. The whole system is designed to achieve the best possible performance, but there is still room to make improvements (remove sync points, more jobs, and better data layout).

Samples

Documentation is not ready yet. You can check “PrefabExample” to learn how to create and instantiate DotsUI prefabs:

Contribution

Right now I’m looking for the feedback. Share your thoughts about the idea of open source UI system. Once I finish the core, we can start with pull requests from the community.

21 Likes

I think you should consider using the built-in conversion system. One thing I discovered relatively recently is that if Entities.ForEach doesn’t let you do what you want to do, you can usually get around it by making an EntityQuery of the types you want and then getting the array of Entities from that. It’s not as fast, but it might let you temporarily get around the RectTransform issue until the next Entities release.

I do weekend game jams to build and battle-test my custom tech stack built on top of DOTS. If you can get this UI working with Unity’s GameObject Conversion, I’d be more than happy to give you some battle-tested feedback!

I will once issues with RectTransform are resolved. I implemented my own converters only because I needed anything to test UnityEngine.UI → DOTS conversion.

Still a lot of work to do, before its “battle-ready” :smile:

I want to thank you for your awesome work. It’s definitely something that I will be using in my future games.

Great job. Will have a look at it as soon as I’ll be on a computer.
I’m mostly looking for UI Text but by looking at the GitHub repo it doesn’t seem to be available yet.

Anyway thanks for this.

Text is supported through text mesh pro component and fonts. Currently, “master” branch supports conversions from the following UI components:

  • Image
  • TextMeshProUGUI (SDF fonts, not all features are supported)
  • TMP_InputField (very simple implementation)
  • Selectable
  • Button
  • RectMask2D
  • CanvasScaler

On develop branch I’m working on ScrollRect implementation.

Unfortunately, ConvertToEntity is still not implemented. I encountered a critical bug in the conversion pipeline. I hope Unity devs can fix it soon. Right now the only way to convert Canvas hierarchy is to call RectTransformConversionUtils.ConvertCanvasHierarchy(Canvas, EntityManager).

DotsUI works with unity 2019.3.0a8+. Hybrid UI renderer requires new Mesh API from 2019.3 (it’s 2-3x faster).

2 Likes

@supron what kind of events does your UI support? (PointerDown, PointerUp, PointerClick, etc)

  • Down
  • Up
  • Click,
  • Enter
  • Exit
  • Selected
  • Deselected

On develop branch I added support for:

  • BeginDrag
  • Drag
  • EndDrag
  • Drop

I’ll merge branches by the end of this week.

Few words about low-level events (raw pointer and keyboard events). I considered different approaches for event handling. In early DotsUI development, I implemented events as components added to the target entity. That wasn’t a bad idea, but it had few drawbacks. The first problem: it required entity data relocation and archetype change. Not bad if you have rare events like click or selection. Worse if you have a lot of frequently updated events (OnDrag, OnEnter+OnExit). The second problem: it required event queue cleanup at the end of the frame (another relocation). In the current DotsUI version, I implemented events as separated entities. Event entity archetype is very simple. It has PointerEvent component (with target entity) and PointerInputBuffer (dynamic buffer with eventID, eventType and eventData). This approach requires additional filtering job before per-target event handling, but it’s very very fast (burst compiled) and avoids archetype changing. I even made a dedicated component system for auto target filtering.

High-level events (ButtonClickedEvent, InputFieldReturnEvent, InputFieldEndEditEvent) are still components added to target entities. I’ll probably leave it like this because high-level events must be easy to use and filter (simple entity query over typeof(MyButton), typeof(ButtonClickedEvent)). Overhead is minimal because these events are rare. Example usage: DotsUI/com.dotsui.hybrid-samples/DotsUI.Samples/PrefabExample/InstantiationSystem.cs at develop · supron54321/DotsUI · GitHub

1 Like

New version merged on GitHub. Changelog:

[0.2.0] - 2019-08-19

Added

  • Added drag & drop support
  • Added ScrollRect

Changes

  • Removed custom parent system. Now DotsUI uses Unity.Transforms
  • Updated entities packages
  • Updated obsolete API
  • Unit tests upgraded to latest changes in the core
  • Minor performance improvements
  • Updated roadmap
  • LegacyRenderSystem renamed to HybridRenderSystem
  • Improved idle performance of HybridRenderSystem (added RequireForUpdate EntityQuery)

Fixes

  • Fixed issue with last few triangles not being rendered after InputField lost focus
  • Renamed folders in DotsUI.Hybrid
  • Removed unnecessary sync point in button system
  • Fixed exception in selectable system caused by NativeHashmap being overfilled
  • Fixed issue with canvas not being properly rebuilt after camera size changed
  • Canvas pixel size is now properly taken from camera size (instead of screen size)
  • Pointer events are now properly stopped from being propagated to parents

ScrollRect doesn’t support all of UnityEngine.UI features. It works only in one direction (Left->Right &? Bottom->Top), and it doesn’t support scroll bar hiding. DotsUI doesn’t support mouse scroll yet, so it’s obvious it doesn’t work in ScrollRect.

[0.3.0] - 2019-09-08

Added

  • Added support for ConvertToEntity
  • Added support for Screen Space - Overlay canvas rendering mode
7 Likes

Hello,
I’ve tried to convert a very simple scene from Unity UI to DotsUI. The setup is extremely simple - just a canvas with an image as a child object. The whole thing works when there is ConvertToEntity on Canvas game object. But I tried converting the Canvas into a subscene. At this point it broke. Not entirely, but it fails to convert the sprite asset. I’ve looked into the source a little bit, looks like you are adding sprites into destination entity manager using

DstEntityManager.CreateEntity(typeof(SpriteAsset), typeof(SpriteVertexData));

Instead, I believe you are supposed to use

GameObjectConversionSystem.DeclareReferencedAsset(sprite);

For this it looks like you need an additional system that updates in GameObjectDeclareReferencedObjectsGroup, and also you need to then convert declared sprite assets by their own conversion system. Anyway, I’m pretty new to this convertion workflow so I wasn’t able to make it all work.

Also it looks like DeclareReferencedAsset already adds a component object with the Sprite to the entity, so I guess you don’t need SpriteAsset shared component at all.

Ok, I managed to fix Image conversion to work with subscenes. Added a system that declares referenced assets (Sprites) and another system that converts those declared sprite asset references by adding SpriteAsset shared component and also SpriteVertexData. For the whole thing to work I had to also create SpriteAssetProxy, make it [System.Serializable] and also make SpriteAsset [System.Serializable].
Next: have to apply a similar fix to TextMeshPro font assets.
And then: figure out if we can work without SpriteAsset shared component altogether, cause Sprite asset entity already has the Sprite component object. This isn’t trivial because SpriteAssets being shared component gets addressed by shared component index later down the pipeline and my understanding is component objects are NOT shared components.

Update: I managed to fix TextMeshProUGUI conversion to also work with subscenes, the whole thing works with subscenes now. I can provide the source code of the changes I made if needed.

2 Likes

Good job! Can you create a pull request with your changes?

SCDs are quite useful in optimization. I can use indices to batch similar materials in the job. Of course, it could be done without them.

Btw. I have a little break from this project. I’ll start commiting new features after the weekend.

1 Like

Here you go: https://github.com/supron54321/DotsUI/pull/3

1 Like

I wonder what the DOTs team make of this. Would they want to follow the same approach or are they doing something completely different?

Now as DotsUI works with subscenes I’d suggest to think about making some/all systems [ExecuteAlways] so that when a subscene is in closed state one can still see the converted UI.

I already started it. I have some problems with RectTransformSystem (unity freezes) but I’m looking what causes this issue. The only problem I see at the moment is that screen space overlay, requires a dummy object to execute command buffer on GUI repaint event. I made some changes in code to create and destroy this object, but I’m looking for a more suitable solution. Unfortunately, Unity doesn’t expose API to hook into GUI repaint without GameObject.

1 Like

One more observation: for the canvas to be rebuilt one has to add DirtyElementComponent flag components. I wonder if the logic behind this could be reversed and instead of DirtyElementComponent flag there would be NonDirtyElementComponent flag that the system sets by itself. Then all entities without said flag would be considered dirty. This way you could eliminate the need for manual setting of dirty flag.

Got a problem that looks quite serious to me. Unity UI has well defined draw order that is based on hierarchy tree. Now the hierarchy itself is preserved when converting to entities, but sibling order is not (as it seems). So images and texts are drawn out-of-order. I guess it was a bad idea to base draw order on hierarchy in the first place. But I don’t see how to fix ordering in DotsUI, I guess we need ideas beyond what Unity UI can provide.

@supron A question: how do I show/hide parts of the UI. Like in GameObject world I’d do SetActive(true/false), what’s the equivalent action in DotsUI? Do I have to actually destroy entities? Or can I flag them (preferably whole hierarchies) to not be rendered?
Edit: figured it out myself - there is that Disabled component from Unity.Entities

1 Like

[0.4.0] - 2019-08-19

Known issues

  • Screen space overlay canvas throws exception in closed subscene

Added

  • Slider control
  • DotsUI inspector window (now displays only UI mesh info)

Changes

  • Removed old conversion pipeline
  • Refactored GO->Entity conversion code

Fixes

  • Fixed sibling order after GO->Entity conversion

It turned out to be hard task, because I couldn’t hook renderer properly. Screen space overlay requires additional GameObject to capture GUI render event. I’m still thinking about solution.

DirtyElement flag is a very efficient way to invalidate canvas hierarchy. We don’t want to rebuild hierarchy every frame. The only problem with the current design is a lack of high level API which could automatically invalidate element when any value was changed. I’m thinking about implementing such API for easier UI control.

Hierarchy order is very simple and straightforward approach. DotsUI uses the same principles, but ConvertToEntity destroys siblings order. I already fixed that issue in 0.4.0 by forcing DynamicBuffer to preserve hierarchy order. It seems like a good solution.

7 Likes