• 2.1k
• 7
• 6.3k

uv coordinates ray intersect

Mar 3 2013 9:20 AM
Hello

Im new to programming and  been studying alot about creating ray intersect triangle and ray intersect model methods for xna. Ive come to
understand alot about them, but theres one last thing Ive been trying  to implement, which is having the ray return the uv coordinates of a model(in my case a
heightmap terrain) and despite my research have yet to find a clear cut example of how to do it. the code Ive been trying to modify is below(and links) and was hoping if anyone could help me out.Thankyou

http://dzindzinovic.blogspot.com/2010/05/xna-get-mouse-cursor-ray.html
http://dzindzinovic.blogspot.com/2010/05/xna-ray-intersect-triangle.html

public Ray GetMouseCursorRay(MouseState _CurrentMouseState, Matrix _projectionMatrix, Matrix _viewMatrix)
{
// Create 2 positions in screenspace using the cursor position.
// 0 is as close as possible to the camera, 1 is as far away as possible.
Vector3 nearSource = new Vector3(_CurrentMouseState.X, _CurrentMouseState.Y, 0.0f);
Vector3 farSource = new Vector3(_CurrentMouseState.X, _CurrentMouseState.Y, 1.0f);

// Use Viewport. Unproject to tell what those two screen space positions would be in world space.
// We'll need the projection matrix and view matrix, which we have saved as member variables.
// We also need a world matrix, which can just be identity.
Vector3 nearPoint = _GraphicsDevice.Viewport.Unproject(nearSource, _projectionMatrix, _viewMatrix, Matrix.Identity);
Vector3 farPoint = _GraphicsDevice.Viewport.Unproject(farSource, _projectionMatrix, _viewMatrix, Matrix.Identity);

// Find the direction vector that goes from the nearPoint to the farPoint and normalize it...
Vector3 direction = farPoint - nearPoint;
direction.Normalize();

// ... and then create a new ray using nearPoint as the source.
return new Ray(nearPoint, direction);
}

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;
}

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;
}