Search Unity

Native Array in NativeArray

Discussion in 'Entity Component System' started by andreicfsteaua, Apr 3, 2020.

  1. andreicfsteaua

    andreicfsteaua

    Joined:
    Nov 18, 2019
    Posts:
    36
    Hi! I am beginner level in DOTS and I wanted to create a grid of cells which themselves can contain an array of elements. Since NativeArray exposes a pointer to native memory, that is not possible(NativeArray<NativeArray<Type>>). How would you do this? One way I thought would be possible is to create an NativeArray<Entity> which will hold the cells as entities and add to each cell a dynamic buffer with the needed type. The only problem I have with this is that there is a certain limit to what a dynamic buffer can contain(lower than 1000 from what I've tested, possibly even lower than this) and I might need more elements than that. If you have a solution let me know!
     
  2. WAYNGames

    WAYNGames

    Joined:
    Mar 16, 2019
    Posts:
    991
    You are still thinking in OOP. Your grid is just a buch of cells with coordinates. and your list of elemnt per cell is just that a buch of element that fits into a cell (so into coordinates).

    You could skip entirely the grid representation and just have a buch of entities with a coordinate component to tell to wich cell they are in. This has the adventage of allowing you to store various types of element in the cell without resorting to Entity referencing.

    I would also suggest you look into chared coponent data for you coordinate component, it will enable you to segregate you elment per cell and ietrate over them if necessary.

    The main limitation of Dynamic buffer for me is that id can store only one type of data. as far as I know there is no size limitation to the dynamic buffer, the only point of caution is if the size of your dinamic buffer (number of element * size of element) exceed the size of the chunk, it will be move out of the "chunk" memory, making it a bit lower to lookup.
     
  3. andreicfsteaua

    andreicfsteaua

    Joined:
    Nov 18, 2019
    Posts:
    36
    I may not understand correctly, but sounds like what I said. This is what I have implemented right now and to me seems to be what you suggested. I've tried to set InternalBufferCapacity to 1000 but it said it is too much
    Code (CSharp):
    1.  [InternalBufferCapacity(100)]
    2. //MyCollider is a struct with IComponentData
    3. public struct EntityList : IBufferElementData
    4. {
    5.     public Entity entity;
    6. }
    7. [InternalBufferCapacity(100)]
    8. public struct ColliderList : IBufferElementData
    9. {
    10.     public MyCollider collider;
    11. }
    12. int gridX;
    13. int gridY;
    14. int gridZ;
    15. NativeArray<Entity> entities;
    16.  
    17. entities = new NativeArray<Entity>(gridX * gridY * gridZ, Allocator.Persistent);
    18.         for ( int i = 0; i < gridX; i++)
    19.         {
    20.             for ( int j = 0; j < gridY; j++)
    21.             {
    22.                 for ( int k = 0; k < gridZ; k++)
    23.                 {
    24.                     entities[i * gridY * gridZ + j * gridZ + k] = entityManager.CreateEntity();
    25.                     entityManager.AddBuffer<EntityList>(
    26.                         entities[i * gridY * gridZ + j * gridZ + k]
    27.                     );
    28.                     entityManager.AddBuffer<ColliderList>(
    29.                         entities[i * gridY * gridZ + j * gridZ + k]
    30.                     );
    31.                    
    32.                 }
    33.             }
    34.         }
    35.  
    That would work fine for low values.
    Pls give me an example as to what you mean
     
  4. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    4,264
    InternalBufferCapacity specifies how many elements gets stored into the chunk before the buffer switches to heap memory. For your use case, you probably want this number to be low. It doesn't matter that you are using heap memory if you have a thousands elements inside of it.
     
  5. andreicfsteaua

    andreicfsteaua

    Joined:
    Nov 18, 2019
    Posts:
    36
    Thank you for the info, regarding the implementation do you think it's good enough? If you have a better solution please share it!
     
  6. RichardWepner

    RichardWepner

    Joined:
    May 29, 2013
    Posts:
    33
    What @WAYN_Group was saying: instead of storing a list of things for each cell, and a list (or list of lists) of cells, just store the things as entities, where each thing has a position (the cell it's inside).
    • Pro: no problem to implement in DOTS
    • Con: if you want to operate on all things in a cell, Jobs might not work for this (but I might not be deep enough in the matter of jobs and entities to judge)
    On the other hand: what are you actually storing per cell that you end up with more than 1000 things per cell?
     
  7. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    4,264
    You haven't specified anything about your problem, just how you want your data laid out. I usually lay out my data to map the problem and consequently can't give you any more feedback than that.
     
    RichardWepner likes this.
  8. andreicfsteaua

    andreicfsteaua

    Joined:
    Nov 18, 2019
    Posts:
    36
    So what I am trying to do is to implement a very basic collision detection algorithm. I am trying at first with spatial grid partioning and then advance to more complex algorithms. The cells need to store the colliders and their coresponding entities to do a broadphase detection. My way of implementing this is as said before. Create the grid, store these entities in a native array, add the collider list and entity list and a system takes care of assigning colliders to these cells. Each frame it clears the buffers of all cells then proceeds to assigning the colliders and entities to each cell. Because I am working with AABB I can get exactly the indeces where the cell will be positioned so that's why I thought it would be good to store the entities in an array. I use BuffersFromEntity passed to jobs to assign to the colliders and at last the system does a n(n+1) /2 search in every cell to find the overlapping AABBs.
    The grid should be evenly spaced producing less than 1000 entities per cell, but some cells may be overly populated and that's why I wanted to know if that would be a problem
    EDIT: Big problem found: cannot write parallel jobs with BufferFromEntity, causing massive spikes in performance. Any solutions to parellezing the process?
     
    Last edited: Apr 3, 2020
  9. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    4,264
    I use a pretty advanced version of this for UEBS-style broadphases. Instead of Dynamic Buffers, each cell contains a linked list of blocks of memory, where each block can hold multiple elements. That helps keep memory utilization under control. (Note: I have not ported this algorithm to Unity yet)

    A big gotcha with such an algorithm is that it becomes very challenging to parallelize when AABBs straddle the grid boundaries. I would advance to the more complex algorithms before trying to tackle anything with parallelism. Some of the more advanced algorithms are easier to parallelize. I maintain a public repo with one-such solution for Unity.
     
  10. WAYNGames

    WAYNGames

    Joined:
    Mar 16, 2019
    Posts:
    991
    Ok, so first have you look at the new physics package?
    Second, as I said you don't need to represent the spaciality of you problen onto the code. Instead of thinking about a grid containing entities in cells. Think about the entities having a common index when they should be in the same cell. IMO, There is no need for the grid representation. One component (possibly an ISharedConponentData) with just the ceelncoordinate should be enougth. There is no limit to the number of ellement per cell, shared component should allow for fast iteration over a single cell and just having the same shared component data will give you the collision query.
    Of course it assumes that one entity can only be in one cell at a time, otherwise it fall apart...
    In that case maybe use a dynamic buffer for the coordinates. I migth also suggest using a native multi hashmap. It will need to be sized to the number of possible entites, which most likely won't be memory efficient, and you would be able to store the coordinates as key and entity references as values.

    Think about the data you use and don't assume the data belong to the entity you conceptualize it to. For me the coordinates belong to the entity in the cell, not the grid you have in your mind.
     
    MehO likes this.
  11. andreicfsteaua

    andreicfsteaua

    Joined:
    Nov 18, 2019
    Posts:
    36
    An entity can be in multiple cells. Ok thank you for your insight. Something I would want to know is if SharedComponents can be changed on a per frame basis. As SharedComponent documentation says:
    SharedComponentData should change rarely. If you want to change a SharedComponentData, it involves using memcpy to copy all ComponentData for that entity into a different chunk.
     
  12. WAYNGames

    WAYNGames

    Joined:
    Mar 16, 2019
    Posts:
    991
    Like the the documentation says it depends on the frequency of cha'ge as it's an expensive operation. Anyway if entites can be in several cells it mute the mater as the entity can be liked to only one shared component of the same type