Trying to understand Physics.ContactModifyEvent

I’m trying to understand the rules for what GetPoint() and GetNormal() represent in ModifiableContactPair.

The normal appears to always aim (from GetPoint()) towards the collider that is not the “other” collider. Is this correct?

But when the separation is greater than 0, it seems unpredictable whether GetPoint() returns a point on the surface of the first collider or on the surface of the “other” collider. Is there any way to know for sure which collider the point is on the surface of?

My use case is that I have a cylinder mesh collider that I want to use as a wheel. The cylinder mesh is bumpy though when it rolls fast, so I want to use ContactModifyEvent to modify the contacts so that they allow the cylinder to roll smoothly. So if the contact is between a flat ground and one of the edges of the cylinder, but that edge is not facing perfectly downward, then I would move the contact point down to the bottom of what a perfectly smooth cylinder would be.

Hi,
I don’t have a proper answer for your actual question, sorry.

I wonder if you can use a perfectly curved CapsuleCollider, and then use SetSeparation and/or IgnoreContact to ignore contacts outside of the area you’re interested in (effectively slicing the ends off the capsule to leave you with a cylinder; I guess you’d need the position and rotation of your cylinder collider and the contact point: ModifiableContactPair has this info though).

I’ve used MeshCollider wheels in my game, but they don’t spin, they skate frictionlessly along the ground on their suspension springs. I’m using SetMaxImpulse to help them smooth over little bumps in the terrain (low penetration = lower max impulse, like squishy tyres).
I’m doing a similar thing to what I described above to work around a Unity bug (Mesh/Terrain collider interactions don’t seem to use contactOffset), I have these inflated MeshCollider wheels and I ignore contacts outside of the zone I’m interested in.

Those are some great ideas thanks!

Bump. When the separation is greater or less than 0, it seems unpredictable whether GetPoint() returns a point on the surface of the first collider or on the surface of the “other” collider. Is there any way to know for sure which collider the point is on the surface of?

Does anyone from Unity know the answer to this? @alexrvn sorry to bug you. You seem to be on the physics team. If this isn’t possible then can I make it a feature request to add a method to ModifiableContactPair like GetPointColliderId(int i) which would return the collider id that GetPoint() is on the surface of in cases where the separation is non-zero? Then I could compare the collider id to my collider of interest to know if it’s on that surface. As it is I need to do a lot of complex math keeping in mind my colliders shape to determine if the point is on the surface of my collider.

Could you explain a bit how you achieved squishy tires? I tried but I couldn’t quite get it working. When I tried to modify the max impulse I got jerky, bouncy tires.

(Edit: my tyres don’t spin though, they are kindof lowpoly bevelled cylindrical meshes that frictionlessly skate over the terrain. Lowpoly bevelled means usually you only get a single contact, at the lowest, central point of the tyre for normal driving)
(Edit2: and my wheels are on ArticulationBody suspension springs: I think without the springs it’d be very bumpy! We have quite offroady terrain, so we’re using slightly complicated springRate and damper stuff, to simulate suspention movement, rather like BeamNG)

private void ApplyContactSoftening( ModifiableContactPair pair ) {
    for ( int i = 0; i < pair.contactCount; ++i ) {
        var penetration = -pair.GetSeparation( i ) ; //Confirmed: GetSeparation call reads the modified value back again if I've previously called SetSeparation
        var maxImpulse = parameters.penetrationImpulseCurve.Evaluate( penetration ); //TODO:We probably want a different curve for lateral impacts
        pair.SetMaxImpulse( i, Mathf.Min( pair.GetMaxImpulse( i ), maxImpulse ) );
    }
}

penetrationImpulseCurve returns a max impulse based on how far into the terrain the wheel has penetrated.
A kindof finger in the air range for max impulse is 25 (zero-to-very little penetration) to 16000 (getting towards a wheel-radius-worth of penetration)

Thanks a lot! I will for sure try this out