Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Is it possible to create compound collider with each child collider attached to corresponding entity

Discussion in 'Physics for ECS' started by BobFlame, Dec 8, 2019.

  1. BobFlame

    BobFlame

    Joined:
    Nov 12, 2018
    Posts:
    95
    In physics demo, the compound collider is added to single entity, and the render mesh is combined adding to the same entity too for rendering.
    But for my situation, I need to create compound collider with each child collider attached to corresponding entity.
    Is there any API to do this?
     
  2. steveeHavok

    steveeHavok

    Joined:
    Mar 19, 2019
    Posts:
    481
    Short answer is probably no! All child colliders are moving together within the compound collider so there is only really one entity with transform needed. Can I ask what your usecase/situation is?
     
    BobFlame likes this.
  3. BobFlame

    BobFlame

    Joined:
    Nov 12, 2018
    Posts:
    95
    Thx for replying! Maybe you're right. My usecase is a building game, spaceship. each block could be separatedly built onto, and also destroied.

    In situation of one block connecting two other blocks is destroied. The two remaining blocks should be turned into individual rigidbodies. This could be easily done in gameObject mode. just adding a rigidbody component. However in ECS mode it need to rebuild the compound collider manually.

    Moreover, the block that being destroied should be disable rendering. I also need to maintain a mapping manually and find which entity this collider is mapping to then destroy that rendering entity.

    Honestly, ECS is really not coding friendly. It is more suitable for Prefab, but not enough support for procedural generating gameplay.
     
    Last edited: Dec 12, 2019
  4. BobFlame

    BobFlame

    Joined:
    Nov 12, 2018
    Posts:
    95
    Also I've tried to using fixjoint instead of compound collider,
    but you know, the fixed joint is not really fixed. it would causing annoying spring effect.
    Another idea is keep every block kinematic, but the whole ship won't response to collision properly.
    So I don't know what to do. Maybe better to give up on ECS. just gameobject.
     
    Last edited: Dec 10, 2019
  5. filod

    filod

    Joined:
    Oct 3, 2015
    Posts:
    223
    same problem but different detail, i use compound to implement character "lift a rock and hold" thing, but many query methods (CollisionType.Composite/CollisionType.Terrain) still remain not implemented. i stuck here and can't find a workaround (fixed joint not apply this situation either)
     
  6. BobFlame

    BobFlame

    Joined:
    Nov 12, 2018
    Posts:
    95
    Hi stevee, is there and progress or any solution to this, after a year......?
     
  7. argibaltzi

    argibaltzi

    Joined:
    Nov 13, 2014
    Posts:
    220
    you would need to rebuild the compound collider and also build a new box collider for the individual dynamic bodies that got separated. This is fairly fast in ECS from what i tested
    You can also have a duplicated set of individual entities that become activated and ready to fall and then just rebuild the compound collider only.
     
  8. steveeHavok

    steveeHavok

    Joined:
    Mar 19, 2019
    Posts:
    481
    Actually, I looked at this issue last week. I added a RenderEntity variable to the ChildCollider struct and updated the conversation pipeline to add the Entity handle. At least that way you have a reference to the graphics representation when you call something like GetLeaf using a ColliderKey from a Ray or Collider cast.
    It has yet to be passed review but should make it into a release early in the new year. If I get a chance I'll post a patch you can apply locally for Unity Physics (though you'll need to wait for the release to get the Havok Physics version as it involves data structure changes).
     
  9. BobFlame

    BobFlame

    Joined:
    Nov 12, 2018
    Posts:
    95
    That's great. I will wait for the release.
     
    petarmHavok likes this.
  10. MicCode

    MicCode

    Joined:
    Nov 19, 2018
    Posts:
    59
    I'm also making a building game and ran into this exact issue, looking forward to the update
     
  11. florianhanke

    florianhanke

    Joined:
    Jun 8, 2018
    Posts:
    426
    This makes me very happy, as it has been bothering me for a long time!

    That said, @steveeHavok what was the reason for calling it "Render"Entity? In my case, the corresponding entities are not always rendered.
    I understand that calling it Entity and renaming Entity -> RootEntity is an issue for in the short term incurring upgrading pains, but I think that RenderEntity could lead to misunderstandings by first-time users in the future.
     
    steveeHavok likes this.
  12. davidus2010

    davidus2010

    Joined:
    Dec 4, 2017
    Posts:
    72
    Hi there, i'm also working on a spaceship building game where i ran into similar issues. What i did to solve it:
    Each "ship grid block" is treated as its own entity, but the collider is used to build a compound collider for the spaceship. To figure out which block is being targeted (to interact with it or remove it from the ship), i store the collider leaf index of each "grid block entity". When casting a ray that hits the compound collider, i extract the sub key of the collider hit, and then search the block on the ship for this key. When the compund collider is reconstructed, i store the collider index key (the index of a single collider that represents the entity in the compound collider) in each entity that belongs to the ship.

    Here's two partial code snippets on how i did this, maybe this can help someone. Note that the code is a whole mess and i'm just using it for POC purposes, but it still manages to run smoothly when operating on grids with 1000+ blocks:
    Code (CSharp):
    1. //generated a new compound collider for a grid, stores the collider keys to each block
    2. private void rebuildGridCollider(Entity gridEntity) {
    3.         var blobList = new NativeList<CompoundCollider.ColliderBlobInstance>(1, Allocator.Persistent);
    4.  
    5.         uint i = 0;
    6.         float weight = 0;
    7.         Entities.ForEach((int entityInQueryIndex, ref PlacedGridBlockTag gridTag) => {
    8.             if (gridTag.gridParent != gridEntity) return;
    9.             gridTag.colliderIndexKey = i++;
    10.             weight += gridTag.mass;
    11.             blobList.Add(new CompoundCollider.ColliderBlobInstance() {
    12.                 Collider = gridTag.colliderRef,
    13.                 CompoundFromChild = new RigidTransform(gridTag.localRotation, gridTag.localPosition)
    14.             });
    15.         }).WithBurst().Run();
    16.  
    17.         //grid destroyed
    18.         if (i == 0)
    19.         {
    20.             EntityManager.DestroyEntity(gridEntity);
    21.             blobList.Dispose();
    22.             return;
    23.         }
    24.  
    25.         Debug.Log("colliders: " + blobList.Length);
    26.  
    27.         BlobAssetReference<Collider> toConstruct = BlobAssetReference<Collider>.Null;
    28.  
    29.         Job.WithBurst().WithCode(() => { toConstruct = CompoundCollider.Create(blobList); }).Run();
    30.  
    31.         EntityManager.SetComponentData(gridEntity, new PhysicsCollider {Value = toConstruct});
    32.         var centerOfMass = toConstruct.Value.MassProperties;
    33.         EntityManager.SetComponentData(gridEntity, PhysicsMass.CreateDynamic(centerOfMass, weight));
    34.  
    35.         blobList.Dispose();
    36.     }
    37.  
    38. //finds the hit block key from the ship's compound collider, indeyKey is the key that is stored in the above method:
    39. private Entity RaycastToGridBlock(float3 RayFrom, float3 RayTo, int layer, out float3 hitPos, out float3 hitNormal,
    40.         out uint indexKey) {
    41.         var physicsWorldSystem = World.DefaultGameObjectInjectionWorld
    42.             .GetExistingSystem<Unity.Physics.Systems.BuildPhysicsWorld>();
    43.         var collisionWorld = physicsWorldSystem.PhysicsWorld.CollisionWorld;
    44.         indexKey = 0;
    45.  
    46.         RaycastInput input = new RaycastInput() {
    47.             Start = RayFrom,
    48.             End = RayTo,
    49.             Filter = LayerToFilter(layer)
    50.         };
    51.  
    52.         bool haveHit = collisionWorld.CastRay(input, out var hit);
    53.         if (haveHit)
    54.         {
    55.             hitPos = hit.Position;
    56.             hitNormal = hit.SurfaceNormal;
    57.             Entity e = physicsWorldSystem.PhysicsWorld.Bodies[hit.RigidBodyIndex].Entity;
    58.  
    59.             var hitCollider = collisionWorld.Bodies[hit.RigidBodyIndex].Collider;
    60.  
    61.             unsafe
    62.             {
    63.                 var isCompound = (CompoundCollider*) hitCollider.GetUnsafePtr();
    64.                 hit.ColliderKey.PopSubKey(isCompound->NumColliderKeyBits, out indexKey);
    65.                 //Debug.Log(indexKey);
    66.             }
    67.  
    68.             return e;
    69.         }
    70.  
    71.         hitPos = float3.zero;
    72.         hitNormal = float3.zero;
    73.         return Entity.Null;
    74.     }
    75.  
     
    cj-currie, Krooq and steveeHavok like this.
  13. steveeHavok

    steveeHavok

    Joined:
    Mar 19, 2019
    Posts:
    481
    Generally the use-case problems were related to the graphics representation feeding into the physics representation but having no path back to graphics from a physics query. I'm happy to rename this before it is shipped if you have a better term, though 'RootEntity' sounds more confusing to me. 'ShapeEntity' was an initial term I considered. Would 'ShapeEntity' be prefered?
     
    florianhanke likes this.
  14. florianhanke

    florianhanke

    Joined:
    Jun 8, 2018
    Posts:
    426
    I think you're right about the naming of RootEntity (I was also considering ParentEntity, but went for root, as parent is used in the code, and the top parent is usually the root). But I suspect we are not talking about the same thing.

    I am assuming you mean this, just to make sure I understand:
    Simple collider:
    - Entity method -> entity
    - ShapeEntity -> entity
    CompoundCollider collider:
    - Entity -> root entity.
    - ShapeEntity -> child entity

    I convoluted two separate issues in my above post and may not have been clear – separating 1:1 child collider-entity and child-collider -> "root" entity readers, and naming of "root" entity. (In simple colliders, "root" entity would == entity)

    In regard to the first issue, I think it best (long term) for the API, when the Entity reader refers to the 1:1 corresponding entity of the original collider, in a simple collider or in a compound collider. At least that least violates my personal expectations.
    As to the naming, perhaps CompoundEntity is better – this signals that we are wanting to accessing the special case, as opposed to the normal Entity case.

    Just to be extra clear what I mean:
    Simple collider:
    - Entity method -> entity
    - ?Entity -> entity
    CompoundCollider collider:
    - Entity -> child entity.
    - ?Entity -> root entity

    I hope what I mean is clearer now…?

    P.S: I know the above hinges very much on what people generally expect when they type eg. hit.Entity – I suspect for people who use compound colliders, it's what entity actually was hit.
     
    Last edited: Jan 7, 2021
    steveeHavok likes this.
  15. MicCode

    MicCode

    Joined:
    Nov 19, 2018
    Posts:
    59
    In the Bullet Physics API, there's something called User Pointer for use case like this, maybe we can call it UserEntity?
     
  16. steveeHavok

    steveeHavok

    Joined:
    Mar 19, 2019
    Posts:
    481
    The expectation from a physics query should be to get the Entity associated with the Body. Generally you want to manipulate that Body by applying impulses etc. If you also get a ColliderKey then a child collider within that body is specifically involved, but a lot of the time you won't care. That said, we need to make it easy to get the extra details if you care and need them for your own logic.

    In re-evaluating things based on this conversion, I can just have a ChildCollider.Entity member. It does not need to be ChildCollider.ShapeEntity or ChildCollider.RenderEntity!

    <TLDR>
    Only read this if you don't care about the Shape/Render naming reasons, which largely stem from Edit Time concerns.
    So the only problem I'm addressing here is that child entities are wrapped into a CompoundCollider with no runtime association back to the original child Entity (i.e. the one at Edit Time that had a Physics Shape Authoring component on it). Hence the 'ShapeEntity' idea.
    I also had 'RenderEntity' as the Mesh Renderer is the component used to test whether a Mesh on a child node is included in calculating the Convex Hull of a Physics Shape on a parent node. This is a similar issue. where one single Physics Collider is associated with multiple Meshes at edit time, though at runtime the original hierarchy of entities that went into the Convex Hull can still easily be retrieved.
    So, due to the importance of the Mesh Renderer in the Convex Hull case I used the name 'RenderEntity' in the CompoundCollider Child case.

    Excuse my rubbishness with youtube but this might help rather than typing more:

    </TLDR>
     
  17. florianhanke

    florianhanke

    Joined:
    Jun 8, 2018
    Posts:
    426
    Thanks @steveeHavok for this answer, and the video!

    Regarding expectations, I was coming at it from my more special case. I almost exclusively use Physics for raycast queries, where I usually want the collider's original entity (material properties of what was hit, does a projectile penetrate and so on and so forth and also virtual colliders to simulate holes or for selection, usually without graphical representations).

    From the video, it looks like my case(s) should be covered, and in an elegant way if I got that correctly (Entity for the child collider will be available if an authoring component is added). So I am looking forward to the next release! :)

    P.S: No youtube rubbishness detected.
     
    steveeHavok likes this.
  18. steveeHavok

    steveeHavok

    Joined:
    Mar 19, 2019
    Posts:
    481
    Just to be clear, Entity for the Child Collider will be available regardless. So your spaceship armor use-case will work out of the box. The extra authoring component in the video is only needed where an associated graphical representation was in a different branch of the hierarchy.
     
    reeseschultz and florianhanke like this.
  19. florianhanke

    florianhanke

    Joined:
    Jun 8, 2018
    Posts:
    426
    Thanks for the clarification, @steveeHavok
     
  20. BobFlame

    BobFlame

    Joined:
    Nov 12, 2018
    Posts:
    95
    @steveeHavok hi, I cant find any "render entity" in "Child Collider" in unity.physics 6.0, is it cancelled or will be added in any version in furture?
     
  21. steveeHavok

    steveeHavok

    Joined:
    Mar 19, 2019
    Posts:
    481
    Sorry about the confusion on this. The 0.6.0 release had actually been prepared before Christmas last year and the release was delayed until last week. The extra field in the ChildCollider will be in the next release tentatively due about 6 weeks after the last one.
    There could have been a quick and dirty addition in the 0.6.0 but it might have created more support questions than answers as full time for testing was not available.

    I do have one issue to ponder though. In creating a CompoundCollider each Entity baked with the Collider children will be the one available at conversation time. If I use a compound body as a prefab and create a bunch of instances that all reference the same CompoundCollider, all of those instances will have Collider children referencing Entities in the prefab hierarchy, not the instance.
    I can imagine some use cases where you want the child Entity in the common prefab hierarchy (e.g. find maximum health of child Entity in common prefab), and I can also imagine some use cases when you want the child Entity in the instance hierarchy (e.g. find current health of child Entity in instance).
    The mouse hover highlighting in the movie I posted above, was initially only tested was all on unique bodies that where not spawned. When I realised and spawned a bunch of compound bodies, the naïve mouse code was highlighting the prefab children. To get around this (and to avoid creating unique CompoundColliders for each instance) I had the mouse hover code check that the hit.Entity (i.e. root entity of the hit child) matched the root parent Entity of the Child.Entity. If they didn't then the mouse hover had hit an instance. If an instance was hit, then I can use the LinkedEntityGroup on the two root Entities to remap the prefab child Entity to the instance child Entity. In production a more specific faster hashmap can achieve this job. Making unique CompoundColliders for each instance would be an inefficient use of memory.
    Do folk have an thoughts/ideas/concerns around this?
     
  22. BobFlame

    BobFlame

    Joined:
    Nov 12, 2018
    Posts:
    95
    I understand your concern. But in my situation, my compoundcollider is not prefab. It's a building spaceship game. The spaceship as a compoundcollider is built from multiple module as childcollider. It's generated at runtime hence it's must be a reference to the instance.
    Although I can bypass this problem by register dynamic buffers, it will be really convenience if there is a referece to original collider entity in API.
    In my opinion, to achive this, physics API should have a CompoundCollider.Create method, take both arguments of NativeArray<ColliderBlobInstance>, and NativeArray<Entity> in addition.
     
  23. Occuros

    Occuros

    Joined:
    Sep 4, 2018
    Posts:
    300
    For me, the most intuitive would be if the 'ShapeEntity' would be the one from the instance rather than the prefab as a default.

    It is more likely that I need the instance entity to manipulate rather than the one from the prefab.
     
    steveeHavok likes this.
  24. steveeHavok

    steveeHavok

    Joined:
    Mar 19, 2019
    Posts:
    481
    In this case, the ColliderBlobInstance would just include an extra Entity field in the struct so you won't need the extra NativeArray<Entity>.

    You can achieve what you need. You'll be able to clone the compound collider and remap the entities. I can see about adding a component extension to make things super simple. The main problem is that cloning and tweaking could be a significant memory overhead, especially for large compounds.
     
    BobFlame likes this.
  25. mk1987

    mk1987

    Joined:
    Mar 18, 2019
    Posts:
    53
    Hi @steveeHavok, i was wondering if this function is due out soon or is part of a bigger update down the line? I have very similar use case to the above for both weapons damage and some prebaking of a voxel based damage system (as voxels damage will vary based on underlying mesh surface area and its associated child entity). If its not due anytime soon i'll make a hack and duplicate and convert the colliders unparented to do what i need to for the prebaking and have a think for the weapons damage one.
     
  26. MarcelArioli

    MarcelArioli

    Joined:
    May 31, 2014
    Posts:
    28
    My usecase would be a ship with multiple children that each have a different setup (as trigger), one child-trigger might detect overlaps with other ships, another one detects overlaps with the harbor to dock properly. I'd like to add a DynamicBuffer<TriggerOverlaps> to these child-entities to then have specific systems to handle these overlaps rather than a monolithic triggerjob. So I need to know which child entity overlaps inside the ITriggerEventsJob. I was hoping the ColliderKey would allow me to extract that information, but it doesn't seem possible.

    Therefore also looking forward to an update :)
     
  27. mk1987

    mk1987

    Joined:
    Mar 18, 2019
    Posts:
    53
    @MarcelArioli When i was experimenting if you add physics step or physics body (cant remember which) to the child, the child collider is associated with the child entity not its parent and the child seemed to track with the parent body. You could use tags on the child collider to decide how the trigger should behave. Not an ideal solution since i'd imagine its getting the physics system to do more than it needs to but for prototyping and getting other systems built round it that may help.
     
  28. MarcelArioli

    MarcelArioli

    Joined:
    May 31, 2014
    Posts:
    28
    @mk1987 Thanks for trying to help :)
    In the meanwhile I came up with another solution (because if you add a PhysicsBody to the child, it gets unparented, so that's no solution for me)

    I use a DynamicBuffer<ColliderKeyMapping> on the root with
    struct ColliderKeyMapping : IBufferElementData
    {
    public ColliderKey ChildKey;
    public Entity ChildEntity;
    }

    I populate that data only once. This allows me to get the entity in a ITriggerEventsJob.
    The only problem is, that to find the ChildEntity, I can only use the child colliders RigidTransform within the compound collider, so each child needs to have a unique position for this mapping to work.
     
  29. mk1987

    mk1987

    Joined:
    Mar 18, 2019
    Posts:
    53
    @MarcelArioli no problem, i have just run a model and the child at least in my version doesn't get unparented once the entity is converted and keeps its own independent collider ID. I havnt tested which entity it picks up on collision but i assume it would be the child in this instance since it has a collider ID component.
     
  30. MarcelArioli

    MarcelArioli

    Joined:
    May 31, 2014
    Posts:
    28
    there might be a difference between a child having a physics body and a child AND a parent each having a physics body (which is my case). In the second case, the physics body on the child even shows a warning that it will get unparented to be part of the simulation
     
  31. mk1987

    mk1987

    Joined:
    Mar 18, 2019
    Posts:
    53
    I checked and you are right it does come up with that warning, however in specific use cases it doesnt appear to be the case.

    If i put the child motion type to static (with the parent in my case being kinematic). At least with box colliders the entity is generated with its own collider and parented to another physics object, this is using GameObjectConversionUtility but it might be different using convert to entity. Not assessed the behaviour too heavily as i havnt needed to.
     
  32. BobFlame

    BobFlame

    Joined:
    Nov 12, 2018
    Posts:
    95
    @mk1987 I have implement my own collider child redirection system some time ago. If you would like to know about it.

    I create compound collider in system, and register your own child buffer to the compound entity. (you could assign it to prefab, so the blob could be reused), don't forget to dispose the blob.

    Also you need to create a collision job (ICollisionEventsJob) to receive the collision event. Here is the key code for getting child in job:
    Code (CSharp):
    1.  
    2.         [MethodImpl(MethodImplOptions.AggressiveInlining)]
    3.         public static Entity GetChild(in this DynamicBuffer<CollideChild> children, PhysicsCollider collider, ColliderKey colliderKey)
    4.         {
    5.             var numKeyBits = collider.Value.Value.NumColliderKeyBits;
    6.             colliderKey.PopSubKey(numKeyBits, out uint childIndex);
    7.             return children[(int)childIndex].child;
    8.         }
    If you need trigger event, you could also register a job.

    Along with direction event to children, I aslo implement an arbitary redirection system, in case you have two rigidbodys, but in gamelogic it should be treated as single.
     
    Last edited: Oct 26, 2021
  33. MarcelArioli

    MarcelArioli

    Joined:
    May 31, 2014
    Posts:
    28
    @BobFlame, thanks for your insights! May I ask, how do you populate your dynamic buffer (CollideChild) ? How do you ensure that the order in that buffer is in sync with what the colliderKey's childIndex points to ?
     
  34. BobFlame

    BobFlame

    Joined:
    Nov 12, 2018
    Posts:
    95
    It's up to you to decide how and when to build the compound collider. When you build the compound collider, you populate the dynamic buffer(ColliderChild) at the same time. So the sequence of compound child and the buffer should be the same.

    You could design another dynamic buffer to accept rebuild request (e.g. CollideChildInput) on the compound entity, or you could design a component (e.g. CollideParent) on child, and use system to query and rebuild the compound collider and the CollideChild buffer.
     
  35. MarcelArioli

    MarcelArioli

    Joined:
    May 31, 2014
    Posts:
    28
    Thanks for the reply! So the only thing I don't yet fully understand is, do you replace the default compound collider - creation done by the physics package itself ?
     
  36. BobFlame

    BobFlame

    Joined:
    Nov 12, 2018
    Posts:
    95
    Ahha, yes. Because i need to rescale my convex collider in runtime, I made myself collider data container, authoring monobehavior and conversion flow.
    But considering new info from unity, I don't know whether it is wise to do so now.
    https://forum.unity.com/threads/is-dots-being-abandoned.1183621/#post-7594702
     
  37. Dan-Foster

    Dan-Foster

    Joined:
    Aug 7, 2019
    Posts:
    53
    I've just hit a similar problem when trying to get a collider's entity from a compound collider.

    I realised that the rigid body entity had on it a PhysicsColliderKeyEntityPair buffer, which looks like this.

    Code (CSharp):
    1. public struct PhysicsColliderKeyEntityPair : IBufferElementData
    2. {
    3.     public ColliderKey Key;
    4.     public Entity Entity;
    5. }
    So I'm now able to do something like the following with a RaycastHit.

    Code (CSharp):
    1. Unity.Physics.RaycastHit closestHit = hits[hitIndex];
    2. PlayerBodyPart hitBodyPart = PlayerBodyPart.Body; // The enum value that I'm looking for.
    3. var key = closestHit.ColliderKey.Value;
    4. var keyEntityPairBuffer = keyEntityPairBufferData[closestHit.Entity]; // BufferFromEntity<PhysicsColliderKeyEntityPair>
    5. for( int j = keyEntityPairBuffer.Length - 1; j >= 0; --j )
    6. {
    7.     PhysicsColliderKeyEntityPair current = keyEntityPairBuffer[j];
    8.     if( current.Key.Value == key
    9.         && playerBodyPartData.TryGetComponent( current.Entity, out PlayerBodyPartComponent bodyPart ) )
    10.     {
    11.         hitBodyPart = bodyPart.Value;
    12.     }
    13. }
    ( Using Entities 0.50.1 + Unity Physics 0.50.0 ).

    Hope that this helps anyone else trying to get an Entity from a collider in a raycast hit!
    Dan
     
    Wobbers, Skibitsky and Occuros like this.
  38. ScallyGames

    ScallyGames

    Joined:
    Sep 10, 2012
    Posts:
    44
    @steveeHavok did this ever make the cut?

    If not, do you have any example code for the LinkedEntityGroup lookup you described?


    After struggling with this issue for a while now I have finally found the ChildCollider.Entity API but it seems I'm now running into the problem of getting a reference to the prefab entities when I would need the instance entity (which I assume would be the more common (and actually quite common in general) use case.

    So far I've still only seen weird multi-line hacks to retrieve the instance entity of a specific child collider when I'd expect it to be a simple function call / property access.
     
  39. daniel-holz

    daniel-holz

    Unity Technologies

    Joined:
    Sep 17, 2021
    Posts:
    277