Search Unity

SharedComponentData

Discussion in 'Entity Component System' started by Spy-Shifty, Apr 8, 2018.

  1. Spy-Shifty

    Spy-Shifty

    Joined:
    May 5, 2011
    Posts:
    546
    There are some open questions about SharedComponentData.

    Documentation:

    IComponentData is appropriate for data that varies between Entities, such as storing a world position. ISharedComponentData is useful when many Entities have something in common, for example in the boid demo we instantiate many Entities from the same Prefab and thus the MeshInstanceRenderer between many boid Entities is exactly the same.
    Code (CSharp):
    1. [System.Serializable]
    2. public struct MeshInstanceRenderer : ISharedComponentData
    3. {
    4.     public Mesh                 mesh;
    5.     public Material             material;
    6.  
    7.     public ShadowCastingMode    castShadows;
    8.     public bool                 receiveShadows;
    9. }
    In the boid demo we never change the MeshInstanceRenderer component, but we do move all the Entities TransformMatrixevery frame.

    The great thing about ISharedComponentData is that there is literally zero memory cost on a per Entity basis.

    We use ISharedComponentData to group all entities using the same InstanceRenderer data together and then efficiently extract all matrices for rendering. The resulting code is simple & efficient because the data is laid out exactly as it is accessed.

    Entities with the same SharedComponentData are grouped together in the same chunks. The index to the SharedComponentData is stored once per chunk, not per Entity. As a result SharedComponentData have zero memory overhead on a per Entity basis.
    • Using ComponentGroup we can iterate over all Entities with the same type.
    • Additionally we can use ComponentGroup.SetFilter() to iterate specifically over Entities that have a specific SharedComponentData value. Due to the data layout this iteration has low overhead.
    • Using EntityManager.GetAllUniqueSharedComponents we can retrieve all unique SharedComponentData that is added to any alive Entities.
    • SharedComponentData are automatically reference counted.
    • SharedComponentData should change rarely. Changing a SharedComponentData involves using memcpy to copy all ComponentData for that Entity into a different chunk.

    Assuming we have the following components:
    Code (CSharp):
    1. struct ItemOwner : ISharedComponentData {
    2.      public Entity Value;
    3. }
    4.  
    How does it really work?
    Normaly I would say ItemOwner is a class now we have a reference to it, and all items related to that reference are in the same group...
    But ItemOwner is a struct, so how does it know it's in the same group?

    How to add entities to that group?
    I would imagine the following:
    Code (CSharp):
    1. EntityManager.AddSharedComponent(itemEntity, new ItemOwner { value = ownerEntity } );
    This will group up all items to the specific owner so that I can filter it.

    What about if I have multiple fields in an SharedComponentData?
    Do all fields in the component have to be the same, to belong to the same group?
    And what If I use float?

    Can I filter a group by multiple SharedComponentData?

    The main problem about this concept to me is, I need to understand the mechanism behind, to get use of all of the features.
     
    Last edited: Apr 8, 2018
  2. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    The assumption is that SharedComponentData are changed rarely.

    We essentially use a hashtable to find if two shared component data on two different entities actaully match. If they do, the entities can be grouped in the same chunk. And the chunk knows which index the SharedComponentData has.

    Overusing SharedComponentData will result in lots of small chunks. So i am not sure the concept of filtering on multiple SharedComponentData types in the same ComponentGroup is a good idea. We support 1 or 2 right now.
     
    Spy-Shifty and Dreamora like this.
  3. xenonsin

    xenonsin

    Joined:
    Dec 12, 2013
    Posts:
    20
    A bit of a follow up to your answer.. What's the recommended way to actually add shared components? Is there a difference with these two methods?

    1.
    Code (CSharp):
    1.   public static ZoneComponent Hand = new ZoneComponent { Value = ZoneType.Hand };
    2.  
    3. EntityManager.AddSharedComponent(entity, Hand);
    4. EntityManager.AddSharedComponent(entity2, Hand);
    2.
    Code (CSharp):
    1. EntityManager.AddSharedComponent(entity, new ZoneComponent { Value = ZoneType.Hand };
    2.  
    3. EntityManager.AddSharedComponent(entity2, new ZoneComponent { Value = ZoneType.Hand };
    Also when you say "the assumption is that SharedComponentData are changed rarely"

    Do you think entities having a zone component that changes values frequently a bad idea? Would a better solution be having TagComponents, ex. DeckTag, HandTag, etc.?
     
  4. HeronHuang

    HeronHuang

    Joined:
    Nov 30, 2012
    Posts:
    27
    Same question above ,anyone can give an answer? thx:)
     
  5. HeronHuang

    HeronHuang

    Joined:
    Nov 30, 2012
    Posts:
    27
    https://forum.unity.com/threads/ecs-memory-layout.532028/
    "SharedComponentData (SCD)
    An SCD is part of the archetype and each unique (by value, not type) instance of an SCD requires its own chunk. So an entity archetype will be split over as many chunks as there are unique SCDs.
    The SCDs are stored in their own type arrays somewhere, not in the archetype chunk; the chunk just contains an index into that array."
    I just found this post, seems it based values.
     
    leni8ec and Spy-Shifty like this.