Search Unity

I think... I want a trigger that doesn't raise trigger events?

Discussion in 'DOTS Physics' started by PhilSA, Dec 3, 2019.

  1. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,739
    Here's the situation:
    • I'm making a character controller
    • Because of the high level of customization of collision response, I want to handle everything through CalculateDistance and ColliderCasts. If a physics box flies off against my character, I want to detect the collision with CalculateDistance and generate contacts manually.
      • Maybe I'll want my character to act like it has infinite mass relatively to the box
      • Maybe I'll want to imitate a 1:1 mass ratio
      • Maybe I'll want to ignore collisions with that specific box
    • That means my PhysicsShape must be a trigger, so that things don't just automatically collide with it
    • I want this to be as performant as it can possibly be, so I don't want the cost of raising trigger events. I'll already be doing a CalculateDistance every frame to get those, so it would be redundant
    I cant accomplish these with BodyPairs modification and ContactJacobians modification jobs, because that would mean using dynamic rigidbodies for my characters, and that comes with many caveats. So, I really just want a PhysicsShape that doesn't collide with things, and doesn't raise any events. Is this possible at the moment?

    also, am I right in assuming that DOTS physics lets us generate contacts as described above?
     
    Last edited: Dec 3, 2019
    Mr-Mechanical likes this.
  2. steveeHavok

    steveeHavok

    Joined:
    Mar 19, 2019
    Posts:
    480
    You can just have a dynamic body with no collider and only motion information (i.e. just a PhysicsVelocity component).
    It isn't something you can setup in the editor. We possibly could add a Shape Type of Null if folk think its useful.

    We did have a demo adding random contact points back in the GDC timeframe. Things have changed a bit but I'll see whats needed to resurrect it. That said, I'm assuming you don't want to be making changes with a local package of Unity Physics? Also, will you want it to work with Havok Physics as well.
     
  3. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,739
    In my case I need a physics shape (so I can do colliderCasts with it, give it collisionFilters, etc...), but I just need it to not react to any collisions and not fire any events whatsoever. I need it to serve exclusively as something to do cast/distance queries with, and to have no performance cost aside from that

    The end goal is to make this an asset store package, so yeah I need to not mod the packages, and it'd be good for it to work with Havok
     
    Last edited: Dec 4, 2019
  4. steveeHavok

    steveeHavok

    Joined:
    Mar 19, 2019
    Posts:
    480
    Just so I understand things fully, the need for a PhysicsShape is for the end user to be able to setup a shape to be used with the character controller?
    Obviously, setting the CollisionFilter BelongsTo & CollidesWith to Nothing gives you want you want currently, though do you want the user to be able to set up filtering for the character shape as well? If that is the case, then I assume you'll still have your own custom components for the CC? If you had you own conversation system for these components as well, then have it [UpdateAfter(typeof(PhysicsBodyConversionSystem)),UpdateAfter(typeof(LegacyRigidbodyConversionSystem))] so the Physics is already converted. Then you could copy the user defined filter information into your own, say Casting Collision Filter Component, and set the PhysicsCollider filter to Nothing. You could even go one set further and extract all the information you need for casting from the converted Physics components into your own components, and then set the PhysicsCollider.Value to null, or remove it altogether.
    Does this make sense or am I still missing something?

    Adding your own contacts points, is still the main missing piece though.

    That reminds me, I must grab a copy of your current CC package for reference.
     
    PhilSA likes this.
  5. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,739
    Huh... that makes sense. I think it would definitely do what I want!

    Although for the time being I'll probably just stick to making my CC be a regular collider and not do anything crazy with custom rigidbody dynamics, since contacts generation is missing. It's something I couldn't do in my previous CC either, but I wanted to experiment with the idea

    Thanks!
     
    Last edited: Dec 4, 2019
  6. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,311
    If you are going for equivalent functionality to KCC, I'm curious what from dynamics you need at all?

    There are a number of pros and cons to whether to use static bodies for this, and they are somewhat context specific. I think the ideal for a first order controller here is don't use dynamic features in the core. But don't exclude users from doing so. Or not. Or changing the body type between dynamic and static.

    For example I sorted out custom static worlds a while back, and they have been very key to scaling to 100k+ colliders per scene. First order controller I'd stick that in a feature level static collision world. But that's our game. Others are going to want dynamic body interactions at some level I'm sure.
     
  7. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,739
    I want to research the possibility of having a CC that feels just as good and "exact" as a kinematic one, but also is capable of interacting with dynamics realistically (with complete user control over mass ratios). The plan from my first post was my idea for that.

    I may also resort to making a CC option that uses a dynamic rigidbody, though. I was about to give you a list of downsides.... but the more I think about it, the more I feel like they can all potentially be solved in some way, when combined with kinematic CC movement hit detection.

    I'll have to experiment with this a bit
     
  8. Rory_Havok

    Rory_Havok

    Joined:
    Jun 25, 2018
    Posts:
    70
    Just some thoughts @PhilSA, may be helpul in your experimentation:

    I'm assuming that you probably want the character capsule to be hit by raycasts etc (or at least have that option), and for characters to be able to collide with each other, which means you want them in the world in some form as opposed to external things that only query the world but can't be queried themselves.

    I would try something like this:

    * The broadphase returns all the overlapping pairs. For any pairs involving a character, you don't want it doing its usual collision response. And you don't necessarily want to set its filter to null to avoid that, becuase then you have to undo that at some point when you query or get queried. So I would use a IBodyPairsJob.

    * When your IBodyPairsJob sees a pair involving a character you can then dispatch that pair to your own character-vs-rb or chraracter-vs-character jobs. The nice thing is the broadphase already told you which bodies are nearby so when you do your CalculateDistance() etc you can do it directly on the relevant bodies rather than querying the world each time. The other especially nice thing is you can run your jobs in parallel with the usual narrowphase and jacbobian building jobs.

    * You could choose to have your jobs inject either contacts or jacobians into the system to get a collision repsonse. You probably want to inject jacobians since that gives you all the control over mass ratios etc that you want. Of course, that ability to inject is the missing piece right now but lets assume that becomes possible again.. :)
    So basically something like this:

    upload_2019-12-6_17-3-48.png

    * In this scenario it probably makes sense to have the characters be regular dynamic rigid bodies since you have full control over how they are solved. Gravity would be applied by the solver too, not sure if you want to control that yourself or not. You could probably use kinematic bodies too, but one issue is the current MassFactors don't allow you to turn zero inverse mass into non-zero only the other way around. (Note that if you made it a static body the broadphase won't produce static-static pairs, and the solver won't be able to move it because there is no velocity data.)
     
  9. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,739
    For some reason, it didn't cross my mind that kinematic bodies would have contact jacobians too, just like dynamic bodies!

    Thanks for the insight. I can see now that my idea would fail because of the raycast problem. I'll start playing around with both the dynamic and the kinematic aporoach to custom physics response, and I'll see where this goes.

    I think I remember hitting a roadblock at some point when trying to implement a dynamic rigidbody CC that behaved exactly like I wanted a few weeks ago, but I can't remember what that roadblock was right now. Could be that I just didn't think this through

    Two questions though:
    • Is the presence of a PhysicsVelocity component and absence of PhysicsMass the only requirement for making a body "kinematic" as opposed to "static"? No custom flags or anything of the sort?
    • Out of curiosity, are there ways to make raycasts hit triggers? I'm not really thinking about using triggers for CCs anymore but I'd like to know
     
    Last edited: Dec 7, 2019
  10. Rory_Havok

    Rory_Havok

    Joined:
    Jun 25, 2018
    Posts:
    70
    Yes a PhysicsVelocity by itself makes a body kinematic (= infinte mass). Adding a PhysicsMass as well makes it dynamic (= finite mass).

    Raycasts already hit triggers, if the collision filters allow it. The only thing the trigger flag actually does is produce a different type of jacobian for solving - it has no effect on queries. (However we may add an easy way for queries to opt OUT of hitting triggers, since that is a common request.)
     
    PhilSA and florianhanke like this.
  11. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,739
    Does this look like the correct way to do a calculateDistance on a specific collider (in a job), as opposed to on the whole world?
    Code (CSharp):
    1. // Create input
    2. ColliderDistanceInput distanceInput = new ColliderDistanceInput
    3. {
    4.     Collider = physicsCollider.ColliderPtr,
    5.     MaxDistance = 0f,
    6.     Transform = new RigidTransform(rotation.Value, translation.Value),
    7. };
    8.  
    9. // Create collector
    10. characterDistanceHitsBuffer.Clear();
    11. DistanceHitsDynamicBufferCollector distanceHitsCollector = new DistanceHitsDynamicBufferCollector(0f, ref characterDistanceHitsBuffer);
    12.  
    13. // Calculate distance between our character collider (the "physicsCollider" assigned in the ColliderDistanceInput) and the hit collider ("tmpHit")
    14. PhysicsWorld.Bodies[tmpHit.RigidBodyIndex].CalculateDistance(distanceInput, ref distanceHitsCollector);
    "distanceHitsCollector" is never receiving any "AddHit" and I'm trying to find out why. It's a copy of AllHitsCollector, but using a DynamicBuffer instead of a NativeList

    I'm taking inspiration from what you said but this case is slightly different. In the kinematic version of the CC, we already do a colliderCast early in the frame for ground probing. I'm using this opportunity for also decolliding from any hits of that cast that had a fraction <= 0f. CalculateDistance will give me the distance that I'll use for creating SurfaceConstraints which will then be used in SimplexSolver

    EDIT:
    I can confirm that my custom collector and my ColliderDistanceInput work just as expected, because if I try replacing the "PhysicsWorld.Bodies[tmpHit.RigidBodyIndex].CalculateDistance" with simply "PhysicsWorld.CalculateDistance", everything works as expected. I'd still very much prefer to figure out calculating distance between only two colliders, though. For performance reasons
     
    Last edited: Dec 8, 2019
  12. Rory_Havok

    Rory_Havok

    Joined:
    Jun 25, 2018
    Posts:
    70
    Sorry, there is currently a bug where the RigidBody query implemenations do not transform the world space query transform into the local space of the body. It was mentioned somewhere in the giant thread (https://forum.unity.com/threads/unity-physics-discussion.646486).

    It is easy to workaround, by doing the transformation yourself. I don't have an example right now (in a hurry). Remember to transform the result back into world space too. If you step into the world query implementation you will see it doing the same thing.
     
    florianhanke and PhilSA like this.
  13. Mr-Mechanical

    Mr-Mechanical

    Joined:
    May 31, 2015
    Posts:
    507
    I am thankful for this thread as I incidentally have a very similar use case as @PhilSA where objects are kinematic and I am handling the narrowphase myself. In your diagram, if I don't need collision response or integration from unity physics (literally all physics objects are going through the custom pipeline), can I safely delete the scheduling code for BuildJacobians/Solver/Integrator and just handle everything I need in my custom narrowphase?

    (I don't need collision response/integration/solver only generating the collision data from kinematic objects in the custom narrowphase)

    I outline my plans for a simple custom closestpoints-based [non-EPA] narrowphase here:
    https://forum.unity.com/threads/for-custom-physics-super-simplify-collision-detection-to-only-
    use-closest-points-gjk-with-no-epa.790451/


    This is the scheduling code I would want to remove (if it is confirmed it is safe to do so) and I hoping to have a custom narrowphase:
    Code (CSharp):
    1.  
    2. // Create contact Jacobians
    3. handle = Solver.ScheduleBuildContactJacobiansJobs(ref input.World.DynamicsWorld, input.TimeStep, math.length(input.Gravity), ref m_Context, handle);
    4. // Solve all Jacobians
    5. handle = Solver.ScheduleSolveJacobiansJobs(ref input.World.DynamicsWorld, input.TimeStep, input.NumSolverIterations, ref m_Context, handle);
    6. // Integrate motions
    7. handle = Integrator.ScheduleIntegrateJobs(ref input.World.DynamicsWorld, input.TimeStep, handle);
    TL;DR
    Can I remove the code above to remove functionaliy without worrying?
     
    Last edited: Dec 8, 2019
  14. Mr-Mechanical

    Mr-Mechanical

    Joined:
    May 31, 2015
    Posts:
    507
    Actually, I don't think I have to delete anything if I could just reroute the pairs as described by @Rory_Havok (then the rest of the phases should be ignored by default), though I struggling to figure out how to dispatch the pairs to go our own custom jobs exclusively (without having the pair being processed by both the custom job and the standard job). May someone elaborate in slightly further detail on how to reroute pairs to custom jobs, this advice is extremely useful for these kinds of use cases. I really like this idea proposed by @Rory_Havok

    Thanks a lot.
     
  15. Rory_Havok

    Rory_Havok

    Joined:
    Jun 25, 2018
    Posts:
    70
    @Mr-Mechanical:

    1. Inject an IBodyPairsJob as per the example at https://github.com/Unity-Technologi...ify/Scripts/ModifyBroadphasePairsBehaviour.cs

    2. In your IBodyPairsJob.Execute() implementation: For any pair you want to have different behavior, copy the pair elsewhere and call ModifiableBodyPair.Disable() to remove from the normal pipeline (as per example above)

    3. Do whatever you want with your copy of the pair. You probably want to send it to a custom NativeStream and have a subsequent custom job process them as you wish. So just make your SimulationCallbacks.Callback implementation inject a bunch of jobs instead of one.
     
    Mr-Mechanical likes this.
  16. Mr-Mechanical

    Mr-Mechanical

    Joined:
    May 31, 2015
    Posts:
    507
    This is really great, thanks a lot! This all makes sense, the only thing is I am new to NativeStreams so this is something I may want to investigate. If there was a convenient example for this I would be grateful for it.
     
  17. Mr-Mechanical

    Mr-Mechanical

    Joined:
    May 31, 2015
    Posts:
    507
    How do you determine pairs are of a certain type, is it through tagged entities? How should determining the type work? Thanks a lot this advice is extremely helpful for progress on my project.
     
  18. Rory_Havok

    Rory_Havok

    Joined:
    Jun 25, 2018
    Posts:
    70
    ModifiableBodyPair gives you the entities and the body indices. I would probably tag bodies by setting one of its CustomTags (via the authoring components), but you could do it any number of other ways too (e.g. I believe you can now build a entity query mask in advance to optimize "is entity tagged with X" use cases).
     
    Mr-Mechanical likes this.
unityunity