# Clamp point to triangle for sphere collision

I'm having some issues clamping a 3d to barycentric triangle. I've searched for some time now and keep seeing the same results, that (u,v,w) should be clamped between 0 and 1. But when I clamp those values, I'm getting very weird results as it saying it's always intersecting. Maybe I'm just clamping the wrong values or what I'm doing wrong.

The issue is that I'm projecting a point on a normal from a given triangle, then testing if the point is inside the triangle, if it is, test if it's inside the sphere. Everything works great except when the sphere center is no longer above/in front of the triangle, so the spheres edge can pass through the edge of the triangle beings that the spheres center is no longer above it. Any help with how I'm supposed to clamp the position inside of the triangle would be much appreciated.

Here is a snippet of the triangle/sphere intersect method:

public boolean CollidesWithMesh(MeshCollider other)
{
float sphereRadius = gameObject.scale * (bounds.Scale().Max()) / 2f;
boolean collided = false;
RawMesh mesh = other.gameObject.meshRenderer.mesh.rawMesh;

for(int i = 0; i < mesh.triangles.length; i++)
{
//Store the verts used in the triangle
int first = i++;

//Project a point along the normal closest to the spheres center
Vector3 normal = mesh.normals[(int) mesh.triangles[first]];
float dot = Vector3.Dot(normal, gameObject.position.Subtract(vert1));
Vector3 d = normal.Multiply(dot);
Vector3 point = gameObject.position.Subtract(d);

//If the point is not inside the triangle, continue
Vector3 v0 = vert3.Subtract(vert1);
Vector3 v1 = vert2.Subtract(vert1);
Vector3 v2 = point.Subtract(vert1);
float dot00 = Vector3.Dot(v0, v0);
float dot01 = Vector3.Dot(v0, v1);
float dot02 = Vector3.Dot(v0, v2);
float dot11 = Vector3.Dot(v1, v1);
float dot12 = Vector3.Dot(v1, v2);
float invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
float u = (dot11 * dot02 - dot01 * dot12) * invDenom;
float v = (dot00 * dot12 - dot01 * dot02) * invDenom;
if(!((u >= 0.0) && (v >= 0.0) && (u + v <= 1))) continue;

//If the sphere does not encapsulates the point, continue
if(!Contains(point)) continue;

//Respond to the collision
Vector3 responseNormal = point.Subtract(gameObject.position).Normalized().Multiply(sphereRadius - (point.Subtract(gameObject.position)).Length());
Vector3.Subtract(gameObject.position, responseNormal);
if(normal.y > 0.75) isGrounded = true;
if(normal.y < -0.75) hitCeiling = true;
collided = true;
}
return collided;
}


Had a few things backwards. After a couple days of research and toying with the code I finally got it working. Here is the finished method:

public boolean CollidesWithMesh(MeshCollider other)
{
float sphereRadius = gameObject.scale * (bounds.Scale().Max()) / 2f;
boolean collided = false;
RawMesh mesh = other.gameObject.meshRenderer.mesh.rawMesh;

for(int i = 0; i < mesh.triangles.length; i++)
{

//Store the verts used in the triangle
int first = i++;
Vector3 normal = mesh.normals[(int) mesh.triangles[first]];

//Calculate and clamp the barycentric coordinates
Vector3 v21 = vert2.Subtract(vert1);
Vector3 v31 = vert3.Subtract(vert1);
Vector3 v1 = gameObject.position.Subtract(vert1);
float dot00 = Vector3.Dot(v21, v21);
float dot01 = Vector3.Dot(v21, v31);
float dot11 = Vector3.Dot(v31, v31);
float dot20 = Vector3.Dot(v1, v21);
float dot21 = Vector3.Dot(v1, v31);
float denom = dot00 * dot11 - dot01 * dot01;
float v = (dot11 * dot20 - dot01 * dot21) / denom;
float w = (dot00 * dot21 - dot01 * dot20) / denom;
float u = 1.0f - v - w;
if(u < 0)
{
Vector3 v32 = vert3.Subtract(vert2);
float t = Vector3.Dot(gameObject.position.Subtract(vert2), v32) / (Vector3.Dot(v32, v32));
t = Mathf.Clamp(t, 0, 1);
u = 0.0f; v = 1.0f - t; w = t;
}
else if(v < 0)
{
Vector3 v13 = vert1.Subtract(vert3);
float t = Vector3.Dot(gameObject.position.Subtract(vert3), v13) / (Vector3.Dot(v13, v13));
t = Mathf.Clamp(t, 0, 1);
u = t; v = 0.0f; w = 1.0f - t;
}
else if(w < 0)
{
float t = dot20 / dot00;
t = Mathf.Clamp(t, 0, 1);
u = 1.0f - t; v = t; w = 0.0f;
}

//Convert the barycentric coordinates to world space
Vector3 point = new Vector3((u * vert1.x) + (v * vert2.x) + (w * vert3.x), (u * vert1.y) + (v * vert2.y) + (w * vert3.y), (u * vert1.z) + (v * vert2.z) + (w * vert3.z));

//If the sphere does not encapsulates the point, continue
if(!Contains(point)) continue;

//Respond to the collision
Vector3 responseNormal = point.Subtract(gameObject.position).Normalized().Multiply(sphereRadius - (point.Subtract(gameObject.position)).Length());
Vector3.Subtract(gameObject.position, responseNormal);
if(normal.y > 0.75) isGrounded = true;
if(normal.y < -0.75) hitCeiling = true;
collided = true;

}
return collided;
}