I am new to ECS and is trying to understand how the underlying rendering is done. Immediately I run into a beginner question: how does ECS locates the static data in memory? (meshes, materials etc.)
I try to understand it from a Graphics.DrawMeshInstanced standpoint:
You need some dynamic data like position, rotation, scale.
You need some static data like meshes, materials.
I know we have already prepared these dynamic data as small structs in native array, and there are chunking to make it run as fast as possible.
But what about those static data? In a Graphics.DrawMeshInstanced scenario, you basically have to use a mapping to find appropriate resources (like a Dictionary<id, Meshes> etc.), how does ECS handle this?
To give a real-world example: consider rendering a scene with many prefabs (different meshes, may or may not be using the same materials), how does ECS say, ok first render this type of prefabs and then move onto another?
And I imagine there are 2 types of scenarios:
(1) In a game with mostly static world (like FPS, Action Adventure): Does it basically advocate a new system to replace scene’s gameobjects with entities, so the workflow is basically the same for artists, but behind the scene they are well-aligned in memory for better rendering performance?
(2) In a game with mostly dynamic world (like a City Builder, Management Sim): Does it mean you still need to have both an array of ids (which represents the world), and a dictionary of <id, entities>, so that you can locate each id’s static resources (meshes, materials) upon render?
Thx in advanced!
(my terminology of ECS might be wildly incorrect, if so, do let me know…)
UPDATE: in scenario (2), you could just have an array of entities as world representation instead, but then my question is how ECS is able to magically locate these static data in memory in a faster way? (are they also components?)
Still wondering about how SetFilter() is able to be more performant than, say, a dictionary-like id search:
UPDATE:
Alright since both RenderMeshSystem and RenderMeshSystemV2 eventually calls EntityManager.GetSharedComponentData to get these static data, from the doc it looks like a linear search on a List of unique components.
Also SharedComponentDataManager is just a list of objects, so I think the speed is mostly from memory layout? Not sure if there are more tricks here.
PS: I think the “unique” here means “unique” in terms of struct values, not just the struct fields, so every unique instance of a RenderMesh is stored here? please correct me if I am wrong.
Get SCD is not a linear search. It is indexing into C# list. C# list indexer is O(1). The index number that allows that is maintained on the chunk. When the item is removed the list slot is just nulled so old indexes are still usable. (List size never decrease) Also a hash-to-index dict is maintained too so the method that takes the value is fast to find existing SCD.
Uniqueness is determined by hashing struct value. If found reference type like Material or Mesh it hash the reference address.
Thx! I am trying to see whether there are idea from ECS we can apply in our project before we fully commit into using ECS full-time: using DrawMeshInstanced eventually lead us into similar design, so future migration would be easier.
(There are also a few third-party ECS solutions that we would like compare it to, someday.)