Collision.contacts[].point is not accurate

Just posting this here because I had been assuming otherwise.

When 2 objects collide, inside OnCollisionEnter() or OnCollisionStay() you can use Collision.contacts[0].point to get the location of the first contact point. There is always guaranteed to be at least one.

I’m moving a rigidbody sphere collider against a stationary mesh collider. The sphere is using a script which simply moves it forward and draws a line at any contact point detected. It uses a physics material with bounce and friction zeroed out.

I had been assuming that since one of the colliders is stationary, the collision point would never fail to be on that collider’s surface.

Here’s the scene:

Most of the time, it is exactly as expected. The collision point is on the non-moving surface. But letting the sphere run back and forth a few times, I get this:

1229928--51619--$UsuallyFine.png

Earlier, coming down very fast from the right, one rather large difference:

1229928--51617--$BigCutIn.png

And moving horizontally only (this surprised me):

1229928--51618--$HozCutIn.png

Here’s the script:

using UnityEngine;
using System.Collections;

public class Move : MonoBehaviour 
{
    void FixedUpdate()
    {
        rigidbody.AddForce(transform.forward * 20.0f);
    }

    void OnCollisionEnter(Collision enterColl)
    {
            Debug.DrawRay(enterColl.contacts[0].point, Vector3.up, Color.blue, 10.0f);
    }

    void OnCollisionStay(Collision stayColl)
    {
            Debug.DrawRay(stayColl.contacts[0].point, Vector3.up, Color.white, 10.0f);
    }
}

It gives the appearance that the contact point is always going to be a point on the moving object, not the surface. It doesn’t matter which object called OnCollisionStay(), as I ran a similar script on the surface mesh, using red lines instead, and the results didn’t change.

Playing with settings showed that Min Penetration For Penalty doesn’t have any effect on this, but Solver Iteration Count does. That makes sense, however not quite as much as I’d like. Setting Solver Iteration Count to 100 still gives the same discrepancy on the horizontal part of my test. Why?
Setting it to just 1 still gives contact points that are perfectly flush with the stationary surface for the large majority of collisions.

So in conclusion it appears that Collision.contacts[ ].point is a point that is guaranteed to be on the moving body’s surface, but not the stationary object’s surface. What precisely defines that point, I don’t know.

Ok now I understand.

Basically it defines a collision point as:

  1. A point on the rigidbody, not the static collider
  2. A point on the RB BEFORE it moved into the position that created the collision. That is, on the RB as if it’s still at the last frame, even though it has moved.
  3. The point on the RB (in its old position) that corresponds to where it would have penetrated the most (in its current position). And yes this means that it can be a point on the RB that hasn’t even collided yet regardless of which of the 2 frames you look at.

The picture will make more sense of things.

The blue sphere has fallen through the dark, dark red surface that is facing downwards.
The yellow and green lines are only alive on this frame.
Yellow is coming from transform.position. (There are other objects in the parent so its centre isn’t inside the sphere.)
Green is coming from Collision.contacts[0].point.

As you can see, the collision point can yes be determined to have some logic involved, but wtf.

I’ve been casting rays to the collision points to get the surface normal. Not only is it not on the surface, but it’s not even through the surface, so the rays have been drawing blanks.

At least now I know what workaround to create, but… I can’t say I’m in love with this little discovery.

1 Like

i know this thread is one year old, but i have come across the exact same problem, i need the collision point to be as precise as possible, does someone know a way to do that ? ( besides doing what mr DanJC already did above.

Its 2019 and s**t still stinks.
Sorry for the brutal verbalization but this totally can drive you into a depression.

Contact point is almost worthless.
First of all it looks like it does not give you information of what is the point of collision ON COLLIDER.
It just give you some point in world space that is mostly useless since bodies are usually no longer in this position anyway.
What we need is:

  1. rotation (also position ?) of a collider when collision occured.
  2. relative point of a collision with respect to the collider.
  3. optionally world position of collision in case collider is no longer available.

The question is, is this the PhysX fault or Unity3d ?

I don’t get it. We do have access to all of this or do you want it to be saved in the Collision struct?
The bodies have not moved when OnCollisionEnter or Stay has been called.

  1. transform.position … or the other object coll.transform.position / rotation…
  2. https://docs.unity3d.com/ScriptReference/Transform.InverseTransformDirection.html
    https://docs.unity3d.com/ScriptReference/Transform.InverseTransformPoint.html
    https://docs.unity3d.com/ScriptReference/Transform.InverseTransformVector.html

Please read the OP.
Also you can read Accurate Position of Object on Collision - Questions & Answers - Unity Discussions

Problem is that it looks like we cannot get object transform state during the collision.
All we get is it’s state after the collision response, so it’s orientation and position might be totally off.
It is a big problem when you try to use fast moving object.

Your response sounded like you weren’t even talking about that part of his post. Must’ve read it wrong.
Never seen this problem before even with objects moving up to max 30 m/s ( snooker game ).
I’m using a extremely low fixedTime and solverIteration just 1 for that with good results but I can see how that might not be possible when you’re spraying bullets performancewise.

I realized this problem when in my game I was spawning arrows. I wanted them to stick to the object they collided with.
The result were unfortunately surprising, some arrows were sticking in a wrong direction sometimes in a wrong position. It’s because I got the data after the collision response.

Did you ever find a solution to this? I’ve encountered the same problem for a while now

Not satisfying one. I’m hacking it like this:
What I do is I cast raycast in front of arrow to where the arrow will be in next frame.
If it hits I assuming this is the place the arrow will hit and act accordingly.

1 Like

Thank you, thats a good idea!

Facing the same problem on 2022.3.10f1.
I need accurate point on the collision surface, the point always has around 0.1 distance to the surface, so I can only use ClosestPoint when collision to get the point on surface, it might be still incorrect to the moving direction, but better than the default value.