How to get collision point when using onTriggerEnter

I have a number of colliders attached to isKinematic=true rigidbodies as I do not want physics to affect my objects. I am using triggers to detect collisions between the colliders and this works fine. I was wondering if it is possible to determine the collision point (Vector3) and normal using triggers? onTriggerEnter takes a Collider instead of a Collision as a parameter. If this is not possible what would be the best way to have my objects not being affected by physics in anyway yet be able to detect collisions and the point of collision as well?

I think it is not possible else I would do it this way: Vector3 ColisionPoint(Vector3 sphere1, Vector3 sphere2, float sphere1radius){ Vector3 Direction = (sphere2 - sphere1).normalized; Vector3 ColisionPoint = sphere1 + (Direction * sphere1radius); return ColisionPoint; } I made no comments instead I've wrote pretty much self explanatory and I did 1 extra line just not to get confused too much. if you get any errors don't look at me I've been writing this on the fly.

Using IsTriggerEnter you cannot get collision points you will have to use OnCollisionEnter(Collision c)

I thought it was not possible to use OnCollisionEnter with triggers? Two isKinematic rigidbodies cannot collide together so I believe I need to use triggers to start collision detection.

Well I found this: [http://forum.unity3d.com/threads/26232-Trigger-collision-contact-point][1] Might be the only way [1]: http://forum.unity3d.com/threads/26232-Trigger-collision-contact-point

6 Answers

6

i accomplished this task using a Raycast upon collision (or colliderEnter) event.

OnTriggerEnter(Collider other){

     RaycastHit hit;
        if (Physics.Raycast(transform.position, transform.forward, out hit))
        {
            Debug.Log("Point of contact: "+hit.point);
        }
}

In my case, the transform.forward gave the object behind the one hit. I had to update the following code: Physics.Raycast(other.transform.position-other.transform.forward, other.transform.forward, out hit)

On this topic because of google, hope this will help future users. I used the @Sdgd method, but there is no need to use radius to me, the following code is applied on a “shield” objet. I instantiante an impact prefab (containing particles) at the collision point and tell the bullet to die.

This code is in Monobehaviour of my object, having SphereCollider Component, without Rigidbody as player bullets already have kinematic ones. This can work with any kind of collider I guess (sphere or box). This code is for whom wants to use kinematic rigidbodies with trigger colliders (as OnCollisionEnter() doesn’t care about them).

The only part that is doing the job are these two lines (all Vector3s) :
tmpDirection = (col.transform.position - myTransf.position);
tmpContactPoint = myTransf.position + tmpDirection;

The rest of the code is for context…

	private Vector3 tmpContactPoint;
	private Vector3 tmpDirection;
	private GameObject tmpGamob;
	private Transform myTransf;

void Start() {
		myTransf = transform;
	}
void OnTriggerEnter(Collider col) {
		if (col.tag !="PlayerBullet") return;
		tmpDirection = (col.transform.position - myTransf.position);
		tmpContactPoint = myTransf.position + tmpDirection;
		col.GetComponent<BulletControl> ().Die ();
		tmpGamob= (GameObject)Instantiate(impactBouclier, tmpContactPoint,Quaternion.identity);
		Destroy (tmpGamob, 0.3f);
	}

This is totaly wrong

This totally worked great for me! :)

It seems that tempContactPoint is just col.transform.position. Could you please explain more details?

Has errors, undefined values and just doesnt work overall, move along people.

This is Completely wrong code. "A + (B-A) == B" You should know this: 1. In Vector3, (A - B) equals (Direction from B to A) 2. (A + 'Direction from B to A') equals (B) Therefore 'myTransf.position + tmpDirection' is equals 'col.transform.position' Check Gizmos or Debug.Log (RTFM: https://docs.unity3d.com/Manual/DirectionDistanceFromOneObjectToAnother.html)

Depending on how big your objects are, you might get away with just using other.transform.position. I use this for playing a splash particle effect when my player hits water and it looks pretty good.

I totally forgot about this simple solution.. slaps forehead .. thanks for reminding me. This is totally it chief In my case I needed a detection point of contact for OnTriggerEnter2D, then spawn something at that vector3 position.

This should do it in most cases and should be cheaper than a raycast:

private void OnTriggerEnter2D(Collider2D collision)
{
    Vector2 point = collision.ClosestPoint(transform.position);
}

Here’s my solution. Only works with a box collider.

localCollider.ClosestPointOnBounds(target.transform.position) does an okay job but is AABB based.

        void OnTriggerEnter(Collider target)
        {
            //print("TouchDamage trigger with " + collider.name);

            var damageable = target.gameObject.GetComponent<Damageable>();
            if (damageable != null)
            {
                var localCollider = GetComponent<BoxCollider>();
                if (localCollider != null)
                {
                    if (CheckEdge(target, damageable, BottomRightEdge(localCollider)))
                        return;
                    if (CheckEdge(target, damageable, TopRightEdge(localCollider)))
                        return;
                    if (CheckEdge(target, damageable, BottomLeftEdge(localCollider)))
                        return;
                    if (CheckEdge(target, damageable, TopLeftEdge(localCollider)))
                        return;

                    CollideWith(target, localCollider.ClosestPointOnBounds(target.transform.position), damageable);
                }
                else
                    CollideWith(target, transform.position, damageable);
            }
        }

        bool CheckEdge(Collider target, Damageable damageable, Ray edge)
        {
            foreach (var hit in Physics.RaycastAll(edge, edge.direction.magnitude))
            {
                if (hit.collider == target)
                {
                    CollideWith(target, hit.point, damageable);
                    return true;
                }
            }
            return false;
        }

        Ray BottomRightEdge(BoxCollider collider)
        {
            var bottomRight = transform.TransformPoint(collider.center + new Vector3(collider.size.x, -collider.size.y, collider.size.z) * 0.5f);
            var topRight = transform.TransformPoint(collider.center + new Vector3(collider.size.x, collider.size.y, collider.size.z) * 0.5f);
            return new Ray(bottomRight, topRight - bottomRight);
        }

        Ray TopRightEdge(BoxCollider collider)
        {
            var bottomRight = transform.TransformPoint(collider.center + new Vector3(collider.size.x, -collider.size.y, -collider.size.z) * 0.5f);
            var topRight = transform.TransformPoint(collider.center + new Vector3(collider.size.x, collider.size.y, -collider.size.z) * 0.5f);
            return new Ray(bottomRight, topRight - bottomRight);
        }

        Ray BottomLeftEdge(BoxCollider collider)
        {
            var bottomLeft = transform.TransformPoint(collider.center + new Vector3(-collider.size.x, -collider.size.y, collider.size.z) * 0.5f);
            var topLeft = transform.TransformPoint(collider.center + new Vector3(-collider.size.x, collider.size.y, collider.size.z) * 0.5f);
            return new Ray(bottomLeft, topLeft - bottomLeft);
        }

        Ray TopLeftEdge(BoxCollider collider)
        {
            var bottomLeft = transform.TransformPoint(collider.center + new Vector3(-collider.size.x, -collider.size.y, -collider.size.z) * 0.5f);
            var topLeft = transform.TransformPoint(collider.center + new Vector3(-collider.size.x, collider.size.y, -collider.size.z) * 0.5f);
            return new Ray(bottomLeft, topLeft - bottomLeft);
        }

        void OnDrawGizmosSelected()
        {
            BoxCollider b = GetComponent<BoxCollider>();
            if (b != null)
            {
                Gizmos.color = Color.red;
                Gizmos.DrawRay(BottomRightEdge(b));
                Gizmos.DrawRay(TopRightEdge(b));
                Gizmos.DrawRay(BottomLeftEdge(b));
                Gizmos.DrawRay(TopLeftEdge(b));
            }
        }

Surely col.gameObject.transform.position is the simplest solution for the hit point.

To get the normal, Surely these will work for you:

2D -col.gameObject.transform.up

3D -col.gameObject.transform.forward

The hit point in OnTriggerEnter is not equal col.transform.position(col.gameObject.transform.position). Probably you think of a small object with a collider. Think about it.. If the sphere collider is very large, then the transform.position of the sphere collider will not touch other collider let alone hit point when OnTriggerEnter situation. So, hit point in OnTriggerEnter, OnCollisionEnter are not equal col.transform.position The real hit point is myCollider, otherCollider's contact point.

And don't call me surely.

I edited to answer your edit comment.