public const float Epsilon = 1E-5f; //for numerical imprecision /// <summary> /// Checks whether a ray intersects a triangle /// </summary> /// <returns>closest intersection point</returns> public static float? RayIntersectTriangle(Ray ray, Vector3[] vertices, Matrix transform, out Triangle triangle) { triangle.v1 = triangle.v2 = triangle.v3 = Vector3.Zero; // Keep track of the closest triangle we found so far, // so we can always return the closest one. float? closestIntersection = null; Vector3 v1 = Vector3.Zero; Vector3 v2 = Vector3.Zero; Vector3 v3 = Vector3.Zero; // Loop over the vertex data, 3 at a time (3 vertices = 1 triangle). for (int i = 0; i < vertices.Length; i += 3) { // Perform a ray to triangle intersection test. float? intersection; // Transform the three vertex positions into world space v1 = Vector3.Transform(vertices[i], transform); v2 = Vector3.Transform(vertices[i + 1], transform); v3 = Vector3.Transform(vertices[i + 2], transform); RayIntersectsTriangle(ray, v1, v2, v3, out intersection); // Does the ray intersect this triangle? if (intersection != null) { // If so, is it closer than any other previous triangle? if ((closestIntersection == null) || (intersection < closestIntersection)) { // Store the distance to this triangle. closestIntersection = intersection; // Store the three vertex positions into the vertex parameters. triangle.v1 = v1; triangle.v2 = v2; triangle.v3 = v3; } } } return closestIntersection; }
/// <summary> /// It checks for the collision between a collision ray and a collision model. /// </summary> protected bool TestRayintersectModel(Ray ray, Vector3[] vertices, Matrix transform, out Vector3 intersect, out Vector3 normal, out float distance) { Triangle outTriangle = new Triangle(Vector3.Zero, Vector3.Zero, Vector3.Zero); distance = 0.0f; intersect = Vector3.Zero; normal = Vector3.Zero; totalCollidingCount += vertices.Length; // Test ray with the model float? checkDistance = Helper3D.RayIntersectTriangle(ray, vertices, transform, out outTriangle); if (checkDistance != null) { // Retry test for intersect point and normal return Helper3D.PointIntersect(ray.Position, ray.Direction, outTriangle, out distance, out intersect, out normal); } return false; }
/// <summary> /// ray intersect face and return intersection distance, point and normal. /// </summary> public static bool PointIntersect(Vector3 rayOrigin, Vector3 rayDirection, Triangle triangle, out float intersectDistance, out Vector3 intersectPosition, out Vector3 intersectNormal) { intersectDistance = 0.0f; intersectPosition = rayOrigin; intersectNormal = Vector3.Zero; Vector3 uvt = Vector3.Zero; if (RayTriangleIntersect(rayOrigin, rayDirection, triangle.v1, triangle.v2, triangle.v3, out uvt.Z, out uvt.X, out uvt.Y)) { intersectDistance = uvt.Z; intersectPosition = (1.0f - uvt.X - uvt.Y) * triangle.v1 + uvt.X * triangle.v2 + uvt.Y * triangle.v3; intersectNormal = Vector3.Normalize( Vector3.Cross(triangle.v3 - triangle.v1, triangle.v2 - triangle.v1)); return true; } return false; }
/// <summary> /// Checks whether a ray intersects a model. This method needs to access /// the model vertex data, /// Returns the distance along the ray to the point of intersection, or null /// if there is no intersection. /// </summary> /// <returns>closest intersection point</returns> public static float? RayIntersectModel(Ray ray, Model model, Matrix worldTransform, out bool insideBoundingSphere, out Triangle triangle) { triangle.v1 = triangle.v2 = triangle.v3 = Vector3.Zero; // Look up our custom collision data from the Tag property of the model. Dictionary<string, object> tagData = (Dictionary<string, object>)model.Tag; if (tagData == null) { throw new InvalidOperationException( "Model.Tag is not set correctly. Make sure your model " + "was built using the custom CollideProcessor."); } // Start off with a fast bounding sphere test. BoundingSphere boundingSphere = (BoundingSphere)tagData["BoundingSphere"]; if (boundingSphere.Intersects(ray) == null) { // If the ray does not intersect the bounding sphere, we cannot // possibly have picked this model, so there is no need to even // bother looking at the individual triangle data. insideBoundingSphere = false; return null; } else { // The bounding sphere test passed, so we need to do a full // triangle picking test. insideBoundingSphere = true; // Keep track of the closest triangle we found so far, // so we can always return the closest one. float? closestIntersection = null; // Loop over the vertex data, 3 at a time (3 vertices = 1 triangle). Vector3[] vertices = (Vector3[])tagData["Vertices"]; for (int i = 0; i < vertices.Length; i += 3) { // Perform a ray to triangle intersection test. float? intersection; RayIntersectsTriangle(ray, vertices[i], vertices[i + 1], vertices[i + 2], out intersection); // Does the ray intersect this triangle? if (intersection != null) { // If so, is it closer than any other previous triangle? if ((closestIntersection == null) || (intersection < closestIntersection)) { // Store the distance to this triangle. closestIntersection = intersection; // Transform the three vertex positions into world space, // and store them into the output vertex parameters. triangle.v1 = Vector3.Transform(vertices[i], worldTransform); triangle.v2 = Vector3.Transform(vertices[i + 1], worldTransform); triangle.v3 = Vector3.Transform(vertices[i + 2], worldTransform); } } } return closestIntersection; } }