List <GameObject> IterativeCut(GameObject obj, int count) { CutParams param = new CutParams(false, false, false, false, Vector3.zero, float.PositiveInfinity, 0, Vector3.zero); try { CutResult res = API.PerformCut(obj, CuttingPlane.RandomInWorldSpace(obj.transform.position), param); res.DestroyObject(); if (res == null) { return(new List <GameObject>()); } if (count > 1) { List <GameObject> ret = new List <GameObject>(); foreach (CutObj robj in res.Results) { ret.AddRange( IterativeCut( robj .CopyParent() .CopyMaterial() .CopyVelocity() .WithDriftVelocity(0.2f) .Instantiate(), count - 1 ) ); } return(ret); } else { return(res.ConvertAll( robj => robj .CopyParent() .CopyMaterial() .WithCollider() .WithRenderer() .CopyVelocity() .WithDriftVelocity(0.2f) .Instantiate() )); } } catch (MeshUtilsException e) { Debug.LogWarning(e); obj.AddComponent <Rigidbody>(); obj.AddComponent <MeshRenderer>(); obj.AddComponent <MeshCollider>(); return(new List <GameObject>() { obj }); } }
void Test() { //for (int i = 0; i < 10; i++) { foreach (GameObject obj in objs) { Debug.Log(obj); DateTime start = DateTime.Now; CutParams p = new CutParams(false, false, false, false, Vector3.zero, 0.2f, 0, Vector2.zero); CuttingPlane pl = CuttingPlane.InWorldSpace(obj.transform.up, obj.transform.position); if (GapAlgorithm.Run(obj, pl, p) == null) { throw new Exception("test failed"); } Debug.Log((DateTime.Now - start).TotalMilliseconds + " elapsed"); } //} }
public void OnCollisionEnter(Collision col) { if (ignoreColliders.Contains(col.collider)) { ignoreColliders.Remove(col.collider); return; } Cuttable cuttable; if (!col.gameObject.TryGetComponent <Cuttable>(out cuttable)) { return; } Vector3 cutDir = directionsAreNormals ? TransformNormal(cutDirection, transform) : transform.TransformDirection(cutDirection); float relVel = (col.relativeVelocity - Vector3.Project(col.relativeVelocity, cutDir)).magnitude; // Debug.Log("vel: "+relVel); // Debug.DrawRay(col.GetContact(0).point,col.relativeVelocity-Vector3.Project(col.relativeVelocity,cutDir)/relVel,Color.blue,1); if (minimumVelocity > relVel) { return; } Vector3 dir = omnidirectionalMode ? -col.relativeVelocity : cutDir; Vector3 edge = directionsAreNormals ? TransformNormal(edgeDirection, transform) : transform.TransformDirection(edgeDirection); Vector3 angleProjection = Vector3.ProjectOnPlane(gameObject.GetComponentInParent <Rigidbody>().velocity, edge); // Debug.Log("angle: "+Vector3.Angle(angleProjection,cutDir)); // if (Vector3.Angle(angleProjection,cutDir) > 70) Debug.Break(); // Debug.DrawRay(col.GetContact(0).point,angleProjection,Color.red,1); // Debug.DrawRay(col.GetContact(0).point,cutDir,Color.green,1); // Debug.DrawRay(col.GetContact(0).point,-col.relativeVelocity,Color.blue,1); if (Vector3.Angle(angleProjection, cutDir) > maxAngle) { return; } Vector3 normal = Vector3.Cross(dir, edge).normalized; Vector3 pointInPlane = useContactPoint ? col.GetContact(0).point : transform.position; CuttingPlane plane = CuttingPlane.InWorldSpace(normal, pointInPlane); CutParams param = new CutParams( cuttable.checkForHoles, true, cuttable.closeOpenSurfaces, cuttable.allowOpenSurfaces, Vector3.zero, float.PositiveInfinity, 0, cuttable.innerTextureCoordinate ); CutResult result = PerformCut(col.gameObject, plane, param); if (result != null) { if (cuttable.polySeparate) { result.PolySeparate(); } result.DestroyObject(); foreach (CutObj res in result.Results) { GameObject resObj = res .UseDefaults() .WithDriftVelocity(driftVelocity) .WithSeperationDistance(seperationDistance) .WithRingWidth(cuttable.highlightWidth) .WithRingColor(cuttable.highLightColor) .FallbackToColor(new Color(1, 0.1f, 0.1f)) .Instantiate(); cuttable.CopyTo(resObj); ignoreColliders.Add(resObj.GetComponent <Collider>()); } } }
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 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 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)); }