- Home /
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 ins$$anonymous$$d 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 is$$anonymous$$inematic 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 $$anonymous$$ight be the only way
interesting:
Quietus2 said:
You can likely get a more accurate position by using some known items, namely the collider.bounds of the trigger, then bounds.IntersectRay from the rear of the actor's collider.bounds along it's local z axis and finally ray.getpoint.
That should return a vector3 with a closer approximation of where the actor's bounding box intersected the trigger.
In any case, I don't believe that triggers are meant to give you such collision information. They don't need it to serve their function. And if they did it would be a line segment of the two bounding boxes' intersection and not a point.
Likely internally it's just using the standard (and very fast) "is one of the bounding box corners within the other box's volume" intersection tests. Only after that returns true does collision code start doing more expensive and accurate tests. They're not needed for a simple trigger, therefore it opts out at that point.
I'm doing this because I heard at forums old posts get RIP and nolonger available to the community.
so he's knowledge will still be alive here on UA
Answer by shacharoz · Dec 09, 2014 at 09:08 AM
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);
}
}
This is the method I would use, but this will give you the hit point in world space. You can also get the local point of contact for a specific object by doing the following:
Vector3 locPos = Vector3.zero;
RaycastHit hit = default(RaycastHit);
Ray raycast = new Ray (drawWithObject.position, drawWithObject.transform.forward);
//using a mask so that I can ignore objects I don't want the raycast to hit
if (Physics.Raycast (raycast, out hit, 1000f, hittable$$anonymous$$ask))
{
//if pointing at the object you want to get collision point for
if (hit.transform.gameObject == myObject.gameObject)
{
//have locPos = the local position of the hit point
locPos = transform.InverseTransformPoint(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)
Answer by PiFLYON · Mar 17, 2017 at 10:04 PM
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);
}
Nice ! :-) $$anonymous$$aybe you can upvote my answer :))
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:
In Vector3, (A - B) equals (Direction from B to A)
(A + 'Direction from B to A') equals (B)
Therefore 'myTransf.position + tmpDirection' is equals 'col.transform.position'
Check Gizmos or Debug.Log
(RTF$$anonymous$$: https://docs.unity3d.com/$$anonymous$$anual/DirectionDistanceFromOneObjectToAnother.html)
Answer by graham20 · Feb 16, 2015 at 01:16 PM
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 re$$anonymous$$ding 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.
Answer by Bryan-Legend · Feb 04, 2016 at 10:40 PM
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));
}
}
Answer by triangle4studios · Jul 11, 2021 at 09:24 PM
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.