// // Ray-plane intersection // http://www.scratchapixel.com/lessons/3d-basic-rendering/minimal-ray-tracer-rendering-simple-shapes/ray-plane-and-ray-disk-intersection // //2d public static bool RayPlane(Plane2 plane, Ray2 ray) { //To avoid floating point precision issues we can add a small value float epsilon = MathUtility.EPSILON; bool areIntersecting = false; float denominator = MyVector2.Dot(plane.normal * -1f, ray.dir); //Debug.Log(denominator); //The ray has to point at the surface of the plane //The surface of the plane is determined by the normal if (denominator > epsilon) { //Now we have to figur out of the ray starts "inside" of the plane //meaning on the other side of the normal //If so it can't hit the plane MyVector2 vecBetween = plane.pos - ray.origin; float t = MyVector2.Dot(vecBetween, plane.normal * -1f) / denominator; //Debug.Log(t); if (t >= 0f) { areIntersecting = true; } } return(areIntersecting); }
//If we know two planes are intersecting, what's the point of intersection? //2d public static MyVector2 GetPlanePlaneIntersectionPoint(Plane2 plane_1, Plane2 plane_2) { MyVector2 lineDir = MyVector2.Normalize(new MyVector2(plane_2.normal.y, -plane_2.normal.x)); Ray2 ray = new Ray2(plane_2.pos, lineDir); MyVector2 intersectionPoint = GetIntersectionCoordinate(plane_1, ray); return(intersectionPoint); }
//We know a line plane is intersecting and now we want the coordinate of intersection //2d public static MyVector2 GetLinePlaneIntersectionPoint(Plane2 plane, Edge2 line) { MyVector2 lineDir = MyVector2.Normalize(line.p1 - line.p2); Ray2 ray = new Ray2(line.p1, lineDir); MyVector2 intersectionPoint = GetIntersectionCoordinate(plane, ray); return(intersectionPoint); }
// // Line, plane, ray intersection with plane // //This is a useful method to find the intersection coordinate if we know we are intersecting //Is used for ray-plane, line-plane, plane-plane //2d private static MyVector2 GetIntersectionCoordinate(Plane2 plane, Ray2 ray) { float denominator = MyVector2.Dot(-plane.normal, ray.dir); MyVector2 vecBetween = plane.pos - ray.origin; float t = MyVector2.Dot(vecBetween, -plane.normal) / denominator; MyVector2 intersectionPoint = ray.origin + ray.dir * t; return(intersectionPoint); }
//Assumes the polygons are oriented counter clockwise //poly is the polygon we want to cut //Assumes the polygon we want to remove from the other polygon is convex, so clipPolygon has to be convex //We will end up with the intersection of the polygons public static List <MyVector2> ClipPolygon(List <MyVector2> poly, List <Plane2> clippingPlanes) { //Clone the vertices because we will remove vertices from this list List <MyVector2> vertices = new List <MyVector2>(poly); //Save the new vertices temporarily in this list before transfering them to vertices List <MyVector2> vertices_tmp = new List <MyVector2>(); //Clip the polygon for (int i = 0; i < clippingPlanes.Count; i++) { Plane2 plane = clippingPlanes[i]; for (int j = 0; j < vertices.Count; j++) { int jPlusOne = MathUtility.ClampListIndex(j + 1, vertices.Count); MyVector2 v1 = vertices[j]; MyVector2 v2 = vertices[jPlusOne]; //Calculate the distance to the plane from each vertex //This is how we will know if they are inside or outside //If they are inside, the distance is positive, which is why the planes normals have to be oriented to the inside float dist_to_v1 = _Geometry.GetSignedDistanceFromPointToPlane(v1, plane); float dist_to_v2 = _Geometry.GetSignedDistanceFromPointToPlane(v2, plane); //TODO: What will happen if they are exactly 0? Should maybe use a tolerance of 0.001 //Case 1. Both are outside (= to the right), do nothing //Case 2. Both are inside (= to the left), save v2 if (dist_to_v1 >= 0f && dist_to_v2 >= 0f) { vertices_tmp.Add(v2); } //Case 3. Outside -> Inside, save intersection point and v2 else if (dist_to_v1 < 0f && dist_to_v2 >= 0f) { MyVector2 rayDir = MyVector2.Normalize(v2 - v1); Ray2 ray = new Ray2(v1, rayDir); MyVector2 intersectionPoint = _Intersections.GetRayPlaneIntersectionPoint(plane, ray); vertices_tmp.Add(intersectionPoint); vertices_tmp.Add(v2); } //Case 4. Inside -> Outside, save intersection point else if (dist_to_v1 >= 0f && dist_to_v2 < 0f) { MyVector2 rayDir = MyVector2.Normalize(v2 - v1); Ray2 ray = new Ray2(v1, rayDir); MyVector2 intersectionPoint = _Intersections.GetRayPlaneIntersectionPoint(plane, ray); vertices_tmp.Add(intersectionPoint); } } //Add the new vertices to the list of vertices vertices.Clear(); vertices.AddRange(vertices_tmp); vertices_tmp.Clear(); } return(vertices); }
//Get the coordinate if we know a ray-plane is intersecting //2d public static MyVector2 GetRayPlaneIntersectionPoint(Plane2 plane, Ray2 ray) { MyVector2 intersectionPoint = GetIntersectionCoordinate(plane, ray); return(intersectionPoint); }
//The original algorithm calculates the intersection between two polygons, this will instead get the outside //Assumes the polygons are oriented counter clockwise //poly is the polygon we want to cut //Assumes the polygon we want to remove from the other polygon is convex, so clipPolygon has to be convex //We will end up with the !intersection of the polygons public static List <List <MyVector2> > ClipPolygonInverted(List <MyVector2> poly, List <Plane2> clippingPlanes) { //The result may be more than one polygons List <List <MyVector2> > finalPolygons = new List <List <MyVector2> >(); List <MyVector2> vertices = new List <MyVector2>(poly); //The remaining polygon after each cut List <MyVector2> vertices_tmp = new List <MyVector2>(); //Clip the polygon for (int i = 0; i < clippingPlanes.Count; i++) { Plane2 plane = clippingPlanes[i]; //A new polygon which is the part of the polygon which is outside of this plane List <MyVector2> outsidePolygon = new List <MyVector2>(); for (int j = 0; j < vertices.Count; j++) { int jPlusOne = MathUtility.ClampListIndex(j + 1, vertices.Count); MyVector2 v1 = vertices[j]; MyVector2 v2 = vertices[jPlusOne]; //Calculate the distance to the plane from each vertex //This is how we will know if they are inside or outside //If they are inside, the distance is positive, which is why the planes normals have to be oriented to the inside float dist_to_v1 = _Geometry.GetSignedDistanceFromPointToPlane(v1, plane); float dist_to_v2 = _Geometry.GetSignedDistanceFromPointToPlane(v2, plane); //TODO: What will happen if they are exactly 0? //Case 1. Both are inside (= to the left), save v2 to the other polygon if (dist_to_v1 >= 0f && dist_to_v2 >= 0f) { vertices_tmp.Add(v2); } //Case 2. Both are outside (= to the right), save v1 else if (dist_to_v1 < 0f && dist_to_v2 < 0f) { outsidePolygon.Add(v2); } //Case 3. Outside -> Inside, save intersection point else if (dist_to_v1 < 0f && dist_to_v2 >= 0f) { MyVector2 rayDir = MyVector2.Normalize(v2 - v1); Ray2 ray = new Ray2(v1, rayDir); MyVector2 intersectionPoint = _Intersections.GetRayPlaneIntersectionPoint(plane, ray); outsidePolygon.Add(intersectionPoint); vertices_tmp.Add(intersectionPoint); vertices_tmp.Add(v2); } //Case 4. Inside -> Outside, save intersection point and v2 else if (dist_to_v1 >= 0f && dist_to_v2 < 0f) { MyVector2 rayDir = MyVector2.Normalize(v2 - v1); Ray2 ray = new Ray2(v1, rayDir); MyVector2 intersectionPoint = _Intersections.GetRayPlaneIntersectionPoint(plane, ray); outsidePolygon.Add(intersectionPoint); outsidePolygon.Add(v2); vertices_tmp.Add(intersectionPoint); } } //Add the polygon outside of this plane to the list of all polygons that are outside of all planes if (outsidePolygon.Count > 0) { finalPolygons.Add(outsidePolygon); } //Add the polygon which was inside of this and previous planes to the polygon we want to test vertices.Clear(); vertices.AddRange(vertices_tmp); vertices_tmp.Clear(); } return(finalPolygons); }