Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

ChunkComponents

Discussion in 'Entity Component System' started by BrianWill, Oct 16, 2019.

  1. BrianWill

    BrianWill

    Joined:
    Oct 10, 2014
    Posts:
    38
    Are chunk components a recent edition? Their documentation is very thin, and I can't find any videos talking about them.

    They sound like shared components in that a chunk only has one value for a chunk component rather than per entity, but unlike shared components these are regular IComponentData blittable types and so can be accessed in jobs. It also seems to differ in that multiple chunks with the same chunk component value have their own copies (whereas chunks with the same ISharedComponentData value would share one copy).

    These chunk components are stored external to the chunk itself, though I'm not clear on how exactly. Looking through the entities package code, they seem to be stored on a 'metaentity' of the chunk, but the code gets very hard to follow from there.

    I'm especially unclear on what happens when you add a new entity with a given chunk component value: if the entity is guaranteed to be added only to chunks that share the same value, how is that guaranteed? Are the values hashed like ISharedComponentData?

    What is the full list of differences between chunk components and ISharedComponents and their intended use cases?

    btw, the name for these things is very search hostile, partly because there is no IChunkComponentData, just AddChunkComponentData(), et al.
     
    M_R likes this.
  2. sschoener

    sschoener

    Joined:
    Aug 18, 2014
    Posts:
    73
    There is a little bit more of documentation around the functions that handle chunk components, see for example this thread and this link in it. The most important part is this, I think:
    The last part in the parentheses is not actually true as outlined in the thread linked above.

    I'd say that the major differences between chunk components and shared components is like this:
    • shared components do not need to be blitable
    • shared component are used to sort entities into chunks by the value of the shared component, whereas chunk components make use of the existing chunk structure and allow you to associate additional data with a chunk
    Do note that chunk components still belong to the archetype of an entity and that the value of a chunk component is easily lost:
    • moving a component to a different chunk means that it now gets the chunk component value from the chunk it is moved into
    • this especially means that the chunk component associated with an entity may change due to addition or removal of a completely unrelated component (this is unintuitive at first)
    Consider how you might use shared components and chunk components in a renderer:
    • for batching purposes, it may be useful to sort entities by the mesh they are using, so the Mesh goes into a shared component. Here we are trying to sort entities.
    • now we need to determine what entities to draw, so ideally we'd have an easy way to cull entities. Luckily, we already have a handy structure in place that we could exploit: Entities are sorted into chunks. We can use a chunk component to keep track of the bounds of the entities in each chunk. Here we are trying to exploit the existing sorting structure (the chunks)
    Does that help? :)
     
    bb8_1, Ryuuguu and BrianWill like this.
  3. BrianWill

    BrianWill

    Joined:
    Oct 10, 2014
    Posts:
    38
    Thanks for the reply!

    So what happens when I create a new entity with a particular value for a chunk component? Does the chunk it happens to get placed in get its old chunk component values clobbered for the whole chunk?

    For shared components, I believe there's a map used to lookup all matching chunks by hash of the shared value, right? But for chunk components, there's no such analog and no such guarantees about an individual entity retaining the chunk component value that was last set for it, yes?

    In the culling example, we create a new entity, get the bounds of its chunk, then update the bounds to encompass the new entity? I'd assume we'd want to select the chunk with the closest matching bounds to insert it into, though, rather than just accept some random chunk.
     
    sschoener likes this.
  4. sschoener

    sschoener

    Joined:
    Aug 18, 2014
    Posts:
    73
    There is a subtlety here that makes this a bit more complicated: You cannot add a new chunk component to a single entity and simultaneously set its value. In fact, AddChunkComponentData with an Entity argument does not allow you to set the value of the chunk component (constrast that with AddComponentData which allows this). This is not allowed because it poses a weird problem: When you add a chunk component to an entity, its archetype will change and it may have to move to a different chunk, which will reset all of its chunk component data. If you were able to set a value when adding the chunk component, would that happen...
    • ...before moving to the new chunk (then you'd change the old chunk's data, but this Entity would get the chunk component data from the new chunk it is moving to, so it wouldn't have the data you actually set),
    • ...or after moving to the new chunk (then you'd essentially overwrite the data from some random chunk)?
    What you can do, however, is use AddChunkComponentData with an EntityQuery, because EntityQueries match against chunks and set the data for the whole chunk. Alternatively, you have to use SetChunkComponentData with the Entity you want to modify. There the documentation (quoted above) states: If you change the value of a chunk component using an entity in that chunk, it changes the value of the chunk component common to all the entities in that chunk.

    Yes, shared components are stored externally and looked up by index. Chunk components are less "reliable" and probably most sensibly used for caching ([1]). The value of a chunk component is pretty volatile and can change by invoking completely unrelated operations. For example, when you add a new component type to an entity without using an EntityQuery, that entity may move to a completely new chunk which resets its chunk component data to the default zero-initialized value (see this post again).

    Well, that depends. The chunk structure is already conveniently inplace and culling by chunk might still be significantly better than not culling at all (and it's dirt cheap). Do you need the added complexity? Maybe? You'd have to test that; I'd bet that in many examples you can get away with this much simpler approach. In fact, this is the approach taken in MegaCity (it's an excellent talk; especially this bit).
     
    Last edited: Oct 16, 2019
    BrianWill likes this.
  5. BrianWill

    BrianWill

    Joined:
    Oct 10, 2014
    Posts:
    38
    Thanks again. It seems quite misleading for the API to let us treat these components as if they belong to the entities at all. I'd rather it require us to get the ArchetypeChunk from an Entity and get/set the ChunkComponent through that instead of through any Entity.
     
    sschoener likes this.