Distance between point and mesh geometry [SOLVED]

Software: Away3D 4.x

Avatar
Mu Duck, Newbie
Posted: 15 December 2013 10:09 PM   Total Posts: 20

Quick question:
Is there a method to calculate the shortest distance (and corresponding point on the surface) between a point in 3d space and a mesh (its surface).

I know how to do it mathematically - find the distance for each face and then choose the shortest one (but it is a big code to write - especially finding the shortest distance per face). Is there an out of the box method for this problem?

Thanks

   

Avatar
Mu Duck, Newbie
Posted: 17 December 2013 09:00 AM   Total Posts: 20   [ # 1 ]

Ok…. I wrote it myself… as usual.
Sharing code here, in case anyone needs:

I don’t know if it very efficient, but on my computer it runs with frequency of 53000 per second, or 830 per 1 frame (60 fps). At least it is mathematically correct and is based on solving the following problem for each face: (a1*x1+a2*x2+a3*x3-x0)^2+(a1*y1+a2*y2+a3*y3-y0)^2+(a1*z1+a2*z2+a3*z3-z0)^2 -> MIN
subject to constraints:
a1 >= 0,a2 >= 0,a3 >= 0
a1+a2+a3 = 1

You can use it to stick some character or any object to some surface (but remember that calculations will become tough with number of faces increasing. In my case I have 12 face mesh)

//returns a point in 3D space on the surface of mesh, which is the closest (in terms of Euclidean distance) to the specified point
 //out - is output vector (if specified - will write there and no new Vector3D object created)
 
private static var _gnp_v:Vector.<Number> = new Vector.<Number>(9, true);//vector with 3 vertices (here for speedup)
 
public static function getNearestPoint(point:Vector3D, mesh:Mesh, out:Vector3D=null):Vector3D {
  
if (mesh == null || point == null) return null;//don't play with me
  
  
var vertexOffset:uint = mesh.subMeshes[0].vertexOffset;
  var 
vertexStride:uint = mesh.subMeshes[0].vertexStride;
  var 
indexData:Vector.<uint> = mesh.subMeshes[0].indexData;
  var 
vertexData:Vector.<Number> = mesh.subMeshes[0].vertexData;
  var 
ind1:uint, ind2:uint, ind3:uint;//indices of face vertexes in vertexData
  
  
var x0:Number=point.x, y0:Number=point.y, z0:Number=point.z;//point coordinates
  
var x1:Number, y1:Number, z1:Number, x2:Number, y2:Number, z2:Number, x3:Number, y3:Number, z3:Number;//coordinates of face verteces
  
var x03:Number, x13:Number, x23:Number, x21:Number;
  var 
y03:Number, y13:Number, y23:Number, y21:Number;
  var 
z03:Number, z13:Number, z23:Number, z21:Number;
  var 
v21_23:Number, v13_23:Number, v03_13:Number, v13_sq:Number;
  
  var 
a1:Number, a2:Number, a3:Number;//optimal weights for vertex1,vertex2,vertex3 (need to find them in solution)
  
var mode:uint, dist:Number, distBest:Number, faceBest:uint;
  var 
rx:Number, ry:Number, rz:Number, rxBest:Number, ryBest:Number, rzBest:Number;//point we are searching for
  
  
distBest = Number.MAX_VALUE;
  var 
faceIndex:int=indexData.length-1;//points to last vertex of the last face
  
while (faceIndex > -1) {//faces iteration;
   //get coordinates of the triangle's 3 vertices (v1,v2,v3)
   
ind3 = vertexOffset + indexData[faceIndex--] * vertexStride;
   
ind2 = vertexOffset + indexData[faceIndex--] * vertexStride;
   
ind1 = vertexOffset + indexData[faceIndex--] * vertexStride;//faceIndex point to last vertex of previous face
   //and apply transformation matrix
   
_gnp_v[0] = vertexData[ind1]; _gnp_v[1] = vertexData[uint(ind1 + 1)]; _gnp_v[2] = vertexData[uint(ind1 + 2)];
   
_gnp_v[3] = vertexData[ind2]; _gnp_v[4] = vertexData[uint(ind2 + 1)]; _gnp_v[5] = vertexData[uint(ind2 + 2)];
   
_gnp_v[6] = vertexData[ind3]; _gnp_v[7] = vertexData[uint(ind3 + 1)]; _gnp_v[8] = vertexData[uint(ind3 + 2)];
   
mesh.sceneTransform.transformVectors(_gnp_v,_gnp_v);
   
x1 = _gnp_v[0]; y1 = _gnp_v[1]; z1 = _gnp_v[2];
   
x2 = _gnp_v[3]; y2 = _gnp_v[4]; z2 = _gnp_v[5];
   
x3 = _gnp_v[6]; y3 = _gnp_v[7]; z3 = _gnp_v[8];
   
   
   
//calculate required differences
   
x03 = x0 - x3; x13 = x1 - x3; x23 = x2 - x3; x21 = x2 - x1;
   
y03 = y0 - y3; y13 = y1 - y3; y23 = y2 - y3; y21 = y2 - y1;
   
z03 = z0 - z3; z13 = z1 - z3; z23 = z2 - z3; z21 = z2 - z1;
   
v21_23 = x21*x23 + y21*y23 + z21*z23;
   
v13_23 = x13*x23 + y13*y23 + z13*z23;
   
v03_13 = x03*x13 + y03*y13 + z03*z13;
   
v13_sq = x13*x13 + y13*y13 + z13*z13;
   
   
//calculate the solution (a1, a2, a3) of minimization without conditions a1>=0 a2>=0 a3>=0 but with condition that a1+a2+a3==1
   
a1 = (v03_13*v21_23 - (x03*x21 + y03*y21 + z03*z21)*v13_23 );
   
a1 = a1 / (v13_sq*v21_23 - (x13*x21 + y13*y21 + z13*z21)*v13_23);
   
a2 = (v03_13 - v13_sq*a1)/v13_23;
   
a3 = 1 - a1 - a2;
   
   
//cool now adjust a1,a2,a3 for condition a1>=0 a2>=0 a3>=0
   
mode = 0;//means all conditions correct - optimal point is inside the triangle
   
if (a1 < 0) { a1 = 0; mode++; }
   
if (a2 < 0) { a2 = 0; mode++; }
   
if (a3 < 0) { a3 = 0; mode++; }
   
if (mode > 1) {//means will get exactly on some vertex of triangle
    
if (a1) a1 = 1
    
else if (a2) a2 = 1;
    else 
a3 = 1;
   
} else if (mode == 1) {//means will be on the edge (same problem but with condition that one a = 0)
    
if (!a1) {//edge between v2 and v3
     
a2 = (x03*x23 + y03*y23 + z03*z23)/(x23*x23 + y23*y23 + z23*z23);
     if(
a2<0)a2=0 else if(a2>1)a2=1
     a3 
= 1 - a2;
    
} else if (!a2) {//edge between v1 and v3
     
a1 = v03_13 / v13_sq;
     if(
a1<0)a1=0 else if(a1>1)a1=1
     a3 
= 1 - a1; 
    
} else {//edge between v1 and v2
     
a2 = ((x0 - x1)*x21 + (y0 - y1)*y21 + (z0 - z1)*z21)/(x21*x21 + x21*x21 + x21*x21);
     if(
a2<0)a2=0 else if(a2>1)a2=1
     a1 
= 1 - a2;
    
}
   }
   
   
//solution found - now based on it calculate point and distance
   
rx = x1*a1 + x2*a2 + x3*a3;
   
ry = y1*a1 + y2*a2 + y3*a3;
   
rz = z1*a1 + z2*a2 + z3*a3;
   
dist = Math.pow(rx - x0, 2) + Math.pow(ry - y0, 2) + Math.pow(rz - z0, 2);
   
   
//if it is shorter than previous distance this point is considered best now
   
if (dist < distBest) {
    distBest 
= dist
    rxBest 
= rx; ryBest = ry; rzBest = rz;
    
faceBest = faceIndex + 1;//write here just for fun
   
}
  }
  
  
//after all faces were checked - return best result
  
if (out != null) { out.x = rxBest; out.y = ryBest; out.z = rzBest; return out; }
  
return new Vector3D(rxBest, ryBest, rzBest);
 
} 
   
   

X

Away3D Forum

Member Login

Username

Password

Remember_me



X