Showing posts with label Ray. Show all posts
Showing posts with label Ray. Show all posts

Friday, May 14, 2010

XNA Pick model triangle with ray

You can find GetMouseCursorRay and RayIntersectTriangle on this blog.

public bool PickedTriangle(Ray cursorRay, ref Vector3 intersection, ref float distance, ref int[] triangle)
{
float pickDist = 0.0f; // distance from ray origin to intersection
float pickU = 0.0f; // barycentric coordinate of intersection
float pickV = 0.0f; // barycentric coordinate of intersection

for (int i = 0; i < (this._IndicesCount / 3); ++i)
{
// changed from left handed (DirectX) to right handed (XNA)
Vector3 tri0 = this._transformedVertices[this._Indices[3 * i + 0]];
Vector3 tri1 = this._transformedVertices[this._Indices[3 * i + 2]];
Vector3 tri2 = this._transformedVertices[this._Indices[3 * i + 1]];

// Check if the pick ray passes through this point
if (RayIntersectTriangle(cursorRay.Position, cursorRay.Direction, tri0, tri1, tri2, ref pickDist, ref pickU, ref pickV))
{
if (pickDist > 0.0f)
{
intersection = pickU * tri1 + pickV * tri2 + (1 - pickU - pickV) * tri0;
distance = pickDist;

triangle[0] = 3 * i + 0;
triangle[1] = 3 * i + 2;
triangle[2] = 3 * i + 1;

return true;
}
}
}

return false;
}

XNA Ray Intersect Triangle

private bool RayIntersectTriangle(Vector3 rayPosition, Vector3 rayDirection, Vector3 tri0, Vector3 tri1, Vector3 tri2, 
 ref float pickDistance, ref float barycentricU, ref float barycentricV)
{
 // Find vectors for two edges sharing vert0
 Vector3 edge1 = tri1 - tri0;
 Vector3 edge2 = tri2 - tri0;

 // Begin calculating determinant - also used to calculate barycentricU parameter
 Vector3 pvec = Vector3.Cross(rayDirection, edge2);

 // If determinant is near zero, ray lies in plane of triangle
 float det = Vector3.Dot(edge1, pvec);
 if (det < 0.0001f)
  return false;

 // Calculate distance from vert0 to ray origin
 Vector3 tvec = rayPosition - tri0;

 // Calculate barycentricU parameter and test bounds
 barycentricU = Vector3.Dot(tvec, pvec);
 if (barycentricU < 0.0f || barycentricU > det)
  return false;

 // Prepare to test barycentricV parameter
 Vector3 qvec = Vector3.Cross(tvec, edge1);

 // Calculate barycentricV parameter and test bounds
 barycentricV = Vector3.Dot(rayDirection, qvec);
 if (barycentricV < 0.0f || barycentricU + barycentricV > det)
  return false;

 // Calculate pickDistance, scale parameters, ray intersects triangle
 pickDistance = Vector3.Dot(edge2, qvec);
 float fInvDet = 1.0f / det;
 pickDistance *= fInvDet;
 barycentricU *= fInvDet;
 barycentricV *= fInvDet;

 return true;
}