/// Minimize the angle between adjacent triangles. Almost the same as mean curvature minimization public void MinimizeDihedralAngle(HMesh m, int max_iter = 10000, bool alpha = false, double gamma = 4.0) { DihedralEnergy energy_fun = new DihedralEnergy(gamma, alpha); PriorityQueueOptimization(m, energy_fun); }
// should only be called by HMesh.CreateVertex public Vertex(HMesh hmesh) { this.hmesh = hmesh; position = Vector3.zero; uv1 = Vector2.zero; uv2 = Vector2.zero; }
// // -----o------ // // Remove boundary vertices with two edge (one ingoing + one outgoing) where edges are parallel // Remove non-boundary vertices with only two adjacent faces where edges are parallel // // The method undo edge split by removing the extra vertex public static int DissolveUnneededVertices(HMesh hmesh) { int count = 0; foreach (var vert in hmesh.GetVertices()) { var circ = vert.Circulate(); double parallelEpsilon = 1E-15; if (vert.IsBoundary() && circ.Count == 1 && VertexDistOnDissolve(vert, circ[0].vert, circ[0].prev.prev.vert) < hmesh.zeroMagnitudeTreshold) { vert.Dissolve(); count++; } else if (!vert.IsBoundary() && circ.Count == 2) { if (VertexDistOnDissolve(vert, circ[0].vert, circ[1].vert) < hmesh.zeroMagnitudeTreshold) { vert.Dissolve(); count++; } } } return(count); }
public static HMesh CreateTestMeshQuad() { HMesh mesh = new HMesh(); var face = mesh.CreateFace(); var edges = new Halfedge[]{ mesh.CreateHalfedge(), mesh.CreateHalfedge(), mesh.CreateHalfedge(), mesh.CreateHalfedge(), }; var verts = new Vertex[]{ mesh.CreateVertex(new Vector3(0,0,0)), mesh.CreateVertex(new Vector3(1,0,0)), mesh.CreateVertex(new Vector3(1,0,1)), mesh.CreateVertex(new Vector3(0,0,1)), }; for (int i=0;i<4;i++){ edges[i].Link(face); edges[i].next = edges[(i+1)%4]; edges[(i+1)%4].prev = edges[i]; edges[i].vert = verts[i]; verts[i].halfedge = edges[i].next; } return mesh; }
static List <Vertex> CreateBoundingTriangle(HMesh mesh, List <Vector3D> position) { BoundsD b = new BoundsD(position[0], Vector3D.zero); for (int i = 1; i < position.Count; i++) { b.Encapsulate(position[i]); } // encapsulate triangle b.center = b.center + b.extents * 3.1f; b.extents = b.extents * 10000f; Vector3D v1 = b.min; Vector3D v2 = b.min + Vector3D.forward * b.size.z; Vector3D v3 = b.min + Vector3D.right * b.size.x; Face face = mesh.CreateTriangle(v1, v2, v3); List <Vertex> boundingVertices = new List <Vertex>(); foreach (var he in face.Circulate()) { boundingVertices.Add(he.vert); } return(boundingVertices); }
public static HMesh CreateTestMeshPolygon(EarClipTest clip) { HMesh mesh = new HMesh(); Transform t = clip.transform; var face = mesh.CreateFace(); var edges = new Halfedge[t.childCount]; var verts = new List <Vertex>(); for (int i = 0; i < t.childCount; i++) { edges[i] = mesh.CreateHalfedge(); verts.Add(mesh.CreateVertex(t.GetChild(i).position)); } for (int i = 0; i < t.childCount; i++) { edges[i].Link(face); edges[i].next = edges[(i + 1) % t.childCount]; edges[(i + 1) % t.childCount].prev = edges[i]; edges[i].vert = verts[i]; } return(mesh); }
public static HMesh CreateTestMeshQuad() { HMesh mesh = new HMesh(); var face = mesh.CreateFace(); var edges = new[] { mesh.CreateHalfedge(), mesh.CreateHalfedge(), mesh.CreateHalfedge(), mesh.CreateHalfedge(), }; var verts = new[] { mesh.CreateVertex(new Vector3(0, 0, 0)), mesh.CreateVertex(new Vector3(1, 0, 0)), mesh.CreateVertex(new Vector3(1, 0, 1)), mesh.CreateVertex(new Vector3(0, 0, 1)), }; for (int i = 0; i < 4; i++) { edges[i].Link(face); edges[i].next = edges[(i + 1) % 4]; edges[(i + 1) % 4].prev = edges[i]; edges[i].vert = verts[i]; } return(mesh); }
public static HMesh Triangulate(List <Vector3> positions) { HMesh mesh = new HMesh(); Stack <Halfedge> flipStack = new Stack <Halfedge>(); List <Vertex> boundingVertices = CreateBoundingTriangle(mesh, positions); foreach (var pos in positions) { Face triangle = FindTriangleWithinPoint(mesh, pos); AddEdgesToFlipStack(triangle, flipStack); InsertPointInTriangle(triangle, pos); while (flipStack.Count > 0) { var e = flipStack.Pop(); if (!IsLocalDelaunay(e)) { var opp = e.opp; var check1 = opp.next; var check2 = check1.next; flipStack.Push(check1); flipStack.Push(check2); e.Flip(); } } } return(mesh); }
public static HMesh CreateTestMeshTriangle() { HMesh mesh = new HMesh(); mesh.CreateTriangle(new Vector3(0, 0, 0), new Vector3(1, 0, 0), new Vector3(0, 0, 1)); return(mesh); }
public void SetDestroyed() { _hmesh = null; #if HMDebug stacktrace = StackTraceUtility.ExtractStackTrace(); #endif }
/// Optimize in a greedy fashion. public void PriorityQueueOptimization(HMesh m, EnergyFun efun) { //HalfEdgeAttributeVector<HalfEdgeCounter> counter(m.allocated_halfedges(), HalfEdgeCounter{0, false}); // VertexAttributeVector<int> flipCounter(m.allocated_vertices(), 0); Dictionary <int, HalfEdgeCounter> counter = new Dictionary <int, HalfEdgeCounter>(); Dictionary <int, int> flipCounter = new Dictionary <int, int>(); Priority_Queue.SimplePriorityQueue <PQElement> Q = new SimplePriorityQueue <PQElement>(); //priority_queue<PQElement> Q; //cout << "Building priority queue"<< endl; int time = 1; foreach (var h in m.GetHalfedgesRaw()) { if (!counter.ContainsKey(h.id)) { counter.Add(h.id, new HalfEdgeCounter()); } AddToQueue(counter, Q, h, efun, flipCounter, time); } //cout << "Emptying priority queue of size: " << Q.size() << " "; while (Q.Count > 0) { PQElement elem = Q.Dequeue(); //Walker w = m.walker(elem.h); if (counter[elem.h.id].isRemovedFromQueue) // if item already has been processed continue { continue; } counter[elem.h.id].isRemovedFromQueue = true; if (counter[elem.h.id].touched != elem.time) { if (efun.DeltaEnergy(elem.h) >= 0) { continue; } } if (!PrecondFlipEdge(elem.h)) { continue; } flipCounter[elem.h.vert.id]++; elem.h.Flip(); AddOneRingToQueue(counter, Q, elem.h.vert, efun, flipCounter, time); AddOneRingToQueue(counter, Q, elem.h.next.vert, efun, flipCounter, time); AddOneRingToQueue(counter, Q, elem.h.opp.vert, efun, flipCounter, time); AddOneRingToQueue(counter, Q, elem.h.opp.next.vert, efun, flipCounter, time); } }
// Use this for initialization void Start() { UpdateMenu(); hmesh = new HMesh(); hmesh.CreateTriangle(new Vector3(0, 0, 0), new Vector3(0, 1, 0), new Vector3(1, 0, 0)); hmeshRenderer = FindObjectOfType <HMeshRenderer>(); hmeshRenderer.hmesh = hmesh; hmeshRenderer.UpdateMesh(); }
public void SetHMesh(HMesh m) { hMesh = m; foreach (var c in GetComponents <HMeshARenderer>()) { c.UpdateMesh(); } }
public static HMesh CreateTestMesh() { HMesh mesh = new HMesh(); GameObject plane = GameObject.CreatePrimitive(PrimitiveType.Plane); var meshFilter = plane.GetComponent<MeshFilter>(); mesh.Build(meshFilter.sharedMesh,Matrix4x4.identity); GameObject.DestroyImmediate(plane); return mesh; }
// should only be called by HMesh.CreateVertex public Vertex(HMesh hmesh) { hes = new List <Halfedge>(); _hmesh = hmesh; position = Vector3.zero; uv1 = Vector2.zero; uv2 = Vector2.zero; id = ++hmesh.vertexMaxId; }
public static HMesh CreateTestMesh() { HMesh mesh = new HMesh(); GameObject plane = GameObject.CreatePrimitive(PrimitiveType.Plane); var meshFilter = plane.GetComponent <MeshFilter>(); mesh.Build(meshFilter.sharedMesh, Matrix4x4.identity); GameObject.DestroyImmediate(plane); return(mesh); }
static Face FindTriangleWithinPoint(HMesh mesh, Vector3D pos) { foreach (var face in mesh.GetFacesRaw()) { if (IsPointInTriangle(face, pos)) { return(face); } } return(null); }
public static HMesh CreateTestMeshTriangle(bool upwardsNormal = false) { HMesh mesh = new HMesh(); if (upwardsNormal) { mesh.CreateTriangle(new Vector3(0, 0, 0), new Vector3(0, 0, 1), new Vector3(1, 0, 0)); } else { mesh.CreateTriangle(new Vector3(0, 0, 0), new Vector3(1, 0, 0), new Vector3(0, 0, 1)); } return(mesh); }
public static HMesh Triangulate(List <Vector3D> positions) { HMesh mesh = new HMesh(); Stack <Halfedge> flipStack = new Stack <Halfedge>(); var outerVerts = CreateBoundingTriangle(mesh, positions); foreach (var pos in positions) { var triangle = FindTriangleWithinPoint(mesh, pos); AddEdgesToFlipStack(triangle, flipStack); bool inserted = InsertPointInTriangle(triangle, pos, flipStack); if (!inserted) { continue; } while (flipStack.Count > 0) { var e = flipStack.Pop(); if (IsLocalDelaunay(e)) { continue; } var opp = e.opp; var check1 = opp.next; var check2 = check1.next; var check3 = e.next; var check4 = check3.next; if (!e.FlipPrecondition()) { continue; } flipStack.Push(check1); flipStack.Push(check2); flipStack.Push(check3); flipStack.Push(check4); e.Flip(); } } foreach (var vert in outerVerts) { foreach (var he in vert.Circulate()) { //he.face.Dissolve(); } } return(mesh); }
static Face FindTriangleWithinPoint(HMesh mesh, Vector3 pos) { foreach (var face in mesh.GetFaces()){ var edges = face.Circulate(); var p1 = edges[0].vert.position; var p2 = edges[1].vert.position; var p3 = edges[2].vert.position; Debug.LogWarning("Points "+p1+", "+p2+", "+p3); if (HMeshMath.LeftOf(p1,p2,pos) && HMeshMath.LeftOf(p2,p3,pos) && HMeshMath.LeftOf(p3,p1,pos)){ return face; } } Debug.LogWarning("Cannot find triangle"); return null; }
static Face FindTriangleWithinPoint(HMesh mesh, Vector3 pos) { foreach (var face in mesh.GetFaces()) { var edges = face.Circulate(); var p1 = edges[0].vert.position; var p2 = edges[1].vert.position; var p3 = edges[2].vert.position; Debug.LogWarning("Points " + p1 + ", " + p2 + ", " + p3); if (HMeshMath.LeftOf(p1, p2, pos) && HMeshMath.LeftOf(p2, p3, pos) && HMeshMath.LeftOf(p3, p1, pos)) { return(face); } } Debug.LogWarning("Cannot find triangle"); return(null); }
static List<Vertex> CreateBoundingTriangle(HMesh mesh, List<Vector3> position) { Bounds b = new Bounds(position[0], Vector3.zero); for (int i=0;i<position.Count;i++){ b.Encapsulate(position[i]); } // encapsulate triangle b.center = b.center + b.extents*1.25f; b.extents = b.extents*40.0f; Vector3 v1 = b.min; Vector3 v2 = b.min + Vector3.right * b.size.x; Vector3 v3 = b.min + Vector3.up * b.size.y; Face face = mesh.CreateTriangle(v1, v2, v3); List<Vertex> boundingVertices = new List<Vertex>(); foreach (var he in face.Circulate()){ Gizmos.DrawLine(he.vert.position, he.next.vert.position); boundingVertices.Add(he.vert); } return boundingVertices; }
private static bool IsFacesOnSamePlane(HMesh hmesh, List <Halfedge> hes, int faceLabel = -1) { bool facesAreOnSamePlane = true; Plane3D plane = new Plane3D(Vector3D.zero, 0); foreach (var he in hes) { if (faceLabel != -1 && he.face.label != faceLabel) { continue; } if (!he.face.IsDegenerate()) { plane = he.face.GetPlaneEquation(); break; } } if (plane.normal == Vector3D.zero) { Debug.Assert(false, "Warning - face is degenerate"); return(false); } // allowing the center of the face to move maximum 50% of zeroMagnitudeTreshold (to the plane of an arbitary face double planeDistThreshold = hmesh.zeroMagnitudeTreshold * 0.5; foreach (Halfedge he in hes) { if (faceLabel != -1 && he.face.label != faceLabel) { continue; } if (plane.GetDistanceToPoint(he.GetCenter()) > planeDistThreshold) { facesAreOnSamePlane = false; break; } } return(facesAreOnSamePlane); }
// Update is called once per frame public Mesh UpdateMesh() { Mesh mesh = GetMesh(); Debug.Log("UpdateMesh"); List <Vector3> lines = new List <Vector3>(); List <Vector3> normals = new List <Vector3>(); List <int> indices = new List <int>(); HMesh hmesh = this.hmesh; foreach (var face in hmesh.GetFaces()) { foreach (var edge in face.Circulate()) { if (renderType == HMeshRendererType.BoundaryEdges) { if (!edge.IsBoundary()) { continue; } } lines.Add(edge.prev.vert.position); lines.Add(edge.vert.position); normals.Add(Vector3.up); normals.Add(Vector3.up); indices.Add(indices.Count); indices.Add(indices.Count); } } mesh.Clear(); mesh.vertices = lines.ToArray(); mesh.normals = normals.ToArray(); var meshTopology = renderType == HMeshRendererType.Vertices ? MeshTopology.Points : MeshTopology.Lines; mesh.SetIndices(indices.ToArray(), meshTopology, 0); mesh.RecalculateBounds(); mesh.UploadMeshData(false); return(mesh); }
public static void RemoveFacesWithTwoEdges(HMesh hmesh) { var faces = new List <Face>(hmesh.GetFaces()); for (int i = 0; i < faces.Count; i++)// (var face in hmesh.GetFaces()) { var edges = faces[i].Circulate(); if (edges.Count == 2) { var opp1 = edges[0].opp; var opp2 = edges[1].opp; var vert1 = edges[0].vert; var vert2 = edges[1].vert; // reassign vertex halfedges to a he not to be destroyed Halfedge.Glue(opp1, opp2); hmesh.Destroy(faces[i]); hmesh.Destroy(edges[0]); hmesh.Destroy(edges[1]); } } }
public static HMesh CreateTestMeshNGon(int n) { HMesh mesh = new HMesh(); var face = mesh.CreateFace(); List <Halfedge> edges = new List <Halfedge>(); List <Vertex> verts = new List <Vertex> (); for (var i = 0; i < n; i++) { edges.Add(mesh.CreateHalfedge()); verts.Add(mesh.CreateVertex(new Vector3(Mathf.Sin((i * Mathf.PI * 2) / n), 0, Mathf.Cos((i * Mathf.PI * 2) / n)))); } for (var i = 0; i < n; i++) { edges[i].Link(face); edges[i].next = edges[(i + 1) % n]; edges[(i + 1) % n].prev = edges[i]; edges[i].vert = verts[i]; } return(mesh); }
static List <Vertex> CreateBoundingTriangle(HMesh mesh, List <Vector3> position) { Bounds b = new Bounds(position[0], Vector3.zero); for (int i = 0; i < position.Count; i++) { b.Encapsulate(position[i]); } // encapsulate triangle b.center = b.center + b.extents * 1.25f; b.extents = b.extents * 40.0f; Vector3 v1 = b.min; Vector3 v2 = b.min + Vector3.right * b.size.x; Vector3 v3 = b.min + Vector3.up * b.size.y; Face face = mesh.CreateTriangle(v1, v2, v3); List <Vertex> boundingVertices = new List <Vertex>(); foreach (var he in face.Circulate()) { Gizmos.DrawLine(he.vert.position, he.next.vert.position); boundingVertices.Add(he.vert); } return(boundingVertices); }
public static HMesh Triangulate(List<Vector3> positions) { HMesh mesh = new HMesh(); Stack<Halfedge> flipStack = new Stack<Halfedge>(); List<Vertex> boundingVertices = CreateBoundingTriangle(mesh, positions); foreach (var pos in positions) { Face triangle = FindTriangleWithinPoint(mesh, pos); AddEdgesToFlipStack(triangle, flipStack); InsertPointInTriangle(triangle, pos); while (flipStack.Count>0){ var e = flipStack.Pop(); if (!IsLocalDelaunay(e)){ var opp = e.opp; var check1 = opp.next; var check2 = check1.next; flipStack.Push(check1); flipStack.Push(check2); e.Flip(); } } } return mesh; }
public static HMesh CreateTestMeshTriangle() { HMesh mesh = new HMesh(); mesh.CreateTriangle(new Vector3(0,0,0),new Vector3(1,0,0),new Vector3(0,0,1)); return mesh; }
public void CreateHMeshQuad() { hmesh = HMesh.CreateTestMeshQuad(); }
static bool PrecondFlipEdge(HMesh mesh, Halfedge he) { return(true); }
public void SetDestroyed() { _hmesh = null; }
// should only be called by HMesh.CreateFace public Face(HMesh hmesh) { _hmesh = hmesh; id = ++hmesh.faceMaxId; }
public HMesh Copy() { List<Vertex> fromVert = new List<Vertex>(); List<Face> fromFaces = new List<Face>(); List<Halfedge> fromHalfedge = new List<Halfedge>(); List<Vertex> toVert = new List<Vertex>(); List<Face> toFace = new List<Face>(); List<Halfedge> toHalfedge = new List<Halfedge>(); HMesh newMesh = new HMesh(); int index = 0; foreach (var v in vertices){ v.label = index; fromVert.Add(v); var nv = newMesh.CreateVertex(v.position); nv.uv1 = v.uv1; nv.uv2 = v.uv2; toVert.Add(nv); index++; } index = 0; foreach (var f in faces){ f.label = index; fromFaces.Add(f); var nf = newMesh.CreateFace(); nf.label = f.label; toFace.Add(nf); index++; } index = 0; foreach (var e in halfedges){ e.label = index; fromHalfedge.Add(e); toHalfedge.Add(newMesh.CreateHalfedge()); index++; } // copy references foreach (var from in vertices){ Vertex to = toVert[from.label]; if (from.halfedge != null){to.halfedge = toHalfedge[from.halfedge.label];} } foreach (var from in faces){ Face to = toFace[from.label]; if (from.halfedge != null){to.halfedge = toHalfedge[from.halfedge.label];} } foreach (var from in halfedges){ Halfedge to = toHalfedge[from.label]; if (from.face != null){to.face = toFace[from.face.label];} if (from.opp != null){to.opp = toHalfedge[from.opp.label];} if (from.next != null){to.next = toHalfedge[from.next.label];} if (from.prev != null){to.prev = toHalfedge[from.prev.label];} if (from.vert != null){to.vert = toVert[from.vert.label];} } return newMesh; }
static bool PrecondFlipEdge(HMesh mesh, Halfedge he) { return true; }
public HMesh Copy() { List <Vertex> fromVert = new List <Vertex>(); List <Face> fromFaces = new List <Face>(); List <Halfedge> fromHalfedge = new List <Halfedge>(); List <Vertex> toVert = new List <Vertex>(); List <Face> toFace = new List <Face>(); List <Halfedge> toHalfedge = new List <Halfedge>(); HMesh newMesh = new HMesh(); int index = 0; foreach (var v in vertices) { v.label = index; fromVert.Add(v); var nv = newMesh.CreateVertex(v.positionD); nv.uv1 = v.uv1; nv.uv2 = v.uv2; toVert.Add(nv); index++; } index = 0; foreach (var f in faces) { f.label = index; fromFaces.Add(f); var nf = newMesh.CreateFace(); nf.label = f.label; toFace.Add(nf); index++; } index = 0; foreach (var e in halfedges) { e.label = index; fromHalfedge.Add(e); toHalfedge.Add(newMesh.CreateHalfedge()); index++; } foreach (var from in faces) { Face to = toFace[from.label]; if (from.halfedge != null) { to.halfedge = toHalfedge[from.halfedge.label]; } } foreach (var from in halfedges) { Halfedge to = toHalfedge[from.label]; if (from.face != null) { to.face = toFace[from.face.label]; } if (from.opp != null) { to.opp = toHalfedge[from.opp.label]; } if (from.next != null) { to.next = toHalfedge[from.next.label]; } if (from.prev != null) { to.prev = toHalfedge[from.prev.label]; } if (from.vert != null) { to.vert = toVert[from.vert.label]; } } return(newMesh); }
// should only be called by HMesh.CreateHalfEdge public Halfedge(HMesh hmesh) { _hmesh = hmesh; id = ++hmesh.halfedgeMaxId; }
public override void OnInspectorGUI() { HMeshRenderer myTarget = (HMeshRenderer)target; DrawDefaultInspector(); if (GUILayout.Button("UpdateMesh")) { myTarget.UpdateMesh(); } if (GUILayout.Button("Create HMesh plane")) { myTarget.CreateHMesh(); myTarget.UpdateMesh(); } if (GUILayout.Button("Create HMesh triangle")) { myTarget.CreateHMeshTriangle(); myTarget.UpdateMesh(); } if (GUILayout.Button("Create HMesh Quad")) { myTarget.CreateHMeshQuad(); myTarget.UpdateMesh(); } if (GUILayout.Button("Create HMesh 2-gon")) { var res = myTarget.CreateHMeshNGon(2); myTarget.UpdateMesh(); Debug.Log(res.ToString()); } if (GUILayout.Button("Create HMesh Hexagon")) { var res = myTarget.CreateHMeshNGon(6); myTarget.UpdateMesh(); Debug.Log(res.ToString()); } if (GUILayout.Button("Create HMesh Octogon")) { var res = myTarget.CreateHMeshNGon(8); myTarget.UpdateMesh(); Debug.Log(res.ToString()); } if (GUILayout.Button("Create HMesh Non convex")) { var res = myTarget.CreateHMeshNGon(32); foreach (var ver in res.GetVertices()) { if (ver.position.z < 0) { var pos = ver.positionD; pos.z *= -1; pos *= 0.8; ver.positionD = pos; } } myTarget.UpdateMesh(); Debug.Log(res.ToString()); } if (GUILayout.Button("RandomRotation")) { HMesh res = myTarget.hmesh; var randomRotation = Random.rotation; foreach (var v in res.GetVerticesRaw()) { v.position = randomRotation * v.position; } myTarget.UpdateMesh(); Debug.Log(res.ToString()); } if (GUILayout.Button("Triangulate")) { var res = myTarget.Triangulate(); myTarget.UpdateMesh(); Debug.Log(res.ToString()); } if (GUILayout.Button("Triangulate step")) { var res = myTarget.Triangulate(true); myTarget.UpdateMesh(); Debug.Log(res.ToString()); } if (GUILayout.Button("Apply transform")) { myTarget.ApplyTransform(); myTarget.UpdateMesh(); } if (GUILayout.Button("Set default colors ")) { myTarget.colors = new Color[] { Color.red, Color.green, Color.blue, Color.yellow, Color.cyan, Color.grey }; } if (GUILayout.Button("Build from obj")) { string objTest = "# Blender v2.78 (sub 0) OBJ File: ''\n" + "# www.blender.org\n" + "mtllib quad.mtl\n" + "o Plane\n" + "v -1.000000 0.000000 1.000000\n" + "v 0.000000 0.000000 0.000000\n" + "v -1.000000 0.000000 -1.000000\n" + "v 1.000000 0.000000 -1.000000\n" + "v 1.000000 0.000000 1.000000\n" + "vn 0.0000 1.0000 0.0000\n" + "usemtl None\n" + "s off\n" + "f 1//1 2//1 3//1\n" + "f 4//1 2//1 5//1\n"; myTarget.hmesh = new HMesh(); myTarget.hmesh.BuildFromObj(objTest); myTarget.hmesh.IsValid(); myTarget.UpdateMesh(); Debug.Log(myTarget.hmesh.CreateDebugData()); } if (GUILayout.Button("Build from obj - multi color")) { string objTest = "# Blender v2.78 (sub 0) OBJ File: ''\n" + "# www.blender.org\n" + "mtllib untitled.mtl\n" + "o Plane\n" + "v -1.000000 0.000000 1.000000\n" + // "v 1.000000 1.000000 1.000000\n" + // vertex moved "v -1.000000 0.000000 -1.000000\n" + // "v 1.000000 0.000000 -1.000000\n" + // "v 0.000000 0.000000 0.000000\n" + // "vn 0.0000 1.0000 0.0000\n" + "usemtl None\n" + "s off\n" + "f 1//1 2//1 5//1\n" + "f 4//1 3//1 5//1\n" + "f 5//1 2//1 4//1\n" + "f 5//1 3//1 1//1\n" + ""; myTarget.hmesh = new HMesh(); myTarget.hmesh.BuildFromObj(objTest); myTarget.hmesh.GetFacesRaw()[0].label = 1; myTarget.hmesh.GetFacesRaw()[2].label = 1; myTarget.hmesh.IsValid(); myTarget.UpdateMesh(); Debug.Log(myTarget.hmesh.CreateDebugData()); } if (GUILayout.Button("Build from obj - flat")) { string objTest = "# Blender v2.78 (sub 0) OBJ File: ''\n" + "# www.blender.org\n" + "mtllib test.mtl\n" + " o Plane_Plane.002\n" + "v -1.000000 0.000000 1.000000\n" + "v 0.390552 0.000000 0.390552\n" + "v -0.390552 0.000000 -0.390552\n" + "v 1.000000 0.000000 -1.000000\n" + "vn 0.0000 1.0000 0.0000\n" + "usemtl None\n" + "s off\n" + "f 1//1 2//1 4//1\n" + "f 4//1 3//1 1//1\n"; myTarget.hmesh = new HMesh(); myTarget.hmesh.BuildFromObj(objTest); myTarget.hmesh.GetFacesRaw()[0].label = 1; myTarget.hmesh.IsValid(); myTarget.UpdateMesh(); Debug.Log(myTarget.hmesh.CreateDebugData()); } if (GUILayout.Button("Build from obj - plane")) { string objTest = "# Blender v2.78 (sub 0) OBJ File: ''\n" + "# www.blender.org\n" + "mtllib test.mtl\n" + "o Plane\n" + "v -1.000000 0.000000 1.000000\n" + "v 1.000000 0.000000 1.000000\n" + "v -1.000000 0.000000 -1.000000\n" + "v 1.000000 0.000000 -1.000000\n" + "v -1.000000 0.000000 0.000000\n" + "v 0.000000 0.000000 1.000000\n" + "v 1.000000 0.000000 0.000000\n" + "v 0.000000 0.000000 -1.000000\n" + "v 0.000000 0.000000 0.000000\n" + "vn 0.0000 1.0000 0.0000\n" + "usemtl None\n" + "s off\n" + "f 7//1 8//1 9//1\n" + "f 9//1 3//1 5//1\n" + "f 6//1 5//1 1//1\n" + "f 2//1 9//1 6//1\n" + "f 7//1 4//1 8//1\n" + "f 9//1 8//1 3//1\n" + "f 6//1 9//1 5//1\n" + "f 2//1 7//1 9//1"; myTarget.hmesh = new HMesh(); myTarget.hmesh.BuildFromObj(objTest); foreach (var f in myTarget.hmesh.GetFaces()) { if (f.GetCenter().x > 0) { // f.label = 1; } } myTarget.hmesh.GetFacesRaw()[0].label = 1; myTarget.hmesh.IsValid(); myTarget.UpdateMesh(); Debug.Log(myTarget.hmesh.CreateDebugData()); } if (GUILayout.Button("Build from obj - optimizeable")) { string objTest = "v -30.025 40.49966 -14.83595\n" + "v -94.63337 40.49973 -147.4859\n" + "v -113.9539 40.49965 15.86017\n" + "v -113.9539 40.49976 -214.1117\n" + "v -94.63337 40.49973 -155.2081\n" + "v -90.32684 40.49973 -147.4859\n" + "v -72.21552 40.49973 -147.4859\n" + "v -55.54735 40.49973 -147.4859\n" + "v -6.504288 40.49969 -76.80889\n" + "v -6.504288 40.49966 0.6029686\n" + "v -6.504288 40.49966 2.818535\n" + "v -6.504288 40.49966 3.218271\n" + "v -6.504288 40.49965 11.65778\n" + "v -31.79999 40.49967 -32.091\n" + "v -31.79999 40.49968 -35.57327\n" + "v -100.9474 40.49968 -35.57016\n" + "v -94.05646 40.49968 -32.09412\n" + "v -44.48075 40.49967 -32.09164\n" + "v -38.34414 40.49967 -32.09133\n" + "v -39.51749 40.49968 -35.57293\n" + "o label0\n" + "f 3 2 4\n" + "f 16 3 17\n" + "f 18 1 19\n" + "f 9 15 14\n" + "f 4 2 5\n" + "f 15 8 7\n" + "f 15 9 8\n" + "f 1 10 9\n" + "f 10 1 11\n" + "f 12 11 1\n" + "f 12 3 13\n" + "f 9 14 1\n" + "f 20 15 7\n" + "f 1 17 12\n" + "f 2 3 16\n" + "f 17 3 12\n" + "f 17 1 18\n" + "f 16 6 2\n" + "f 20 6 16\n" + "f 20 7 6\n" + "f 19 1 14\n" + "o label1\n" + "f 15 20 14\n" + "f 16 18 19\n" + "f 16 17 18\n" + "f 20 19 14\n" + "f 19 20 16\n" + ""; myTarget.hmesh = new HMesh(); myTarget.hmesh.BuildFromObj(objTest); foreach (var f in myTarget.hmesh.GetFaces()) { if (f.GetCenter().x > 0) { // f.label = 1; } } myTarget.hmesh.GetFacesRaw()[0].label = 1; myTarget.hmesh.IsValid(); myTarget.UpdateMesh(); } if (GUILayout.Button("Build from obj - degenerate")) { string objTest = "# Blender v2.78 (sub 0) OBJ File: ''\n" + "# www.blender.org\n" + "mtllib degenerate.mtl\n" + "o Plane\n" + "v -0.477655 -1.045174 1.105640\n" + "v -0.477655 -1.045174 -0.894360\n" + "v -0.477655 -0.480058 0.105640\n" + "v 0.522345 -1.045174 1.105640\n" + "v 0.522345 -1.045174 -0.894360\n" + "v 0.522345 -1.045174 0.105640\n" + "v -0.477655 -1.045174 0.105640\n" + "v 0.522345 -1.045174 0.605640\n" + "v -0.477655 -1.045174 0.105640\n" + "v 0.522345 -1.045174 -0.394360\n" + "vn 0.0000 1.0000 0.0000\n" + "vn 0.0000 0.0000 1.0000\n" + "vn 0.0000 0.0000 -1.0000\n" + "usemtl None\n" + "s off\n" + "f 1//1 4//1 8//1\n" + "f 10//1 2//1 9//1\n" + "f 7//2 6//2 3//2\n" + "f 7//1 8//1 6//1\n" + "f 6//1 10//1 9//1\n" + "f 1//1 8//1 7//1\n" + "f 6//3 9//3 3//3\n" + "f 10//1 5//1 2//1\n"; myTarget.hmesh = new HMesh(); myTarget.hmesh.BuildFromObj(objTest); myTarget.hmesh.IsValid(); myTarget.UpdateMesh(); Debug.Log(myTarget.hmesh.CreateDebugData()); } if (GUILayout.Button("Build from obj - flat degenerate 1")) { string objTest = "# Blender v2.78 (sub 0) OBJ File: ''\n" + "# www.blender.org\n" + "mtllib degenerate1.mtl\n" + " o degenerate1\n" + "v -1.000000 0.000000 1.000000\n" + "v 1.000000 0.000000 1.000000\n" + "v -1.000000 0.000000 -1.000000\n" + "v 1.000000 0.000000 -1.000000\n" + "v -1.000000 0.000000 0.000000\n" + "v 0.000000 0.000000 1.000000\n" + "v 1.000000 0.000000 0.000000\n" + "v 0.000000 0.000000 -1.000000\n" + "v 0.633916 0.000000 0.000000\n" + "v -0.636292 0.000000 0.000000\n" + "v 0.000000 0.000000 0.000000\n" + "v 0.000000 0.000000 0.000000\n" + "v -0.357594 0.000000 -0.016980\n" + "v -0.357594 0.000000 -0.016980\n" + "v 0.316958 0.000000 0.000000\n" + "vn 0.0000 1.0000 0.0000\n" + "vn 0.0000 -1.0000 0.0000\n" + "usemtl None\n" + "s off\n" + "f 5//1 10//1 14//1 12//1 8//1 3//1\n" + "f 1//1 6//1 11//1 13//1 10//1 5//1\n" + "f 6//1 2//1 7//1 9//1 11//1\n" + "f 11//2 9//2 15//2 12//2 14//2 10//2 13//2\n" + "f 12//1 15//1 9//1 7//1 4//1 8//1\n" + ""; myTarget.hmesh = new HMesh(); myTarget.hmesh.BuildFromObj(objTest); myTarget.hmesh.IsValid(); myTarget.UpdateMesh(); Debug.Log(myTarget.hmesh.CreateDebugData()); } if (GUILayout.Button("Build from obj - flat degenerate 2")) { string objTest = "# Blender v2.78 (sub 0) OBJ File: ''\n" + "# www.blender.org\n" + "mtllib degenerate2.mtl\n" + " o Degenerate2\n" + "v -1.000000 0.000000 1.000000\n" + "v 1.000000 0.000000 1.000000\n" + "v -1.000000 0.000000 -1.000000\n" + "v 1.000000 0.000000 -1.000000\n" + "v -1.000000 0.000000 0.000000\n" + "v 0.000000 0.000000 1.000000\n" + "v 1.000000 0.000000 0.000000\n" + "v 0.000000 0.000000 -1.000000\n" + "v 0.584243 0.000000 0.000000\n" + "v -0.029986 0.000000 0.012126\n" + "v -0.029986 0.000000 0.012126\n" + "v 0.000000 0.000000 -0.681619\n" + "v -0.180637 0.000000 0.149689\n" + "v -0.029986 0.000000 0.012126\n" + "v -0.046522 0.000000 -0.408366\n" + "v -0.046522 0.000000 -0.408366\n" + "vn -0.0000 1.0000 -0.0000\n" + "usemtl None\n" + "s off\n" + "f 5//1 10//1 16//1 12//1 8//1 3//1\n" + "f 1//1 6//1 11//1 13//1 10//1 5//1\n" + "f 6//1 2//1 7//1 9//1 11//1\n" + "f 11//1 9//1 14//1 15//1 12//1 16//1 10//1 13//1\n" + "f 12//1 15//1 14//1 9//1 7//1 4//1 8//1\n" + ""; myTarget.hmesh = new HMesh(); myTarget.hmesh.BuildFromObj(objTest); myTarget.hmesh.IsValid(); myTarget.UpdateMesh(); Debug.Log(myTarget.hmesh.CreateDebugData()); } if (GUILayout.Button("Build from obj - flat degenerate 3")) { string objTest = "# Blender v2.78 (sub 0) OBJ File: ''\n" + "# www.blender.org\n" + "mtllib degenerate3.mtl\n" + "o Denegerate3\n" + "v -1.000000 0.000000 1.000000\n" + "v 1.000000 0.000000 1.000000\n" + "v -1.000000 0.000000 -1.000000\n" + "v 1.000000 0.000000 -1.000000\n" + "v -1.000000 0.000000 0.000000\n" + "v 0.000000 0.000000 1.000000\n" + "v 1.000000 0.000000 0.000000\n" + "v 0.000000 0.000000 -1.000000\n" + "v 0.809701 0.000000 0.000000\n" + "v -0.795454 0.000000 0.000000\n" + "v 0.000000 0.000000 0.026553\n" + "v 0.000000 0.000000 0.026553\n" + "v 0.417223 0.000000 0.020130\n" + "v 0.531795 0.000000 0.383705\n" + "v 0.628144 -0.000000 -0.286403\n" + "v 0.417223 0.000000 0.020130\n" + "v -0.298932 0.000000 0.031520\n" + "v -0.478770 0.000000 -0.367569\n" + "v -0.622377 0.000000 0.355869\n" + "v -0.298932 0.000000 0.031520\n" + "vn -0.0000 1.0000 -0.0000\n" + "usemtl None\n" + "s off\n" + "f 10//1 19//1 20//1 11//1 13//1 14//1 9//1 15//1 16//1 12//1 17//1 18//1\n" + "f 5//1 10//1 18//1 17//1 12//1 8//1 3//1\n" + "f 1//1 6//1 11//1 20//1 19//1 10//1 5//1\n" + "f 6//1 2//1 7//1 9//1 14//1 13//1 11//1\n" + "f 12//1 16//1 15//1 9//1 7//1 4//1 8//1\n" + ""; myTarget.hmesh = new HMesh(); myTarget.hmesh.BuildFromObj(objTest); myTarget.hmesh.IsValid(); myTarget.UpdateMesh(); Debug.Log(myTarget.hmesh.CreateDebugData()); } if (GUILayout.Button("Build from obj - test")) { string objTest = myTarget.objfile; myTarget.hmesh = new HMesh(); myTarget.hmesh.BuildFromObj(objTest); myTarget.hmesh.IsValid(); myTarget.UpdateMesh(); Debug.Log(myTarget.hmesh.CreateDebugData()); } if (GUILayout.Button("Simplify")) { int res = HMeshSimplification.SimplifyByCollapse(myTarget.hmesh); Debug.Log("Res " + res); Debug.Log("Valid " + myTarget.hmesh.IsValid()); myTarget.UpdateMesh(); Debug.Log(myTarget.hmesh.CreateDebugData()); } if (GUILayout.Button("Optimize")) { HMeshOptimizer optimizer = new HMeshOptimizer(); optimizer.FaceLabelContrain = myTarget.OptimizeFaceLabelContrain; optimizer.FaceNormalContrain = myTarget.OptimizeFaceNormalContrain; switch (myTarget.optStategy) { case OptimizationStrategy.MaximizeMinAngle: optimizer.MaximizeMinAngle(myTarget.hmesh, myTarget.OptimizeMinMaxAngleThreshold); break; case OptimizationStrategy.MinimizeDihedralAngle: optimizer.MinimizeDihedralAngle(myTarget.hmesh); break; case OptimizationStrategy.OptimizeValency: optimizer.OptimizeValency(myTarget.hmesh); break; } myTarget.hmesh.IsValid(); myTarget.UpdateMesh(); Debug.Log(myTarget.hmesh.CreateDebugData()); } if (GUILayout.Button("Split 2x1x2")) { var hmesh = EarClipTestEditor.CreateTestMeshPolygon(myTarget.GetComponent <EarClipTest>()); foreach (var f in hmesh.GetFaces()) { EarClipping.Tesselate(f); } var meshes = hmesh.ExportSplit(new Vector3i(2, 1, 2)); foreach (var mesh in meshes) { GameObject go = new GameObject("SplitMesh"); var mr = go.AddComponent <MeshRenderer>(); var mat = new Material(Shader.Find("Standard")); mat.color = Color.white; mr.material = mat; var mf = go.AddComponent <MeshFilter>(); mf.mesh = mesh; } } if (GUILayout.Button("Export OBJ")) { var fileObj = myTarget.hmesh.ExportObj(); File.WriteAllText("/Users/mnob/Desktop/export-obj.obj", fileObj); } }
public void CreateHMeshTriangle() { hmesh = HMesh.CreateTestMeshTriangle(); }
void OnGUI() { if (GUI.Button(new Rect(0,0,200,50), "FaceSplit")){ HMesh hMesh = new HMesh(); var mf = GetComponent<MeshFilter>(); hMesh.Build(mf.mesh); foreach (var f in hMesh.GetFaces()){ f.Split(); } var mesh = hMesh.Export(); mesh.RecalculateNormals(); mf.mesh = mesh; } if (GUI.Button(new Rect(200,0,200,50), "EdgeFlip")){ HMesh hMesh = new HMesh(); var mf = GetComponent<MeshFilter>(); hMesh.Build(mf.mesh); HashSet<Halfedge> isFlipped = new HashSet<Halfedge>(); foreach (var h in hMesh.GetHalfedges()){ if (!h.IsBoundary() && !isFlipped.Contains(h)){ Debug.DrawLine(h.vert.position, h.prev.vert.position,Color.cyan,5); h.Flip(); isFlipped.Add(h.opp); } } var mesh = hMesh.Export(); mesh.RecalculateNormals(); mf.mesh = mesh; } if (GUI.Button(new Rect(400,0,200,50), "EdgeSplit")){ HMesh hMesh = new HMesh(); var mf = GetComponent<MeshFilter>(); hMesh.Build(mf.mesh); HashSet<Halfedge> isSplit = new HashSet<Halfedge>(); foreach (var h in hMesh.GetHalfedges()){ if (!h.IsBoundary() && !isSplit.Contains(h)){ Debug.DrawLine(h.vert.position, h.prev.vert.position,Color.cyan,5); isSplit.Add(h.opp); h.Split(); } } var mesh = hMesh.Export(); mesh.RecalculateNormals(); mf.mesh = mesh; } if (GUI.Button(new Rect(600,0,200,50), "CollapseEdge")){ HMesh hMesh = new HMesh(); var mf = GetComponent<MeshFilter>(); hMesh.Build(mf.mesh); HashSet<Halfedge> isCollapsed = new HashSet<Halfedge>(); foreach (var h in hMesh.GetHalfedges()){ if (!h.IsBoundary()){ if (!h.vert.IsBoundary() && !h.prev.vert.IsBoundary() && !isCollapsed.Contains(h)){ Debug.DrawLine(h.vert.position, h.prev.vert.position,Color.cyan,5); isCollapsed.Add(h.opp); h.Collapse(); break; } } } var mesh = hMesh.Export(); mesh.RecalculateNormals(); mf.mesh = mesh; } if (GUI.Button(new Rect(0,50,200,50), "CirculateRndVertex")){ HMesh hMesh = new HMesh(); var mf = GetComponent<MeshFilter>(); hMesh.Build(mf.mesh); HashSet<Halfedge> isCollapsed = new HashSet<Halfedge>(); var vertices = new List<Vertex>(hMesh.GetVertices()); var vertex = vertices[1];//Random.Range(0,vertices.Count-1)]; foreach (var h in vertex.Circulate()){ Debug.DrawLine(h.vert.position, h.prev.vert.position,Color.cyan,5); } Debug.Log("Circulate vertex: "+vertex.Circulate().Count); } if (GUI.Button(new Rect(200,50,200,50), "CirculateOppRndVertex")){ HMesh hMesh = new HMesh(); var mf = GetComponent<MeshFilter>(); hMesh.Build(mf.mesh); //HashSet<Halfedge> isCollapsed = new HashSet<Halfedge>(); var vertices = new List<Vertex>(hMesh.GetVertices()); var vertex = vertices[1];//Random.Range(0,vertices.Count-1)]; foreach (var h in vertex.CirculateOpp()){ Debug.DrawLine(h.vert.position, h.prev.vert.position,Color.cyan,5); } Debug.Log("Circulate vertex: "+vertex.Circulate().Count); } if (GUI.Button(new Rect(400,50,200,50), "Circulate1RingRndVertex")){ HMesh hMesh = new HMesh(); var mf = GetComponent<MeshFilter>(); hMesh.Build(mf.mesh); // HashSet<Halfedge> isCollapsed = new HashSet<Halfedge>(); var vertices = new List<Vertex>(hMesh.GetVertices()); var vertex = vertices[Random.Range(0,vertices.Count-1)]; foreach (var h in vertex.CirculateOneRing()){ Debug.DrawLine(h.vert.position, h.prev.vert.position,Color.cyan,5); } Debug.Log("Circulate 1-ring: "+vertex.CirculateOneRing().Count); } if (GUI.Button(new Rect(600,50,200,50), "CirculateRndFace")){ HMesh hMesh = new HMesh(); var mf = GetComponent<MeshFilter>(); hMesh.Build(mf.mesh); HashSet<Halfedge> isCollapsed = new HashSet<Halfedge>(); var faces = new List<Face>(hMesh.GetFaces()); var face = faces[Random.Range(0,faces.Count-1)]; foreach (var h in face.Circulate()){ Debug.DrawLine(h.vert.position, h.prev.vert.position, Color.cyan, 5); } Debug.Log("Circulate face: "+face.Circulate().Count); } }
// should only be called by HMesh.CreateFace public Face(HMesh hmesh) { this.hmesh = hmesh; }