public static PlaneTriResult planeTriIntersection(float4 plane, FaceTri triangle, float epsilon, ref float3[] front, out int fcount, ref float3[] back, out int bcount) { fcount = 0; bcount = 0; // get the three vertices of the triangle. float3 p1 = triangle.P1; float3 p2 = triangle.P2; float3 p3 = triangle.P3; PlaneTriResult r1 = getSidePlane(p1, plane, epsilon); // compute the side of the plane each vertex is on PlaneTriResult r2 = getSidePlane(p2, plane, epsilon); PlaneTriResult r3 = getSidePlane(p3, plane, epsilon); if (r1 == r2 && r1 == r3) // if all three vertices are on the same side of the plane. { if (r1 == PlaneTriResult.PTR_FRONT) // if all three are in front of the plane, then copy to the 'front' output triangle. { add(p1, front, ref fcount); add(p2, front, ref fcount); add(p3, front, ref fcount); } else { add(p1, back, ref bcount); // if all three are in 'back' then copy to the 'back' output triangle. add(p2, back, ref bcount); add(p3, back, ref bcount); } return(r1); // if all three points are on the same side of the plane return result } // ok.. we need to split the triangle at the plane. // First test ray segment P1 to P2 if (r1 == r2) // if these are both on the same side... { if (r1 == PlaneTriResult.PTR_FRONT) { add(p1, front, ref fcount); add(p2, front, ref fcount); } else { add(p1, back, ref bcount); add(p2, back, ref bcount); } } else { float3 split = new float3(); intersect(p1, p2, split, plane); if (r1 == PlaneTriResult.PTR_FRONT) { add(p1, front, ref fcount); add(split, front, ref fcount); add(split, back, ref bcount); add(p2, back, ref bcount); } else { add(p1, back, ref bcount); add(split, back, ref bcount); add(split, front, ref fcount); add(p2, front, ref fcount); } } // Next test ray segment P2 to P3 if (r2 == r3) // if these are both on the same side... { if (r3 == PlaneTriResult.PTR_FRONT) { add(p3, front, ref fcount); } else { add(p3, back, ref bcount); } } else { float3 split = new float3(); // split the point intersect(p2, p3, split, plane); if (r3 == PlaneTriResult.PTR_FRONT) { add(split, front, ref fcount); add(split, back, ref bcount); add(p3, front, ref fcount); } else { add(split, front, ref fcount); add(split, back, ref bcount); add(p3, back, ref bcount); } } // Next test ray segment P3 to P1 if (r3 != r1) // if these are both on the same side... { float3 split = new float3(); // split the point intersect(p3, p1, split, plane); if (r1 == PlaneTriResult.PTR_FRONT) { add(split, front, ref fcount); add(split, back, ref bcount); } else { add(split, front, ref fcount); add(split, back, ref bcount); } } return(PlaneTriResult.PTR_SPLIT); }
public static void calcConvexDecomposition(List <float3> vertices, List <int> indices, ConvexDecompositionCallback callback, float masterVolume, int depth, int maxDepth, float concavePercent, float mergePercent) { float4 plane = new float4(); bool split = false; if (depth < maxDepth) { float volume = 0f; float c = Concavity.computeConcavity(vertices, indices, ref plane, ref volume); if (depth == 0) { masterVolume = volume; } float percent = (c * 100.0f) / masterVolume; if (percent > concavePercent) // if great than 5% of the total volume is concave, go ahead and keep splitting. { split = true; } } if (depth >= maxDepth || !split) { HullResult result = new HullResult(); HullDesc desc = new HullDesc(); desc.SetHullFlag(HullFlag.QF_TRIANGLES); desc.Vertices = vertices; HullError ret = HullUtils.CreateConvexHull(desc, ref result); if (ret == HullError.QE_OK) { ConvexResult r = new ConvexResult(result.OutputVertices, result.Indices); callback(r); } return; } List <int> ifront = new List <int>(); List <int> iback = new List <int>(); VertexPool vfront = new VertexPool(); VertexPool vback = new VertexPool(); // ok..now we are going to 'split' all of the input triangles against this plane! for (int i = 0; i < indices.Count / 3; i++) { int i1 = indices[i * 3 + 0]; int i2 = indices[i * 3 + 1]; int i3 = indices[i * 3 + 2]; FaceTri t = new FaceTri(vertices, i1, i2, i3); float3[] front = new float3[4]; float3[] back = new float3[4]; int fcount = 0; int bcount = 0; PlaneTriResult result = PlaneTri.planeTriIntersection(plane, t, 0.00001f, ref front, out fcount, ref back, out bcount); if (fcount > 4 || bcount > 4) { result = PlaneTri.planeTriIntersection(plane, t, 0.00001f, ref front, out fcount, ref back, out bcount); } switch (result) { case PlaneTriResult.PTR_FRONT: Debug.Assert(fcount == 3); addTri(vfront, ifront, front[0], front[1], front[2]); break; case PlaneTriResult.PTR_BACK: Debug.Assert(bcount == 3); addTri(vback, iback, back[0], back[1], back[2]); break; case PlaneTriResult.PTR_SPLIT: Debug.Assert(fcount >= 3 && fcount <= 4); Debug.Assert(bcount >= 3 && bcount <= 4); addTri(vfront, ifront, front[0], front[1], front[2]); addTri(vback, iback, back[0], back[1], back[2]); if (fcount == 4) { addTri(vfront, ifront, front[0], front[2], front[3]); } if (bcount == 4) { addTri(vback, iback, back[0], back[2], back[3]); } break; } } // ok... here we recursively call if (ifront.Count > 0) { int vcount = vfront.GetSize(); List <float3> vertices2 = vfront.GetVertices(); for (int i = 0; i < vertices2.Count; i++) { vertices2[i] = new float3(vertices2[i]); } int tcount = ifront.Count / 3; calcConvexDecomposition(vertices2, ifront, callback, masterVolume, depth + 1, maxDepth, concavePercent, mergePercent); } ifront.Clear(); vfront.Clear(); if (iback.Count > 0) { int vcount = vback.GetSize(); List <float3> vertices2 = vback.GetVertices(); int tcount = iback.Count / 3; calcConvexDecomposition(vertices2, iback, callback, masterVolume, depth + 1, maxDepth, concavePercent, mergePercent); } iback.Clear(); vback.Clear(); }