Search Unity

Getting 1 chunk per entity with SharedComponentData

Discussion in 'Entity Component System' started by Mike37, Jul 26, 2019.

  1. Mike37

    Mike37

    Joined:
    Oct 21, 2018
    Posts:
    26
    I'm using Unity 2019.1.11f1 with Entities 0.0.12-preview.33. I have some code roughly like the following:

    Code (CSharp):
    1. // in Start(), initialize some variables
    2. manager = World.Active.EntityManager;
    3. enemyArchetype = manager.CreateArchetype(typeof(RenderMesh), /* more components... */);
    4. renderMesh = new RenderMesh
    5. {
    6.     material = EnemyMaterial,
    7.     mesh = EnemyMesh
    8. };
    9.  
    10.    
    11. // in Update()  
    12. if (Input.GetKeyDown(KeyCode.Space))
    13. {
    14.     Entity enemy = manager.CreateEntity(enemyArchetype);
    15.     manager.SetSharedComponentData(enemy, renderMesh);
    16. }
    Every time I press spacebar, it creates a new entity and a new chunk (so 10 entities would mean 10 chunks). I'm guessing this is because when it creates the entity, the RenderMesh isn't yet set and therefore doesn't match the other entities, and it doesn't condense them once I give it the same RenderMesh.

    Is this intended behaviour? How can I ensure the enemies are added to an existing chunk?
     
  2. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    4,271
    Is the source of the material from a GameObject renderer? If so, it might be cloning the material every time you fetch it.
     
  3. Mike37

    Mike37

    Joined:
    Oct 21, 2018
    Posts:
    26
    The material is set from the editor. I have a public field in my class, like this:

    Code (CSharp):
    1. public class EnemySpawner : MonoBehaviour
    2. {
    3.     public Material EnemyMaterial;
    4.     public Mesh EnemyMesh;
    5.  
    6.     private RenderMesh renderMesh;
    7.     // more stuff...
    8.  
    9.     void Start()
    10.     {
    11.         renderMesh = new RenderMesh
    12.         {
    13.             material = EnemyMaterial,
    14.             mesh = EnemyMesh
    15.         };
    16.  
    17.         // more code...
    18.     }
    19. }
     
  4. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    4,271
    Not sure. Only other thing I can think of is that you got a dynamic buffer with a huge capacity in the archetype. Instead of instantiating from an archetype, could you use the archetype to create a prefab and then instantiate the prefab? I'd be curious if that still created unique chunks. How are you determining the chunk count?
     
  5. Mike37

    Mike37

    Joined:
    Oct 21, 2018
    Posts:
    26
    The Entity Debugger shows the number of chunks.

    It seems if I do manager.Instantiate(someOtherEnemy), then it gets added to an existing chunk. I could use that as a workaround, but it's inconvenient because I need an enemy to clone.
     
    sngdan likes this.
  6. Mike37

    Mike37

    Joined:
    Oct 21, 2018
    Posts:
    26
    Does anyone know if this will be fixed in a future version?
     
  7. Mike37

    Mike37

    Joined:
    Oct 21, 2018
    Posts:
    26
    Just an update: you still get a single entity per chunk if you instantiate from a prefab. I'm on Entities 0.1.1 now.

    So if you use:
    Code (CSharp):
    1. enemyArchetype = manager.CreateArchetype(typeof(RenderMesh), typeof(Prefab), /* more components... */);
    2. enemyPrefab = manager.CreateEntity(enemyArchetype);
    3. manager.SetSharedComponentData(enemyPrefab, /* set RenderMesh here */);
    4.  
    5. // Some time later...
    6. manager.Instantiate(enemyPrefab);
    It won't help.
     
  8. SubPixelPerfect

    SubPixelPerfect

    Joined:
    Oct 14, 2015
    Posts:
    224
    Caught the same bug

    once per frame i'm instantiating an entity that has both RenderMesh and Prefab and all instances get stored one per chunk

    but when i'm instantiating exactly the same entity but without prefab component, everything works as expected

    (Entities 0.1.1 HybridRenderer 0.1.1)
     
    Mike37 likes this.
  9. GilCat

    GilCat

    Joined:
    Sep 21, 2013
    Posts:
    676
    I have experienced that without the HybridRenderer.
    It seems like if the entities are instantiated in different frames that will end up in different chunks.
    Will put together a simple example to test this out...
     
  10. GilCat

    GilCat

    Joined:
    Sep 21, 2013
    Posts:
    676
    I was able to pin down why every time a certain entity was instantiated a new chunk was formed.
    It only happens if we use EntityManager.AddComponent(EntityQuery entityQuery, ComponentType componentType) API and for some reason this is forcing such beahviour.
    The reason you see this happening with HybridRender related instances is because the refferred API is used in RenderBoundsUpdateSystem (RenderBoundsUpdateSystem line 188 and 198):
    Code (CSharp):
    1.             EntityManager.AddComponent(m_MissingWorldRenderBounds, typeof(WorldRenderBounds));
    2.             EntityManager.AddComponent(m_MissingWorldChunkRenderBounds, ComponentType.ChunkComponent<ChunkWorldRenderBounds>());
    As you can see ISharedComponentData has nothing to do with it.

    I've put up a very simple system where this behaviour is replicated:
    Code (CSharp):
    1. struct ComponentData_A : IComponentData { }
    2. struct ComponentData_B : IComponentData { }
    3.  
    4. [AlwaysUpdateSystem]
    5. public class TestSystem : ComponentSystem {
    6.   EntityQuery m_query;
    7.   EntityQuery m_missingComponentQuery;
    8.  
    9.   protected override void OnCreate() {
    10.  
    11.     m_missingComponentQuery = GetEntityQuery(
    12.               ComponentType.ReadOnly<ComponentData_A>(),
    13.               ComponentType.Exclude<ComponentData_B>());
    14.  
    15.     m_query = GetEntityQuery(
    16.               ComponentType.ReadWrite<ComponentData_A>(),
    17.               ComponentType.ReadWrite<ComponentData_B>());
    18.   }
    19.  
    20.   protected override void OnUpdate() {
    21.     EntityManager.AddComponent(m_missingComponentQuery, ComponentType.ReadOnly<ComponentData_B>());
    22.     if (Input.GetKeyDown(KeyCode.C))
    23.       EntityManager.CreateEntity(typeof(ComponentData_A));
    24.   }
    25. }
    Just copy/paste and every time you press C a new entity is created on a new chunk.
    Note that if you instantiate several entities at once they will go to the same chunk.
     
    Mike37 and SubPixelPerfect like this.