public CHull canMerge(CHull a, CHull b) { if (!a.overlap(b)) // if their AABB's (with a little slop) don't overlap, then return. { return(null); } CHull ret = null; // ok..we are going to combine both meshes into a single mesh // and then we are going to compute the concavity... VertexPool vc = new VertexPool(); List <int> indices = new List <int>(); getMesh(a.mResult, vc, indices); getMesh(b.mResult, vc, indices); // 20131224 not used int vcount = vc.GetSize(); List <float3> vertices = vc.GetVertices(); int tcount = indices.Count / 3; //don't do anything if hull is empty if (tcount == 0) { vc.Clear(); return(null); } HullResult hresult = new HullResult(); HullDesc desc = new HullDesc(); desc.SetHullFlag(HullFlag.QF_TRIANGLES); desc.Vertices = vertices; HullError hret = HullUtils.CreateConvexHull(desc, ref hresult); if (hret == HullError.QE_OK) { float combineVolume = Concavity.computeMeshVolume(hresult.OutputVertices, hresult.Indices); float sumVolume = a.mVolume + b.mVolume; float percent = (sumVolume * 100) / combineVolume; if (percent >= (100.0f - MERGE_PERCENT)) { ConvexResult cr = new ConvexResult(hresult.OutputVertices, hresult.Indices); ret = new CHull(cr); } } vc.Clear(); return(ret); }
// compute's how 'concave' this object is and returns the total volume of the // convex hull as well as the volume of the 'concavity' which was found. public static float computeConcavity(List<float3> vertices, List<int> indices, ref float4 plane, ref float volume) { float cret = 0f; volume = 1f; HullResult result = new HullResult(); HullDesc desc = new HullDesc(); desc.MaxFaces = 256; desc.MaxVertices = 256; desc.SetHullFlag(HullFlag.QF_TRIANGLES); desc.Vertices = vertices; HullError ret = HullUtils.CreateConvexHull(desc, ref result); if (ret == HullError.QE_OK) { volume = computeMeshVolume2(result.OutputVertices, result.Indices); // ok..now..for each triangle on the original mesh.. // we extrude the points to the nearest point on the hull. List<CTri> tris = new List<CTri>(); for (int i = 0; i < result.Indices.Count / 3; i++) { int i1 = result.Indices[i * 3 + 0]; int i2 = result.Indices[i * 3 + 1]; int i3 = result.Indices[i * 3 + 2]; float3 p1 = result.OutputVertices[i1]; float3 p2 = result.OutputVertices[i2]; float3 p3 = result.OutputVertices[i3]; CTri t = new CTri(p1, p2, p3, i1, i2, i3); tris.Add(t); } // we have not pre-computed the plane equation for each triangle in the convex hull.. float totalVolume = 0; List<CTri> ftris = new List<CTri>(); // 'feature' triangles. List<CTri> input_mesh = new List<CTri>(); 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]; float3 p1 = vertices[i1]; float3 p2 = vertices[i2]; float3 p3 = vertices[i3]; CTri t = new CTri(p1, p2, p3, i1, i2, i3); input_mesh.Add(t); } 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]; float3 p1 = vertices[i1]; float3 p2 = vertices[i2]; float3 p3 = vertices[i3]; CTri t = new CTri(p1, p2, p3, i1, i2, i3); featureMatch(t, tris, input_mesh); if (t.mConcavity > 0.05f) { float v = t.getVolume(); totalVolume += v; ftris.Add(t); } } SplitPlane.computeSplitPlane(vertices, indices, ref plane); cret = totalVolume; } return cret; }
// compute's how 'concave' this object is and returns the total volume of the // convex hull as well as the volume of the 'concavity' which was found. public static float computeConcavity(List <float3> vertices, List <int> indices, ref float4 plane, ref float volume) { float cret = 0f; volume = 1f; HullResult result = new HullResult(); HullDesc desc = new HullDesc(); desc.MaxFaces = 256; desc.MaxVertices = 256; desc.SetHullFlag(HullFlag.QF_TRIANGLES); desc.Vertices = vertices; HullError ret = HullUtils.CreateConvexHull(desc, ref result); if (ret == HullError.QE_OK) { volume = computeMeshVolume2(result.OutputVertices, result.Indices); // ok..now..for each triangle on the original mesh.. // we extrude the points to the nearest point on the hull. List <CTri> tris = new List <CTri>(); for (int i = 0; i < result.Indices.Count / 3; i++) { int i1 = result.Indices[i * 3 + 0]; int i2 = result.Indices[i * 3 + 1]; int i3 = result.Indices[i * 3 + 2]; float3 p1 = result.OutputVertices[i1]; float3 p2 = result.OutputVertices[i2]; float3 p3 = result.OutputVertices[i3]; CTri t = new CTri(p1, p2, p3, i1, i2, i3); tris.Add(t); } // we have not pre-computed the plane equation for each triangle in the convex hull.. float totalVolume = 0; List <CTri> ftris = new List <CTri>(); // 'feature' triangles. List <CTri> input_mesh = new List <CTri>(); 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]; float3 p1 = vertices[i1]; float3 p2 = vertices[i2]; float3 p3 = vertices[i3]; CTri t = new CTri(p1, p2, p3, i1, i2, i3); input_mesh.Add(t); } 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]; float3 p1 = vertices[i1]; float3 p2 = vertices[i2]; float3 p3 = vertices[i3]; CTri t = new CTri(p1, p2, p3, i1, i2, i3); featureMatch(t, tris, input_mesh); if (t.mConcavity > 0.05f) { float v = t.getVolume(); totalVolume += v; ftris.Add(t); } } SplitPlane.computeSplitPlane(vertices, indices, ref plane); cret = totalVolume; } return(cret); }
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) { // 20131224 not used int vcount = vfront.GetSize(); List<float3> vertices2 = vfront.GetVertices(); for (int i = 0; i < vertices2.Count; i++) vertices2[i] = new float3(vertices2[i]); // 20131224 not used int tcount = ifront.Count / 3; calcConvexDecomposition(vertices2, ifront, callback, masterVolume, depth + 1, maxDepth, concavePercent, mergePercent); } ifront.Clear(); vfront.Clear(); if (iback.Count > 0) { // 20131224 not used int vcount = vback.GetSize(); List<float3> vertices2 = vback.GetVertices(); // 20131224 not used int tcount = iback.Count / 3; calcConvexDecomposition(vertices2, iback, callback, masterVolume, depth + 1, maxDepth, concavePercent, mergePercent); } iback.Clear(); vback.Clear(); }
public int process(DecompDesc desc) { int ret = 0; MAXDEPTH = (int)desc.mDepth; CONCAVE_PERCENT = desc.mCpercent; MERGE_PERCENT = desc.mPpercent; ConvexDecomposition.calcConvexDecomposition(desc.mVertices, desc.mIndices, ConvexDecompResult, 0f, 0, MAXDEPTH, CONCAVE_PERCENT, MERGE_PERCENT); while (combineHulls()) // keep combinging hulls until I can't combine any more... ; int i; for (i = 0; i < mChulls.Count; i++) { CHull cr = mChulls[i]; // before we hand it back to the application, we need to regenerate the hull based on the // limits given by the user. ConvexResult c = cr.mResult; // the high resolution hull... HullResult result = new HullResult(); HullDesc hdesc = new HullDesc(); hdesc.SetHullFlag(HullFlag.QF_TRIANGLES); hdesc.Vertices = c.HullVertices; hdesc.MaxVertices = desc.mMaxVertices; // maximum number of vertices allowed in the output if (desc.mSkinWidth != 0f) { hdesc.SkinWidth = desc.mSkinWidth; hdesc.SetHullFlag(HullFlag.QF_SKIN_WIDTH); // do skin width computation. } HullError ret2 = HullUtils.CreateConvexHull(hdesc, ref result); if (ret2 == HullError.QE_OK) { ConvexResult r = new ConvexResult(result.OutputVertices, result.Indices); r.mHullVolume = Concavity.computeMeshVolume(result.OutputVertices, result.Indices); // the volume of the hull. // compute the best fit OBB //computeBestFitOBB(result.mNumOutputVertices, result.mOutputVertices, sizeof(float) * 3, r.mOBBSides, r.mOBBTransform); //r.mOBBVolume = r.mOBBSides[0] * r.mOBBSides[1] * r.mOBBSides[2]; // compute the OBB volume. //fm_getTranslation(r.mOBBTransform, r.mOBBCenter); // get the translation component of the 4x4 matrix. //fm_matrixToQuat(r.mOBBTransform, r.mOBBOrientation); // extract the orientation as a quaternion. //r.mSphereRadius = computeBoundingSphere(result.mNumOutputVertices, result.mOutputVertices, r.mSphereCenter); //r.mSphereVolume = fm_sphereVolume(r.mSphereRadius); mCallback(r); } result = null; cr.Dispose(); } ret = mChulls.Count; mChulls.Clear(); return ret; }
public CHull canMerge(CHull a, CHull b) { if (!a.overlap(b)) // if their AABB's (with a little slop) don't overlap, then return. return null; CHull ret = null; // ok..we are going to combine both meshes into a single mesh // and then we are going to compute the concavity... VertexPool vc = new VertexPool(); List<int> indices = new List<int>(); getMesh(a.mResult, vc, indices); getMesh(b.mResult, vc, indices); // 20131224 not used int vcount = vc.GetSize(); List<float3> vertices = vc.GetVertices(); int tcount = indices.Count / 3; //don't do anything if hull is empty if (tcount == 0) { vc.Clear(); return null; } HullResult hresult = new HullResult(); HullDesc desc = new HullDesc(); desc.SetHullFlag(HullFlag.QF_TRIANGLES); desc.Vertices = vertices; HullError hret = HullUtils.CreateConvexHull(desc, ref hresult); if (hret == HullError.QE_OK) { float combineVolume = Concavity.computeMeshVolume(hresult.OutputVertices, hresult.Indices); float sumVolume = a.mVolume + b.mVolume; float percent = (sumVolume * 100) / combineVolume; if (percent >= (100.0f - MERGE_PERCENT)) { ConvexResult cr = new ConvexResult(hresult.OutputVertices, hresult.Indices); ret = new CHull(cr); } } vc.Clear(); return ret; }
public int process(DecompDesc desc) { int ret = 0; MAXDEPTH = (int)desc.mDepth; CONCAVE_PERCENT = desc.mCpercent; MERGE_PERCENT = desc.mPpercent; ConvexDecomposition.calcConvexDecomposition(desc.mVertices, desc.mIndices, ConvexDecompResult, 0f, 0, MAXDEPTH, CONCAVE_PERCENT, MERGE_PERCENT); while (combineHulls()) // keep combinging hulls until I can't combine any more... { ; } int i; for (i = 0; i < mChulls.Count; i++) { CHull cr = mChulls[i]; // before we hand it back to the application, we need to regenerate the hull based on the // limits given by the user. ConvexResult c = cr.mResult; // the high resolution hull... HullResult result = new HullResult(); HullDesc hdesc = new HullDesc(); hdesc.SetHullFlag(HullFlag.QF_TRIANGLES); hdesc.Vertices = c.HullVertices; hdesc.MaxVertices = desc.mMaxVertices; // maximum number of vertices allowed in the output if (desc.mSkinWidth != 0f) { hdesc.SkinWidth = desc.mSkinWidth; hdesc.SetHullFlag(HullFlag.QF_SKIN_WIDTH); // do skin width computation. } HullError ret2 = HullUtils.CreateConvexHull(hdesc, ref result); if (ret2 == HullError.QE_OK) { ConvexResult r = new ConvexResult(result.OutputVertices, result.Indices); r.mHullVolume = Concavity.computeMeshVolume(result.OutputVertices, result.Indices); // the volume of the hull. // compute the best fit OBB //computeBestFitOBB(result.mNumOutputVertices, result.mOutputVertices, sizeof(float) * 3, r.mOBBSides, r.mOBBTransform); //r.mOBBVolume = r.mOBBSides[0] * r.mOBBSides[1] * r.mOBBSides[2]; // compute the OBB volume. //fm_getTranslation(r.mOBBTransform, r.mOBBCenter); // get the translation component of the 4x4 matrix. //fm_matrixToQuat(r.mOBBTransform, r.mOBBOrientation); // extract the orientation as a quaternion. //r.mSphereRadius = computeBoundingSphere(result.mNumOutputVertices, result.mOutputVertices, r.mSphereCenter); //r.mSphereVolume = fm_sphereVolume(r.mSphereRadius); mCallback(r); } result = null; cr.Dispose(); } ret = mChulls.Count; mChulls.Clear(); return(ret); }
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) { // 20131224 not used int vcount = vfront.GetSize(); List <float3> vertices2 = vfront.GetVertices(); for (int i = 0; i < vertices2.Count; i++) { vertices2[i] = new float3(vertices2[i]); } // 20131224 not used int tcount = ifront.Count / 3; calcConvexDecomposition(vertices2, ifront, callback, masterVolume, depth + 1, maxDepth, concavePercent, mergePercent); } ifront.Clear(); vfront.Clear(); if (iback.Count > 0) { // 20131224 not used int vcount = vback.GetSize(); List <float3> vertices2 = vback.GetVertices(); // 20131224 not used int tcount = iback.Count / 3; calcConvexDecomposition(vertices2, iback, callback, masterVolume, depth + 1, maxDepth, concavePercent, mergePercent); } iback.Clear(); vback.Clear(); }