- Home /
nearest point on mesh?
So this could be a long one.
Basically my issue is this

Now what i'm doing is rotating an object so the 2 nearest faces of an object are parallel.
the issue is when you have a sphere basically against a non sphere. Imagine if you rotated this object on the left, the hexagon, so that the face of it THE SOLID LINE goes though, was parallel. You would get a parallel face. However if you casted from the object to the center of the black line object. you'd find that the rotation had basically made it so a new face had rotated around.
Basically everytime you rotate the object you get a new face to rotate.
The reason is because your not casting directly out your casting slightly up to the center of the object.
really if you casted to the nearest point of the object it'd work.
But i've no idea how to do that.
pretty much if the face of an object is long enough (the angle between each face is big enoguh)
it's not an issue.
it find the right face even casting at an angle.
but for shallow angles it finds a new face everytime.
I'd like to cast from the center of object hexagon
to the nearest point on another ojbect.
but not the nearest vertex. cause thats the point at the top of the line or maybe at the bottom.
the nearest point in space.
can it even be done?
the line of course is actually a triangle (viewed side on, its actually a 3d triangle)
i can find the nearest triangle i'm confident but can i use some averaging of the 3 points of the trinagle to find the nearest point.
like in this case really for this 2d view what i want is to cast direciton (x,y)
where x = object x - other object x y = object y
i want to keep the same height I'm not sure how to translate this into 3 dimensions however.
is it perhaps the x and z of the second objects position but the height of the first objects that will go in the direction of the closest point?
Answer by whydoidoit · Mar 26, 2013 at 09:23 AM
Ok so here's the description of how to do that.
Iterate through each triangle in the mesh
Get the normal of the plane on which the triangle lies
Calculate the nearest point on that plane (using the normal above)
Work out the barycentric coordinates of the point within the triangle (see the third post here)
Clamp each barycentric coordinate between 0 and 1 which forces the point to be just within the triangle if in fact it originally lay outside.
Convert the barycentric coordinates to world coordinates
Store the point if the sqrMagnitude of the distance to the start point is less than the current best
Loop until all triangles have been considered
You have the closest point
This is some code I wrote a while ago to do it, can't remember if this is the final version though!
You'd use it like this:
var closestPointCalculator = new BaryCentricDistance(someMeshFilter);
var result = closestPointCalculator.GetClosestTriangleAndPoint(someVector3);
var closest = result.closestPoint;
Here's the script
using UnityEngine;
using System.Collections;
using System.Linq;
public class BaryCentricDistance {
public BaryCentricDistance(MeshFilter meshfilter)
{
_meshfilter = meshfilter;
_mesh = _meshfilter.sharedMesh;
_triangles = _mesh.triangles;
_vertices = _mesh.vertices;
_transform = meshfilter.transform;
}
public struct Result
{
public float distanceSquared;
public float distance
{
get
{
return Mathf.Sqrt(distanceSquared);
}
}
public int triangle;
public Vector3 normal;
public Vector3 centre;
public Vector3 closestPoint;
}
int[] _triangles;
Vector3[] _vertices;
Mesh _mesh;
MeshFilter _meshfilter;
Transform _transform;
public Result GetClosestTriangleAndPoint(Vector3 point)
{
point = _transform.InverseTransformPoint(point);
var minDistance = float.PositiveInfinity;
var finalResult = new Result();
var length = (int)(_triangles.Length/3);
for(var t = 0; t < length; t++)
{
var result = GetTriangleInfoForPoint(point, t);
if(minDistance > result.distanceSquared)
{
minDistance = result.distanceSquared;
finalResult = result;
}
}
finalResult.centre = _transform.TransformPoint(finalResult.centre);
finalResult.closestPoint = _transform.TransformPoint(finalResult.closestPoint);
finalResult.normal = _transform.TransformDirection(finalResult.normal);
finalResult.distanceSquared = (finalResult.closestPoint - point).sqrMagnitude;
return finalResult;
}
Result GetTriangleInfoForPoint(Vector3 point, int triangle)
{
Result result = new Result();
result.triangle = triangle;
result.distanceSquared = float.PositiveInfinity;
if(triangle >= _triangles.Length/3)
return result;
//Get the vertices of the triangle
var p1 = _vertices[ _triangles[0 + triangle*3] ];
var p2 = _vertices[ _triangles[1 + triangle*3] ];
var p3 = _vertices[ _triangles[2 + triangle*3] ];
result.normal = Vector3.Cross((p2-p1).normalized, (p3-p1).normalized);
//Project our point onto the plane
var projected = point + Vector3.Dot((p1 - point), result.normal) * result.normal;
//Calculate the barycentric coordinates
var u = ((projected.x * p2.y) - (projected.x * p3.y) - (p2.x * projected.y) + (p2.x * p3.y) + (p3.x * projected.y) - (p3.x * p2.y)) /
((p1.x * p2.y) - (p1.x * p3.y) - (p2.x * p1.y) + (p2.x * p3.y) + (p3.x * p1.y) - (p3.x * p2.y));
var v = ((p1.x * projected.y) - (p1.x * p3.y) - (projected.x * p1.y) + (projected.x * p3.y) + (p3.x * p1.y) - (p3.x * projected.y))/
((p1.x * p2.y) - (p1.x * p3.y) - (p2.x * p1.y) + (p2.x * p3.y) + (p3.x * p1.y) - (p3.x * p2.y));
var w = ((p1.x * p2.y) - (p1.x * projected.y) - (p2.x * p1.y) + (p2.x * projected.y) + (projected.x * p1.y) - (projected.x * p2.y))/
((p1.x * p2.y) - (p1.x * p3.y) - (p2.x * p1.y) + (p2.x * p3.y) + (p3.x * p1.y) - (p3.x * p2.y));
result.centre = p1 * 0.3333f + p2 * 0.3333f + p3 * 0.3333f;
//Find the nearest point
var vector = (new Vector3(u,v,w)).normalized;
//work out where that point is
var nearest = p1 * vector.x + p2 * vector.y + p3 * vector.z;
result.closestPoint = nearest;
result.distanceSquared = (nearest - point).sqrMagnitude;
if(float.IsNaN(result.distanceSquared))
{
result.distanceSquared = float.PositiveInfinity;
}
return result;
}
}
im going to mark this correct.
I'm going to try first to see if it's close enough to the truth casting to the center but then whatever face i hit on the second object, casting again but this time to the inverse normal direction of the face.
Basically if i find the nearest face and cast in the inverse normal direction i think it'll work.
but i will remember this, mostly i don't wnat to use barycentric co-ordinate cause i dont' understand it except that it is the center of mass, and i get that but when i did a debug.drawray and drew from the hit objects barycenter to the hit planes normal direction the barycenter was moving around which i don't understand cause i would have though the center of mass stayed constant and basically if i use that i'm going to have to spend an hour at least wrapping my head around what it means REALLY and what the result is "roughly" in my head of a barycenter calculation.
Ok you aren't using the barycentre you are using barycentric coordinates because clamping between 0 and 1 on each axis gives you a point inside the triangle - it's what barycentric coordinates are good for.

Answer by matfrem · Sep 10, 2013 at 09:41 PM
There's an error. You need to replace "`w = Mathf.Clamp01(w);`" by "`w = 1.0f - u - v;`" to keep the barycentric coordinates normalized.
Answer by Bloxard · Apr 18, 2014 at 06:21 PM
I know this is an old post, but I just want to correct this. You cannot find the nearest point on the triangle in barycentric coordinates like this.
//Find the nearest point
var vector = (new Vector3(u,v,w)).normalized;
If is true that if u>0 and v>0 and u+v<1.0 then the point is inside the triangle, but this doesn't mean that the clamped point is the closest point on the triangle.
This code above will give you a rough estimate at best.
Your answer