On the concept of Sub-Entities

As shown in Benchmarking tag component v2 , Huge entities are terrible for performance, adding a empty “tag” component to a large entity is also terrible for performance, adding any type or size of component is terrible, working on huge entities is also slow because there are less of them per chunk, imagine iterating over 100kb sized entities when you only want 8 bytes off them
Small entities are the way to go for performance.

Let me give an example to justify a sub entity feature:
You have a MainCharacter that contains: position, skills, inventory, collision, renderer, combat info, combat buffs, etc.
Now you want to make area of effect attacks, so to not have you checking every single entity every time for range check, you make so that each entity have a SharedComponentData(part of the map you are right now), something like MapTile(0, 0, 15, 15) if his position is (7, 0, 9) and would change to MapTile(15, 0, 30, 15) if his position is (16, 0, 9). Now each entity is on a ‘15x15 tile’ of the map, so you first check which tiles the AOE spell hits, and then only checks the entities in those ‘tiles’ the spell hits.
The issue is that adding or changing a SharedComponentData will move the entity to a chunk marked for that value, so the insanely huge MainCharacter entity will, in whole, have to me moved to a new chunk every time, and it is probably the only entity with that very specific archetype, so not only you need to move it to-from chunks, you also need to destroy/create chunks every single time.

Here enters a SubEntity. You split MainCharacter in MainCharacter +MainCharacterPosition, where MainCharacterPosition only have the character position, the current SharedComponentData for it’s tile, and a link to it’s parent Entity. When you need to check for spells, you only check these very small Position entities, so you can check for many of them in the same chunk, and since all of them are the very same, they all go to the same chunks and you only need to make a very new chunk if it is the only entity in the current map tile SharedComponentData.
Currently, this is already possible, the issue is a huge amount of boilerplate code needed to make it work, and it’s very error prone to manage these sub entities. I am aware that iterating values from the parent and sub entity at once have a cost of accessing two different chunks, but the reduced cost of moving huge entites all the time for every single little thing would probably outweigh it some times

[It is also possible that I misunderstand how entities are stored in chunks and all of this is wrong. Currently I understand that each entity archetype have it’s own chunk, so adding a component changes the entity’s archetype , and therefore it needs to be moved to a new chunk for the new archetype ]

For that we using, and most part of developer using spatial maps, binary/quad/octrees, there is no need to overcomplicate things, they works fast, they implements simple :slight_smile:

I could also make a sphere cast using Unity Physics and would even skip the fake-octree part, there are many other ways to solve that example, that’s not the point of the post.

Unity Physics also works on trees inside - BVH tree if i remember right :slight_smile:

Another use case is render sub-entities. Your simulation systems are usually not going to touch your render components, so why have them take space in the same chunk? In this case if two characters have different simulation components, as long as their visual representation is the same, their render entities still end up in the same chunk and vice versa (simulation the same components but rendering different). You could even destroy the render entity entirely if it gets culled off-screen.
The downside is that you end up spending cycles to copy their position/rotation and also have duplicated data, or write your renderer in a way that it gets it from the entity it belongs to (different chunk access + now you need a seperate code path for that).
I think in this case the benefits outweigh the cons.

There are pros and cons that need to be considered seperately for each case. I think that with the archetype-based chunks Unity uses, smaller sub-entities are a useful tool and I’d probably use it more as my entities get bigger.

3 Likes

They not take spase inside chunk, they stored not in chunk but in heap and archetype only use index (one int) of SCD for getting rendering data.

Think of other render components than just Hybrid Renderer’s RenderMesh (SCD). For example animation state, LOD components, interpolated position, etc.

Also if I were making a renderer I would probably also have a non-SCD variant of RenderMesh, because most games have objects that are only rendered once and don’t require instancing. It doesn’t make sense to reserve an entire chunk for those, and I hope a future version of Hybrid Renderer is going to consider that use case.

Going to necro this thread once since I had the brilliant idea of making it when the devs were away on holidays
Hopefully we can get some official support, at least some sort of callback when a Entity is destroyed, so we can destroy all sub-entities with it

You can add your sub-entities to the main entity’s LinkedEntityGroup.

does it destroy them as a group too? or ‘disabling’ and ‘destroying’ a entity is the same thing?

It sounds like DOTS can hit the same problems as OOP in that the data can get heavily connected and too large clogging up the processing bandwidth.

The thing is modern CPUs often have large caches and I think DOTS had a fixed chunk size, could the chunking size mechanism be getting in the way once a threshold is reached in entity size?

@Guedez can I ask what cache sizes does your CPU have and how large is the entity?

It’s a theoretical situation, not a current issue of mine, although it might become one day

In your example you mention 100kb sized entities most modern CPUs have a cache size less than this e.g. Zen 3700 only has a 32kb cache. And I think DOTS has a 16kb chunk size to help fit in with most common CPU caches.

it was an example of a huge entity given without knowing these numbers you stated