public List <MeshPart> PartialPolySeparate( CuttingPlane plane, HashSet <Vector3> allow_cut ) { //Debug.Log("allow_cut"); //foreach (Vector3 v in allow_cut) Debug.Log(VecStr(v)); //Debug.Log("missing"); List <Tuple <HashSet <int>, HashSet <Vector3>, List <int> > > list = new List <Tuple <HashSet <int>, HashSet <Vector3>, List <int> > >(); AssertMatchingCounts(); // create index groups for (int i = 0; i < indices.Count; i += 3) { int i0 = indices[i], i1 = indices[i + 1], i2 = indices[i + 2]; Vector3 v0 = vertices[i0], v1 = vertices[i1], v2 = vertices[i2]; bool ci0 = allow_cut.Contains(v0), ci1 = allow_cut.Contains(v1), ci2 = allow_cut.Contains(v2); AddIndices(list, vertices, v0, v1, v2, i0, i1, i2, ci0, ci1, ci2); } return(list.ConvertAll(set => { MeshPart part = new MeshPart(false); int doSwap = 0, doStay = 0; // temporary solution (?) foreach (int ind in set.Item3) { Vector3 point = vertices[ind]; if (!allow_cut.Contains(point)) { if (plane.IsAbove(point)) { doSwap++; } else { doStay++; } } ; if (part.indexMap.ContainsKey(ind)) { part.indices.Add(part.indexMap[ind]); } else { part.indexMap.Add(ind, part.vertices.Count); part.indices.Add(part.vertices.Count); part.vertices.Add(point); if (uvs.Count > 0) { part.uvs.Add(uvs[ind]); } } } if (doSwap > doStay) { part.SwapSide(); } part.AssertMatchingCounts(); return part; })); }
public static CutResult Run( GameObject target, CuttingPlane plane, CutParams param ) { CuttingPlane cutting_plane = plane.ToLocalSpace(target.transform); Mesh mesh = target.GetComponent <MeshFilter>().mesh; MeshPart pos = new MeshPart(true), neg = new MeshPart(false); RingGenerator pos_rings = new RingGenerator(), neg_rings = new RingGenerator(); Vector2[] uvs = mesh.uv; Vector3[] vertices = mesh.vertices; Vector3[] normals = mesh.normals; int[] triangles = mesh.triangles; bool addUVs = uvs.Length > 0 && param.innerTextureCoord != null, addNormals = normals.Length > 0; // removed indices HashSet <int> removed = new HashSet <int>(); // divide mesh in half by vertices int i = -1; foreach (Vector3 vertex in vertices) { i++; float dist = cutting_plane.Distance(vertex); if (dist < param.seperationDistance) { removed.Add(i); continue; } if (cutting_plane.IsAbove(vertex)) { pos.indexMap.Add(i, pos.vertices.Count); pos.vertices.Add(vertex); if (addUVs) { pos.uvs.Add(uvs[i]); } if (addNormals) { pos.normals.Add(normals[i]); } } else { neg.indexMap.Add(i, neg.vertices.Count); neg.vertices.Add(vertex); if (addUVs) { neg.uvs.Add(uvs[i]); } if (addNormals) { pos.normals.Add(normals[i]); } } } // if either vertex list is empty and no vertices were removed, the knife plane didn't collide if (pos.vertices.Count == 0 || neg.vertices.Count == 0) { if (!param.allowSingleResult) { return(null); } } // put triangles in correct mesh for (i = 0; i < triangles.Length; i += 3) { // find orignal indices int i_a = triangles[i], i_b = triangles[i + 1], i_c = triangles[i + 2]; // find if these were removed in cut bool r_a = removed.Contains(i_a), r_b = removed.Contains(i_b), r_c = removed.Contains(i_c); // if all are removed, ignore triangle if (r_a && r_b && r_c) { continue; } // find original verticies Vector3 a = vertices[i_a], b = vertices[i_b], c = vertices[i_c]; Vector2 txa, txb, txc; // find original uvs if (uvs.Length > 0) { txa = uvs[i_a]; txb = uvs[i_b]; txc = uvs[i_c]; } else { txa = txb = txc = Vector2.zero; } // find original normals Vector3 na, nb, nc; if (addNormals) { na = normals[i_a]; nb = normals[i_b]; nc = normals[i_c]; } else { na = nb = nc = Vector3.zero; } // seperation check bool aAbove = cutting_plane.IsAbove(a), bAbove = cutting_plane.IsAbove(b), cAbove = cutting_plane.IsAbove(c); if (!r_a && !r_b && !r_c) { // all available if (aAbove && bAbove && cAbove) { // triangle above plane pos.indices.Add(pos.indexMap[i_a]); pos.indices.Add(pos.indexMap[i_b]); pos.indices.Add(pos.indexMap[i_c]); } else if (!aAbove && !bAbove && !cAbove) { // triangle below plane neg.indices.Add(neg.indexMap[i_a]); neg.indices.Add(neg.indexMap[i_b]); neg.indices.Add(neg.indexMap[i_c]); } else { // triangle crosses plane if (aAbove == bAbove) { // a, b, c GenTwoTriangles( cutting_plane, aAbove ? pos : neg, a, b, c, txa, txb, txc, na, nb, nc, i_a, i_b, i_c, aAbove ? pos_rings : neg_rings, addUVs, addNormals, -param.seperationDistance ); GenTriangle( cutting_plane, cAbove ? pos : neg, c, a, b, txc, txa, txb, nc, na, nb, i_c, i_a, i_b, cAbove ? pos_rings : neg_rings, addUVs, addNormals, param.seperationDistance ); } else if (aAbove == cAbove) { // c, a, b GenTwoTriangles( cutting_plane, aAbove ? pos : neg, c, a, b, txc, txa, txb, nc, na, nb, i_c, i_a, i_b, aAbove ? pos_rings : neg_rings, addUVs, addNormals, -param.seperationDistance ); GenTriangle( cutting_plane, bAbove ? pos : neg, b, c, a, txb, txc, txa, nb, nc, na, i_b, i_c, i_a, bAbove ? pos_rings : neg_rings, addUVs, addNormals, param.seperationDistance ); } else if (bAbove == cAbove) { // b, c, a GenTwoTriangles( cutting_plane, bAbove ? pos : neg, b, c, a, txb, txc, txa, nb, nc, na, i_b, i_c, i_a, bAbove ? pos_rings : neg_rings, addUVs, addNormals, -param.seperationDistance ); GenTriangle( cutting_plane, aAbove ? pos : neg, a, b, c, txa, txb, txc, na, nb, nc, i_a, i_b, i_c, aAbove ? pos_rings : neg_rings, addUVs, addNormals, param.seperationDistance ); } } } else if (!r_a && !r_b) { // a and b available if (aAbove != bAbove) { GenTriangle( cutting_plane, aAbove ? pos : neg, a, b, c, txa, txb, txc, na, nb, nc, i_a, i_b, i_c, aAbove ? pos_rings : neg_rings, addUVs, addNormals, param.seperationDistance ); GenTriangle( cutting_plane, bAbove ? pos : neg, b, c, a, txb, txc, txa, nb, nc, na, i_b, i_c, i_a, bAbove ? pos_rings : neg_rings, addUVs, addNormals, param.seperationDistance ); } else { GenTwoTriangles( cutting_plane, aAbove ? pos : neg, a, b, c, txa, txb, txc, na, nb, nc, i_a, i_b, i_c, aAbove ? pos_rings : neg_rings, addUVs, addNormals, -param.seperationDistance ); } } else if (!r_a && !r_c) { // a and c available if (aAbove != cAbove) { GenTriangle( cutting_plane, aAbove ? pos : neg, a, b, c, txa, txb, txc, na, nb, nc, i_a, i_b, i_c, aAbove ? pos_rings : neg_rings, addUVs, addNormals, param.seperationDistance ); GenTriangle( cutting_plane, cAbove ? pos : neg, c, a, b, txc, txa, txb, nc, na, nb, i_c, i_a, i_b, cAbove ? pos_rings : neg_rings, addUVs, addNormals, param.seperationDistance ); } else { GenTwoTriangles( cutting_plane, aAbove ? pos : neg, c, a, b, txc, txa, txb, nc, na, nb, i_c, i_a, i_b, aAbove ? pos_rings : neg_rings, addUVs, addNormals, -param.seperationDistance ); } } else if (!r_b && !r_c) { // b and c available if (bAbove != cAbove) { GenTriangle( cutting_plane, bAbove ? pos : neg, b, c, a, txb, txc, txa, nb, nc, na, i_b, i_c, i_a, bAbove ? pos_rings : neg_rings, addUVs, addNormals, param.seperationDistance ); GenTriangle( cutting_plane, cAbove ? pos : neg, c, a, b, txc, txa, txb, nc, na, nb, i_c, i_a, i_b, cAbove ? pos_rings : neg_rings, addUVs, addNormals, param.seperationDistance ); } else { GenTwoTriangles( cutting_plane, bAbove ? pos : neg, b, c, a, txb, txc, txa, nb, nc, na, i_b, i_c, i_a, bAbove ? pos_rings : neg_rings, addUVs, addNormals, -param.seperationDistance ); } } else if (!r_a) { // a available GenTriangle( cutting_plane, aAbove ? pos : neg, a, b, c, txa, txb, txc, na, nb, nc, i_a, i_b, i_c, aAbove ? pos_rings : neg_rings, addUVs, addNormals, param.seperationDistance ); } else if (!r_b) { // b available GenTriangle( cutting_plane, bAbove ? pos : neg, b, c, a, txb, txc, txa, nb, nc, na, i_b, i_c, i_a, bAbove ? pos_rings : neg_rings, addUVs, addNormals, param.seperationDistance ); } else { // c available GenTriangle( cutting_plane, cAbove ? pos : neg, c, a, b, txc, txa, txb, nc, na, nb, i_c, i_a, i_b, cAbove ? pos_rings : neg_rings, addUVs, addNormals, param.seperationDistance ); } } List <Ring> pos_ring_res = pos_rings.GetRings(param.selfConnectRings, param.ignorePartialRings); List <Ring> neg_ring_res = neg_rings.GetRings(param.selfConnectRings, param.ignorePartialRings); List <Ring> pos_analysis = param.hiearchyAnalysis ? Hierarchy.Analyse(pos_ring_res, cutting_plane.normal) : pos_ring_res; List <Ring> neg_analysis = param.hiearchyAnalysis ? Hierarchy.Analyse(neg_ring_res, cutting_plane.normal) : neg_ring_res; Vector2?innerUV = addUVs ? param.innerTextureCoord : null; // generate seperation meshing foreach (var ring in pos_analysis) { GenerateRingMesh(ring, pos, cutting_plane.normal, innerUV); } foreach (var ring in neg_analysis) { GenerateRingMesh(ring, neg, cutting_plane.normal, innerUV); } List <MeshPart> resParts = new List <MeshPart>(); if (pos.vertices.Count > 0) { resParts.Add(pos); } if (neg.vertices.Count > 0) { resParts.Add(neg); } if (resParts.Count < 2 && !param.allowSingleResult) { return(null); } return(new CutResult(target, resParts, cutting_plane.ToWorldSpace().normal, new List <Ring>(), false)); }
public static CutResult Run( GameObject target, CuttingPlane plane, CutParams param ) { CuttingPlane cutting_plane = plane.ToLocalSpace(target.transform); Mesh mesh = target.GetComponent <MeshFilter>().mesh; MeshPart pos = new MeshPart(true), neg = new MeshPart(false); RingGenerator rings = new RingGenerator(); //DateTime start = DateTime.Now; Vector2[] uvs = mesh.uv; Vector3[] vertices = mesh.vertices; Vector3[] normals = mesh.normals; int[] triangles = mesh.triangles; bool addUVs = uvs.Length > 0 && param.innerTextureCoord != null, addNormals = normals.Length > 0; // divide mesh in half by vertices int i = 0; foreach (Vector3 vertex in vertices) { if (cutting_plane.IsAbove(vertex)) { pos.indexMap.Add(i, pos.vertices.Count); pos.vertices.Add(vertex); if (addUVs) { pos.uvs.Add(uvs[i]); } if (addNormals) { pos.normals.Add(normals[i]); } } else { neg.indexMap.Add(i, neg.vertices.Count); neg.vertices.Add(vertex); if (addUVs) { neg.uvs.Add(uvs[i]); } if (addNormals) { neg.normals.Add(normals[i]); } } i++; } //Debug.Log((DateTime.Now-start).TotalMilliseconds+" elapsed (1)"); //start = DateTime.Now; // if either vertex list is empty the knife plane didn't collide if (pos.vertices.Count == 0 || neg.vertices.Count == 0) { if (!param.allowSingleResult) { return(null); } } // put triangles in correct mesh for (i = 0; i < triangles.Length; i += 3) { // find orignal indices int i_a = triangles[i], i_b = triangles[i + 1], i_c = triangles[i + 2]; // find original verticies Vector3 a = vertices[i_a], b = vertices[i_b], c = vertices[i_c]; // find original uvs Vector2 txa, txb, txc; if (addUVs) { txa = uvs[i_a]; txb = uvs[i_b]; txc = uvs[i_c]; } else { txa = txb = txc = Vector3.zero; } // find original normals Vector3 na, nb, nc; if (addNormals) { na = normals[i_a]; nb = normals[i_b]; nc = normals[i_c]; } else { na = nb = nc = Vector3.zero; } // seperation check bool aAbove = cutting_plane.IsAbove(a), bAbove = cutting_plane.IsAbove(b), cAbove = cutting_plane.IsAbove(c); if (aAbove && bAbove && cAbove) { // triangle above plane pos.indices.Add(pos.indexMap[i_a]); pos.indices.Add(pos.indexMap[i_b]); pos.indices.Add(pos.indexMap[i_c]); } else if (!aAbove && !bAbove && !cAbove) { // triangle below plane neg.indices.Add(neg.indexMap[i_a]); neg.indices.Add(neg.indexMap[i_b]); neg.indices.Add(neg.indexMap[i_c]); } else { // triangle crosses plane // call Util.GenTriangles if (aAbove == bAbove) { // a, b, c GenTriangles( cutting_plane, aAbove ? pos : neg, !aAbove ? pos : neg, a, b, c, txa, txb, txc, na, nb, nc, i_a, i_b, i_c, rings, addUVs, addNormals ); } else if (aAbove == cAbove) { // c, a, b GenTriangles( cutting_plane, aAbove ? pos : neg, !aAbove ? pos : neg, c, a, b, txc, txa, txb, na, nb, nc, i_c, i_a, i_b, rings, addUVs, addNormals ); } else if (bAbove == cAbove) { // b, c, a (use bAbove) GenTriangles( cutting_plane, bAbove ? pos : neg, !bAbove ? pos : neg, b, c, a, txb, txc, txa, na, nb, nc, i_b, i_c, i_a, rings, addUVs, addNormals ); } } } //Debug.Log((DateTime.Now-start).TotalMilliseconds+" elapsed (2)"); //start = DateTime.Now; List <Ring> ringOut = rings.GetRings(param.selfConnectRings, param.ignorePartialRings); List <Ring> analysis = param.hiearchyAnalysis ? Hierarchy.Analyse(ringOut, cutting_plane.normal) : ringOut; Vector2?innerUV = addUVs ? param.innerTextureCoord : null; // generate seperation meshing foreach (var ring in analysis) { GenerateRingMesh(ring, pos, cutting_plane.normal, innerUV, addNormals); GenerateRingMesh(ring, neg, cutting_plane.normal, innerUV, addNormals); } //Debug.Log((DateTime.Now-start).TotalMilliseconds+" elapsed (3)"); //start = DateTime.Now; return(new CutResult(target, cutting_plane.ToWorldSpace().normal, ringOut, pos, neg)); }
public static CutResult Run( GameObject target, CuttingPlane plane, CutParams param ) { CuttingPlane cutting_plane = plane.ToLocalSpace(target.transform); Mesh mesh = target.GetComponent <MeshFilter>().mesh; MeshPart part = new MeshPart(false); Vector2[] uvs = mesh.uv; Vector3[] vertices = mesh.vertices; int[] triangles = mesh.triangles; // // First we find the rings that are eligable for cutting // RingGenerator rings = new RingGenerator(); int i; for (i = 0; i < triangles.Length; i += 3) { // find orignal indices int i_a = triangles[i], i_b = triangles[i + 1], i_c = triangles[i + 2]; // find original verticies Vector3 a = vertices[i_a], b = vertices[i_b], c = vertices[i_c]; // seperation check bool aAbove = cutting_plane.IsAbove(a), bAbove = cutting_plane.IsAbove(b), cAbove = cutting_plane.IsAbove(c); if (aAbove == bAbove && aAbove == cAbove) { continue; } if (aAbove == bAbove) { // a, b, c GenIntersection( cutting_plane, a, b, c, rings ); } else if (aAbove == cAbove) { // c, a, b GenIntersection( cutting_plane, c, a, b, rings ); } else if (bAbove == cAbove) { // b, c, a GenIntersection( cutting_plane, b, c, a, rings ); } } Vector3 point = target.transform.InverseTransformPoint(param.originPoint); List <Ring> resulting_rings = new List <Ring>(); foreach (Ring ring in rings.GetRings(param.selfConnectRings, param.ignorePartialRings)) { Vector3 vec = ring.FurthestVectorToRingPerimeter(point); vec = target.transform.TransformVector(vec); // Debug.DrawRay(param.originPoint,vec,Color.blue,10); float mag = vec.magnitude; Debug.Log(mag); if (mag < param.maxCutDistance) { resulting_rings.Add(ring); } } if (resulting_rings.Count == 0) { return(null); } // Debug.Log(resulting_rings.Count); HashSet <Vector3> allow_cut = new HashSet <Vector3>(); foreach (Ring ring in resulting_rings) { foreach (Vector3 v in ring.verts) { allow_cut.Add(v); } } // // Start of cutting // bool addUVs = uvs.Length > 0 && param.innerTextureCoord != null; // transfer vertices into MeshPart i = 0; foreach (Vector3 vertex in vertices) { part.indexMap.Add(i, part.vertices.Count); part.vertices.Add(vertex); if (addUVs) { part.uvs.Add(uvs[i]); } i++; } // process triangles for (i = 0; i < triangles.Length; i += 3) { // find orignal indices int i_a = triangles[i], i_b = triangles[i + 1], i_c = triangles[i + 2]; // find original verticies Vector3 a = vertices[i_a], b = vertices[i_b], c = vertices[i_c]; Vector2 txa, txb, txc; // find original uvs if (uvs.Length > 0) { txa = uvs[i_a]; txb = uvs[i_b]; txc = uvs[i_c]; } else { txa = txb = txc = Vector2.zero; } // seperation check bool aAbove = cutting_plane.IsAbove(a), bAbove = cutting_plane.IsAbove(b), cAbove = cutting_plane.IsAbove(c); if (aAbove == bAbove && aAbove == cAbove) { // triangle on one side of plane part.indices.Add(part.indexMap[i_a]); part.indices.Add(part.indexMap[i_b]); part.indices.Add(part.indexMap[i_c]); } else { // triangle crosses plane if (aAbove == bAbove) { // a, b, c GenPartialTriangles( cutting_plane, part, a, b, c, txa, txb, txc, i_a, i_b, i_c, allow_cut, addUVs ); } else if (aAbove == cAbove) { // c, a, b GenPartialTriangles( cutting_plane, part, c, a, b, txc, txa, txb, i_c, i_a, i_b, allow_cut, addUVs ); } else if (bAbove == cAbove) { // b, c, a GenPartialTriangles( cutting_plane, part, b, c, a, txb, txc, txa, i_b, i_c, i_a, allow_cut, addUVs ); } } } List <Ring> analysis = param.hiearchyAnalysis ? Hierarchy.Analyse(resulting_rings, cutting_plane.normal) : resulting_rings; List <MeshPart> parts = part.PartialPolySeparate(cutting_plane, allow_cut); if (parts.Count < 2 && !param.allowSingleResult) { return(null); } // generate seperation meshing if (parts.Count > 0) { foreach (var ring in analysis) { foreach (var resPart in parts) { GenerateRingMesh(ring, resPart, cutting_plane.normal, param.innerTextureCoord); } } } return(new CutResult(target, parts, cutting_plane.ToWorldSpace().normal, resulting_rings, true)); }