Issue: all colliders are merged into a single compound collider. The layers are also merged. This creates issues for many use cases.
Use case 1: Rotating child colliders as separate entities is not possible with compound colliders. Example 1: Tank turret Example 2: Animated characters example, a character control capsule collider. Depending on the animation crawling/standing the hitboxes may become obscured by the capsule collider.
Use case 2: Separating hitboxes from rigidbody physics interaction. Example 1: Wheels or tank track hurt boxes. These boxes often collide with terrain when part of a compound collider. This behavior is undesirable. These boxes are only used to determine if tires or tank tracks are damaged. Having these colliders as part of a compound collider cause lots of undesired collision interactions that become part of the rigidbody solver. Example 2: Animated character’s hitboxes such as a large head damage box.
Use case 3: Colliders within colliders. Example 1: Energy shield that protects the unit Example 2: Animated characters which have a capsule collider as a rigidbody. Inside this, capsule you attach arm or leg hitboxes to bones. Since the layers are all merged raycasts will never hit the internal arm or leg hitboxes. Example 3: A hitbox that is partly blocked at certain angles.
Use case 4: Increased raycast complexity and unexpected results. Example 1: Raycasting only against a specific layer. This is possible but only if you expect the compound collider to be a convex hull and you are just trying to get a segment of that hull’s surface. Even then requiring a ColliderKey results in increased complexity. This still does not solve the issue of other children blocking the raycast.
this also effecting me, may case is, a building part with multiple Socket, these socket collider can be detected by raycast to provide snapping functionality (these sockets only use for physics query)
In my use cases, the worst part is that the collider contains the categories / layer information.
So the collider needs to be cloned any time you want to change its collision filter individually (or be set to unique).
If I ever saw something that should be an IComponentData, it’s CollisionFilter.
It completely falls apart from there once compound colliders are involved. At least some sort of control over which colliders are globbed together and which become their own entities would be a huge improvement to the authoring workflow.
Compound colliders definitely need to improve or some other form of compound needs to be introduced.
Games like besiege, trailmakers where you want to have dynamically added/removed parts are really complicated work to achieve in ECS. The compound collider gets out of control when you have a few hundred objects in it
Thanks for the feedback everyone. Sorry for the late response. There has been a lot of work put into colliders over the last year and this has been a lower priority, but I do understand all your concerns.
I’ll try to go through them one by one and then we can discuss what could be done to improve the situation.
To that end, I’ll use @TheOtherMonarch 's bullet points above for structure, keeping the topics in seperate replies to facilitate the discussion, and include any additional feedback that was provided in this thread.
Use case 1: Transforming child colliders as entities
My understanding is that you would like to model a hierarchy of kinematic rigid bodies which can all follow one root, as in your tank example, and move them relative to each other with ease.
Correct me if I’m wrong, but this case can be achieved (with a caveat, which I’ll detail below) by adding additional kinematic Rigidbody authoring components. This will create individually controllable, kinematic rigid body entities, enabling easy transformation of the individual parts.
However, due to the flattening of the game objects hierarchy into top-level rigid bodies, we can no longer benefit from parent-child relationships anymore, making the movement of the entire mechanism (the tank) cumbersome, as well as making modeling of relative motion of children relative to their parent (see the turret) difficult.
So, for this case, I would propose something that has been suggested previously in this forum, which is to allow for kinematic rigid bodies in a hierarchy. With this feature, kinematic rigid bodies would follow their parent entity, which can itself be kinematic or even dynamic, making it possible to model the tank use case with ease.
Let me know what you think about that.
Use case 2: @TheOtherMonarch : I’m not sure I understand that one. Could you provide some more details?
It sounds like something that can be modelled using the hierarchical kinematic bodies I mentioned above combined with trigger colliders and maybe collision filters (Rigidbody and Collider layer overrides) which don’t cause physical contacts. But I’m not sure.
If I understand correctly, you would like to have a combination of colliders in a physically connected object here all of which have a potentially different purpose:
actual physical colliders
hit boxes
…
When you do a raycast, you want to be able to easily exclude specific types of colliders here without the different types occluding each other, such as either only casting on hitboxes or only on physical colliders.
If that is the case, again, the solution for use case 1 combined with collision filters might do the job here, right? In raycasts and other queries the collision filter can be provided for the corresponding query filtering.
With the ability to mark individual colliders during baking with additional Rigidbody authoring components (see use case 1), compound colliders would in this situation only be created for objects for which you don’t mind that their colliders are merged together via compounds (which is really just a performance improvement), and you therefore wouldn’t need to drill into compound colliders anymore to pull all that apart at runtime painstakingly.
If we also elevate collision filters to the component level, as suggested by @Thygrrr , all that would be made even easier for dynamic cases in which collision filters are runtime modified.
If we make collision filters components, which makes a whole lot of sense to me, given the need for them to be runtime modified in a large set of use cases, we would only need embedded collision filters in compounds for the child colliders. The top level compound collision filter would still remain a component.
Let me know if that makes sense.
Use case 1: The type of hitboxes I am considering are similar to the Counter-Strike head hitboxes. They do not have to detect kinematic collisions with other hitboxes. In fact, interacting with other hitboxes / colliders is a negative. They only need to interact with raycasts from projectiles and OverlapSpheres from explosions.
My vehicles use my own kinematic controller and have their collision layer set so that they only interact with the terrain and other main colliders. Vehicles use a single suspended box collider for the controller. The suspension uses a spring with my own integrator implementation and is raycast base. In addition to the main kinematic collider, a half dozen hitboxes are attached in the hierarchy to detect projectiles and explosions only.
Use case 2: Is about separating hit boxes using layers.
Use case 3: Is purely a side effects of Compound colliders. Compound colliders only return a single hit rather than returning all intersecting sub-colliders when interacting with a raycast. See below case 4.
Use case 4: Allowing Compound colliders to have multiple layers would be an enhancement of Compound colliders. In some cases, it could be possible to leave the hitboxes as part of the compound collider but allow for separate layers. For example, if your hitboxes do not need to move independently. Such as the engine inside our tank’s hull. In my case crew compartment hitboxes, armor hitboxes, engine hitboxes and ammo hit boxes are all enclosed within the main kinematic collider and never move separately from the main collider.
For damage processing a ray is shot through all of the hitboxes. Then the resulting hits are processed to account for armor. While the main collider is on a different layer. I don’t think in my case simply allowing compound colliders to have multiple layers would be enough since all of the different types of hitboxes are on the same layer and a raycast would not return all intersecting sub-colliders. Also, I need to know which hitbox type is hit which may be possible but is not as straightforward. See above case 3.
Kinematic child Rigidbodys: I don’t use the hitboxes for physics interactions. A kinematic Rigidbody is more than I need, I think. I only require hit detection from raycasts and OverlapSpheres. Interactions between hitboxes and other hitboxes / colliders is a negative. I separate out the main collider from interacting with the child hitboxes with layers.
Kinematic child Rigidbodys would be nice, but I imagine that they would serve a different purpose from hitboxes and be more resource intensive.
Use cases 1 - 3:
Got it. So, simply splitting the colliders that are currently batched into compound colliders up into separate entities while allowing the “triggers” to follow the “dynamically simulated” or otherwise moving entities would also here get the job done, right?
I am not suggesting that these additional entities you would have for your triggers would all behave like physically colliding rigid bodies (see your statement/concern in Kinematic child Rigidbodys), but simply that you would have (1) clear control at authoring time over which colliders do get batched together and which don’t, and (2) allow attaching “trigger entities” to other moving entities (which could be dynamically simulated or manually driven, aka, kinematic)
Let’s ignore the performance implications of this added number of entities for a moment.
Ideally, you should be able to specify at authoring time that a given hierarchy of colliders can all go into a compound collider because you won’t need to get more granular information from the children (for hit boxes and what not). They can all behave the same on your end. The behavior options are:
the entire collider behaves as a pure trigger, and it can be inside a dynamically simulated rigid body (say jointed to something else), a kinematic rigid body (moved around by the user, or with my suggestion following some parent entity) or a static rigid body (not moving, but can optionally be moved by the user on occasion if required)
the CollisionResponse in its Unity.Physics.Material is set to CollisionResponsePolicy.RaiseTriggerEvents
the entire collider behaves as a fully dynamic rigid body collider, that optionally also raises trigger events
the CollisionResponse in its Unity.Physics.Material is set to CollisionResponsePolicy.Collide and optionally to CollisionResponsePolicy.CollideRaiseCollisionEvents.
the entire collider behaves as a fully static rigid body collider, that optionally also raises trigger events
the CollisionResponse in its Unity.Physics.Material is set to CollisionResponsePolicy.Collide and optionally to CollisionResponsePolicy.CollideRaiseCollisionEvents.
the entire collider behaves as a fully kinematic rigid body collider, that optionally also raises trigger events
the CollisionResponse in its Unity.Physics.Material is set to CollisionResponsePolicy.Collide and optionally to CollisionResponsePolicy.CollideRaiseCollisionEvents.
So, as it stands, if you want to have a combination of colliders with different behavior types in your objects and want to avoid drilling into compound colliders, as it stands, you would need to add additional entities, each with a collider that uses a different Unity.Physics.Material.CollisionResponse type and optionally a different CollisionFilter.
From what I understand, this is your primary use case and this is where your main concern with compound colliders lies since they batch things up in a way that it’s hard to get the required behavioral granularity.
Say you have the actual “head” collider, plus a “head hitbox”. So the head collider should act as a type 2 above. But the head hitbox collider should act as a kinematic (!) type 1 above.
Today, entities can only ever hold one collider within their PhysicsCollider component, which either is a “leaf” collider or a compound. We could of course make changes in the engine and allow a PhysicsCollider component to contain a dynamic buffer of colliders. But that would also force users to check for this case in their code, just like they need to do today for compounds.
With my suggestion of allowing kinematic colliders to follow their parent, you could have a parent entity with type 2 collider for the head, and attach to it a kinematic child entity with type 1 collider for the head hitbox. The head collider would then automatically follow the head collider. And both colliders can be processed within your user code at the top entity level without having to drill into the entity and deal with arrays of colliders or compounds.
Use case 4:
If I understand your example correctly, you need two information sets here:
Is the main tank chassis hit, represented by a physical collider, e.g., of type 2)?
If the main tank chassis is hit, are there any tank components within the tank chassis hit, all represented by type 1 colliders?
Also, you state that all the tank component colliders don’t move relative to each other (and also not relative to the chassis).
Assigning different layers to different colliders within a compound is possible already today. Simply using a Collider authoring component for each and specifying the corresponding “Layer Overrides” allows for that.
As you already pointed out, it is possible to gather all hits from a compound collider using the following two marked query functions (a “all hits” one, and a “generic collector” one):
I suppose there is no issue here. Given that you can specify a CollisionFilter in the RaycastInput passed into the CastRay functions, you can have the ray collide with any layers you want it to. That means it will collide only with the children that sit on the corresponding layers.
You state that you “need to know which hitbox type is hit which may be possible but is not as straightforward”.
Are you referring to the RaycastHit results here? Are you missing some information in there which we could simply add for your convenience? Maybe just adding a CollisionFilter to the RaycastHit result, which would be the CollisionFilter of the collider that was hit, could help here. That would give you the layer information you are interested in I think.
My root collider is using CollisionResponsePolicy.Collide and my child hitboxes are all using CollisionResponsePolicy.None. Since CollisionResponsePolicy.None will still pick up raycast hits. The root collider is also on a different layer from the children. Each of the children is its own entity and has a good deal of IComponentData such as armor thickness etc.
Some of the children can also rotate, for example tank turrets. I want to use skeletal animation rather than MonoBehaviour for animations which will also affect hitboxes.
I don’t actually currently have any compound colliders. The only change I would like is a way to make baking easier. That it should be possible to opt out of compound collider creation.
It’s funny because I was just about to write something about this because I realized that I missed the CollisionResponsePolicy.None type for your use case entirely, which is the perfect choice for cases where you just want to run your own queries on specific objects.
So, for this setup, you just manually create colliders that use CollisionResponsePolicy.None I suppose, rather than relying on the baking code for the provided authoring components.
How do you move these colliders currently?
This is actually quite interesting, because the compound colliders are really only useful for performance improvements of colliders which are in the collision world, meaning, you want them to raise trigger events or get physical contacts from them, neither of which is the case here.
Ideally, these “None” colliders shouldn’t even be in the collision world unless the user wants to do queries on the entire collision world and expects them to be included. If they were not in the collision world, not having compounds for these would really not be a big deal for performance.
That’s interesting. The engine considers these entities as static colliders, which do support being part of a hierarchy (their LocalToWorld component is used rather than their LocalTransform for obtaining their latest transformation at the beginning of a frame).
So when these move around, theoretically your static broadphase gets rebuilt, which is suboptimal.
Do you mind sharing a quick profiler screenshot of the jobs leading up to the ParallelCreateContactsJobs?
Also, do you need to add a PhysicsWorldIndex here for these colliders with policy “None”? In other words, do you need them to be in the collision world for full collision world queries? Or do you raycast directly on known tank entities?
This sounds like something that will lead to subtle bugs. I think giving up a little performance for consistency is well worth it. Hopefully, this is addressed in general not just for CollisionResponsePolicy.None but for all static colliders as part of the Unification of Entities and GameObjects.
That was not what I was expecting. I have found both dynamic and static CollisionResponsePolicy.None very useful. My application is extremely GPU bound so that is probably why I have not noticed the impact. I should run some stress tests.
I am only baking prefabs. At least for the default world they are behaving just like normal colliders when I instantiate them. I need to check how they behave with multiple worlds. What is the recommended practice?
I am running into these limitations too. I am attempting to create something that uses use case 3. I have a spacecraft that is created with compounded colliders. This works great for the spaceships shape but the ship also has a shield that is created out of a collider that is a bit larger than the ship. The gameplay requires the shield to be able to block raycasts to intercept damage, be able to be disable if damaged (allowing the ship hull be damaged), and also collide with geometry and impact the physical simulation of the ship.
The automatic handling of compound colliders breaks this use case since it becomes part of the ships collider. I have worked around it by making the shield its own physics object where I sync its position with the ship every frame. I’ve worked around the ability to disable the collider by assigning a null collider and swapping back to the original assigned one when necessary. One issue remains though, the shield needs to still impact the collision of the ship when its active and my current solution doesn’t allow for that. I’m left with doing something like detect the collisions with the ship’s compound collider and do a bunch of Component/Buffer lookups to see if the shield is active to know where to apply the damage. I will probably do something like this but it would be nice the shield’s collision could power this functionality as this solution is not ideal code and will not match the shield’s collider’s shape.
Edit: One more note on this. Instead of the match position every frame solution I first tried using a RigidJoint. This worked fine with a low entity count but as soon as I added more entities the joint broke randomly, causing the shield to rotate madly for many entities. There seems to be a bug currently with joints.
This is by far the biggest roadblock for me currently. Animations, vfx, … missing is less of a problem than this, all workarounds get complicated fast.