Search Unity

Question Unwanted Transforms are required in 1.0 Baking?

Discussion in 'Entity Component System' started by lclemens, Jan 28, 2023.

  1. lclemens

    lclemens

    Joined:
    Feb 15, 2020
    Posts:
    761
    In 0.51 I had a faction matrix - a singleton entity that store information about which teams were at war and which ones were at peace. I had an authoring gameobject inside of a subscene that was used to configure it and IConvertEntity was used to make it into an entity. When the object was converted, it did not have any transform information - which is fine, it didn't need that information.

    When I converted it to a baker in 1.0, now there is transform information attached to the entity. It is completely pointless to have this transform information. I supposed it's not the end of the world or anything, but it seems like a waste of memory and possibly CPU. I can envision some situations where an application might have thousands of baked entities that don't need transforms. This is not performance-by-default.

    upload_2023-1-28_16-6-13.png

    The same is true for lots of other entities in subscenes that are abstract concepts and have no need for a world transform. Another example is PhysicsStep in Unity.Physics.

    upload_2023-1-28_16-7-14.png

    In the TMG discord I asked if anyone knew a way to disable the transforms, but no one knew. I searched all over online but was unable to find any information about disabling them.

    One idea I have is to create the entity programmatically at runtime in a game-object's Awake() or Start() function.... but that just seems hacky and less performant. And it won't work in situations where baking is required.

    I did notice that if I check the "Static" checkbox in the inspector, "World Transform" and "Local Transform" are removed, but "Local To World" still remains.

    So what's the deal? Are we just supposed to accept this as a new "feature"? Maybe there is some mechanism such that performance and memory footprint aren't affected? Or is there some way to disable the transforms that I missed in the documentation?
     
    Last edited: Jan 28, 2023
  2. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,761
    Currently transform baking flag don't really work except manual override, however you can use this to stop components being added

    this.AddTransformUsageFlags(TransformUsageFlags.ManualOverride);

    Once TransformUsageFlags are working correctly this should basically be a way to limit what transform components are added to entities dynamically

    https://gitlab.com/tertle/com.bovin...ore.Authoring/TransformUsageFlagsAuthoring.cs

    A script here to do it for you, though as I said atm only manual override will work
     
    soundeosdev likes this.
  3. Arnold_2013

    Arnold_2013

    Joined:
    Nov 24, 2013
    Posts:
    287
    Maybe you can remove these components with a baking system? I would assume these run when you close a subscene so they don't have to run at runtime... Not great because now you need to keep an eye on changes Unity makes to the amount of data they add by default.

    On the other hand, since the max entities in a chunk is now 128 because of the 'enable component'... does it still get you any performance to create small entities?
     
  4. OndrejP

    OndrejP

    Joined:
    Jul 19, 2017
    Posts:
    304
    I've encountered similar issue, no good solution found.

    More specifically, I'd my entities to have Parent component, but no transforms. The reason for this is to have logical entities of my prefabs under the prefab in the hierarchy window. Without that, it would create big mess.

    Maybe better solution for this would be to allow user-defined nesting of entities in the hierarchy window - purely visual for Editor. Then I would be able to use any of my own components for visual nesting. This is common case for Entities which can have multiple logical parts - especially when they can have same part twice.
     
  5. TheOtherMonarch

    TheOtherMonarch

    Joined:
    Jul 28, 2012
    Posts:
    867
    I am not sure this will be a popular opinion but here goes. If your entity does not require a transform, it probably should not be a baked entity. For singleton entities that require a lot of data serialize them separately using your own logic not with baking.

    This sounds like a terrible idea. You can separate your logic with components. If you need two of the same component on a entity it sounds like something is wrong with your design.
     
    Last edited: Jan 29, 2023
  6. OndrejP

    OndrejP

    Joined:
    Jul 19, 2017
    Posts:
    304
    I'm not interested in your judgemental opinions, you put your opinions first without even trying to understand the problem. You can't take the other perspective, and the only truth is your truth. So please, don't even bother to reply to my posts (this is not the first case).

    Let me give better example for other people, who might want to help me find the solution:

    I have an entity representing a space ship, the space ship has various parts, like fuel tanks, crew quarters, cargo bays etc. In game the space ship is represented by simple sprite, there's no need for parts to have transforms. The game logic does not need transforms either. The part of the gameplay is management of different ship systems, ship can have multiple instances of some systems (like fuel tanks). For example when one fuel tank is destroyed, ship can still use the other one. All systems have some shared characteristics, like HP, how much space they take on the ship etc.

    It's clear and convenient that individual systems are separate entities. They have to be linked to the space ship somehow and ideally, I want them to be children in hierarchy window in Editor. There are few options I'd be happy with.
    1. Space ship systems would have
      Parent
      component and no transforms.
    2. Space ship systems would have
      ShipSystem
      component, which contains reference to ship Entity
      -
      ShipSystem
      component would be tagged with attribute (for example)
      - Hierarchy window would show ship systems under space ship entity
    In both cases I'd prefer to avoid transform components on ship systems, because they make no sense.
    If there are transforms on ship systems, would they update when ship moves? That might be wasted performance.

    I should not care about wasted space in chunks or batching, it will be probably fine, but lets do some calculation anyway.
    Chunk has 64K and can have up to 128 entities (for optimal batching), that means one entity is 512 B or less.
    Transform components have:
    8 floats - WorldTransform
    8 floats - LocalTransform
    16 floats - LocalToWorld
    32 floats = 128 B in total, that's 25% of space

    That means I get to use 384 B for my components, which should be more than enough.
     
  7. TheOtherMonarch

    TheOtherMonarch

    Joined:
    Jul 28, 2012
    Posts:
    867
    I did not mean to upset you. I don't think I ever interacted with you before so I don't know where the hostility is coming from. I probably should not reply since you asked me not to, but I will reply anyway since other readers may find it useful.

    Destroying entities or adding tags is a bad way of doing things and has less performance generally. You give an example of a fuel tank being destroyed. You probably need to know the state of each fuel tank to show in the GUI. In other words fuel tanks are not interchangeable tank 1 is not going to show up on in the GUI the same as tank 2. So, your example is not really a good one. You need to do a lot of extra work which you did not touch on.

    The way I would do it is a have a different component schema for each class of ship. Or a Dynamic buffer / FixedList in really complex cases.

    Code (CSharp):
    1.  
    2. public struct fuelShipType1 : IComponentData
    3. {
    4.     public float tank1HP; //if hp == 0 tank is destroyed show destoyed in GUI
    5.     public float tank2HP;
    6.  
    7.     public float tank1FuelGallons;
    8.     public float tank2FuelGallons;
    9. }
    10.  
    11.  
    Destroying a child entity just to represent a logical change is a bad design likewise adding tag components is also bad design. Structural changes should be avoided.
     
    Last edited: Jan 29, 2023
  8. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    4,270
    16 kB, not 64 kB. So transforms fill things up fast.
    Lifecycle of state is a major factor that needs to be considered, and is something you are completely neglecting. Multi-entity designs are a completely valid way to go about things. Is it different from how you think it should be done? Yes. But it is valid and effective nonetheless.

    Anyways, I agree with the sentiment that the Entities Hierarchy hardcoding the Parent component as its organization system is a pita, and I would really appreciate if we could define our own "logical parent types" that the hierarchy could work with.
     
  9. TheOtherMonarch

    TheOtherMonarch

    Joined:
    Jul 28, 2012
    Posts:
    867
    The cost of accessing hierarchical components is huge. You need to pass in not one but many ComponentLookup’s and end up with huge amounts of random access. You kind of have to do it if you need physics collider and transforms. But it is not something you should ever do for simple logic if you can avoid it. My own code has huge amounts of spaghetti code from ComponentLookup’s. I can only imagine the hell of having more random lookups.

    From this discussion, I am taking my own advice and moving the damage states for my vehicles into a root component which will reduce the random access a lot. Rather than needing to do it every update, I will be able to check states easily and only update them when a part is actually damaged, which is not very often.
     
    Last edited: Jan 30, 2023
  10. Arnold_2013

    Arnold_2013

    Joined:
    Nov 24, 2013
    Posts:
    287
    I think you are both right :). The random lookup of data from other entities, or if an entity still exists is definitely something I would try to reduce in my next project. And I already try to make a fat root entities.
    But I also see the benefit from having separate entities (prefabs) doing separate things, making them easy to exchange and easy to reuse in other places. I admit the physics system also likes these splits. It does result in many 'every frame' entity lookups, losing performance in a way that is not easy to refactor later.

    I like the performance of ECS, but I also need the flexibility of quickly changing stuff. Maybe this is because I don't have a good enough design document, and I am making/changing stuff as I go. Sorry for not really adding to this discussion, but wanted to say they do help me think about ECS in a more structed way. So thanks :).
     
    OndrejP and lclemens like this.
  11. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    4,270
    Indeed, that is another factor to consider (and one I assumed you were already considering). There are however a plethora of techniques to minimize lookups while having objects split into logical entities.

    It is also a good time to remind everyone that not everyone uses ECS for the "most optimal performance", but rather, ECS gives a large performance headroom with nearly all game logic being Burst-compiled that they can focus less on optimizing and more on crafting the experience they want to create.
     
    JesOb and lclemens like this.
  12. lclemens

    lclemens

    Joined:
    Feb 15, 2020
    Posts:
    761
    I hear what you are saying, but in 0.51 one of the nice features was the ability to easily do composition by stacking components onto an entity in the editor instead of via code. We could simply add new components by adding them to the game-object. With 1.0 it is more difficult to do that for baked entities that don't need transforms without keeping the transforms hanging around for no reason.

    Yes, sometimes doing the initialization outside of baking is a good way to avoid the problem, but there are situations where the data might need to be baked for performance reasons, initialization timing reasons, live conversion reasons, entity-relationship reasons, etc.

    The good news is that @tertle 's solution works! Just add that TransformUsageFlagsAuthoring component to the gameobject and set the flag to ManualOverride in the editor and the LocalToWorldTransform goes away. I wish there was just a checkbox to enable/disable transform addition on every subscene element (like the "Static" checkbox) instead, but tertle's method gets the job done. Performance by default restored.
     
  13. OndrejP

    OndrejP

    Joined:
    Jul 19, 2017
    Posts:
    304
    The hostility comes probably from the discussion about fixed point. Anyway, to the point.

    By destroying fuel tank I meant "destroying" in terms of gameplay event, not deleting entity. The entity would stay there when fuel tank explodes. While I hate having to do random access to get data from child entities, it provides nice flexibility.

    It allows me to easily refit the ship at the equipment dock. Player can dock there and remove second fuel tank in favor of additional cargo bay. Or he can add extra oxygen generator and small shield generator for example (they are very small)

    Having ship systems as separate entities allows me to do some shared processing easily, like hit detection and damage.
    Simple example: ship gets hit, to find which system got hit, I can calculate system hit probability based on it's size (fuel tank has higher probability than cockpit because it's bigger).

    I was considering using DynamicBuffers/FixedBuffers directly on the ship, but it comes with it's own problems. To enumerate all ship systems, I'd need to go through all the buffers: buffer for fuel tanks, buffer for cargo bays etc. And in the buffers, shared functionality would be duplicated (e.g. taking damage), each ship system would have it's own buffer component with it's own HP variable. These details are way beyond the scope of this topic. I still don't know which way is optimal and I'm trying different approaches while learning ECS to see it's upsides and downsides.

    As suggested above, I'd appreciate ability to define my own visual organization component in Editor (besides hard-coded Parent component).

    You're right, it's only 16 KB, which means chunk gets completely filled by 128 entities with transform components, that's sad. It means if there are transform components on the entity, batching will be always worse than it could be - batch will be smaller than 128 entities. Not a problem for my prototyping and learning, but it might be something to consider by Unity team.
     
    JesOb likes this.
  14. Arnold_2013

    Arnold_2013

    Joined:
    Nov 24, 2013
    Posts:
    287
    You also get the linkedEntityGroup which can takeup a lot of bytes when using a hierarchy (it auto adds when instantiating a prefab, but is not there when you put something in the subscene). It makes sure all children get destroyed when the parent gets destroyed, so its not useless. Still it adds bytes.

    When I look in Window -> Entities -> achetypes. I have chuncks with only ~18 capacity, oke they need that data. But I also have chunks with ~70 capacity where most of the data is the transforms.

    Does it matter? SIMD takes 256 bit (32 bytes). Data is aligned in the chunk per component, so reducing hitpoints (4 byte float) would still be done in batches of 8 entities. Scheduling parallel is probably done per chunk (maybe not?) so having ~8 low capacity chunks could be faster than 1 high capacity chunk depending on the scheduling overhead.
    For cache prefetches it will be an impact, since every chunk needs to be fetched separately.

    It just does not feel right to have low capacity chunks.
     
    soundeosdev and OndrejP like this.