protected override ActionResult PerformActionImplementation() { if (MeshSelection.selectedObjectCount < 1) { return(ActionResult.NoSelection); } UndoUtility.RecordSelection("Fill Hole"); ActionResult res = new ActionResult(ActionResult.Status.NoChange, "No Holes Found"); int filled = 0; bool wholePath = m_SelectEntirePath; foreach (ProBuilderMesh mesh in MeshSelection.topInternal) { bool selectAll = mesh.selectedIndexesInternal == null || mesh.selectedIndexesInternal.Length < 1; IEnumerable <int> indexes = selectAll ? mesh.facesInternal.SelectMany(x => x.indexes) : mesh.selectedIndexesInternal; mesh.ToMesh(); List <WingedEdge> wings = WingedEdge.GetWingedEdges(mesh); HashSet <int> common = mesh.GetSharedVertexHandles(indexes); List <List <WingedEdge> > holes = ElementSelection.FindHoles(wings, common); HashSet <Face> appendedFaces = new HashSet <Face>(); foreach (List <WingedEdge> hole in holes) { List <int> holeIndexes; Face face; if (wholePath) { // if selecting whole path and in edge mode, make sure the path contains // at least one complete edge from the selection. if (ProBuilderEditor.selectMode == SelectMode.Edge && !hole.Any(x => common.Contains(x.edge.common.a) && common.Contains(x.edge.common.b))) { continue; } holeIndexes = hole.Select(x => x.edge.local.a).ToList(); face = AppendElements.CreatePolygon(mesh, holeIndexes, false); } else { IEnumerable <WingedEdge> selected = hole.Where(x => common.Contains(x.edge.common.a)); holeIndexes = selected.Select(x => x.edge.local.a).ToList(); face = AppendElements.CreatePolygon(mesh, holeIndexes, true); } if (face != null) { filled++; appendedFaces.Add(face); } } mesh.SetSelectedFaces(appendedFaces); wings = WingedEdge.GetWingedEdges(mesh); // make sure the appended faces match the first adjacent face found // both in winding and face properties foreach (var appendedFace in appendedFaces) { var wing = wings.FirstOrDefault(x => x.face == appendedFace); if (wing == null) { continue; } using (var it = new WingedEdgeEnumerator(wing)) { while (it.MoveNext()) { if (it.Current == null) { continue; } var currentWing = it.Current; var oppositeFace = it.Current.opposite != null ? it.Current.opposite.face : null; if (oppositeFace != null && !appendedFaces.Contains(oppositeFace)) { currentWing.face.submeshIndex = oppositeFace.submeshIndex; currentWing.face.uv = new AutoUnwrapSettings(oppositeFace.uv); SurfaceTopology.ConformOppositeNormal(currentWing.opposite); break; } } } } mesh.ToMesh(); mesh.Refresh(); mesh.Optimize(); } ProBuilderEditor.Refresh(); if (filled > 0) { res = new ActionResult(ActionResult.Status.Success, filled > 1 ? string.Format("Filled {0} Holes", filled) : "Fill Hole"); } return(res); }
public override void FillHoles() { int filled = 0; foreach (ProBuilderMesh mesh in m_edgeSelection.Meshes) { //MeshSelection selection = new MeshSelection(); //selection.SelectedEdges.Add(mesh, m_edgeSelection.GetEdges(mesh)); //selection.EdgesToVertices(false); HashSet <int> indexes = new HashSet <int>(); for (int i = 0; i < mesh.vertexCount; ++i) { indexes.Add(i); } List <List <Edge> > holes = PBElementSelection.FindHoles(mesh, indexes); mesh.ToMesh(); List <WingedEdge> wings = WingedEdge.GetWingedEdges(mesh); HashSet <Face> appendedFaces = new HashSet <Face>(); // const bool wholePath = false; foreach (List <Edge> hole in holes) { List <int> holeIndexes; Face face; if (!hole.All(e => m_edgeSelection.IsSelected(mesh, e))) { continue; } //if (wholePath) //{ // // if selecting whole path and in edge mode, make sure the path contains // // at least one complete edge from the selection. // if (!hole.Any(x => common.Contains(x.edge.common.a) && // common.Contains(x.edge.common.b))) // continue; // holeIndexes = hole.Select(x => x.edge.local.a).ToList(); // face = AppendElements.CreatePolygon(mesh, holeIndexes, false); //} //else { //IEnumerable<WingedEdge> selected = hole.Where(x => common.Contains(x.edge.common.a)); //holeIndexes = selected.Select(x => x.edge.local.a).ToList(); //holeIndexes = hole.Select(x => x.edge.local.a).ToList(); //face = AppendElements.CreatePolygon(mesh, holeIndexes, true); holeIndexes = hole.Select(x => x.a).ToList(); face = AppendElements.CreatePolygon(mesh, holeIndexes, true); } if (face != null) { filled++; appendedFaces.Add(face); } } mesh.SetSelectedFaces(appendedFaces); wings = WingedEdge.GetWingedEdges(mesh); // make sure the appended faces match the first adjacent face found // both in winding and face properties foreach (var appendedFace in appendedFaces) { var wing = wings.FirstOrDefault(x => x.face == appendedFace); if (wing == null) { continue; } using (var it = new WingedEdgeEnumerator(wing)) { while (it.MoveNext()) { if (it.Current == null) { continue; } var currentWing = it.Current; var oppositeFace = it.Current.opposite != null ? it.Current.opposite.face : null; if (oppositeFace != null && !appendedFaces.Contains(oppositeFace)) { currentWing.face.submeshIndex = oppositeFace.submeshIndex; currentWing.face.uv = new AutoUnwrapSettings(oppositeFace.uv); PBSurfaceTopology.ConformOppositeNormal(currentWing.opposite); break; } } } } mesh.ToMesh(); mesh.Refresh(); //mesh.Optimize(); } }
public void Generate() { switch (ShapeType) { case ShapeTypes.Wythoff: var wythoff = new WythoffPoly(PolyType, PrismP, PrismQ); wythoff.BuildFaces(); poly = new ConwayPoly(wythoff); break; case ShapeTypes.Johnson: poly = JohnsonPoly.Build(JohnsonPolyType, PrismP); break; case ShapeTypes.Grid: poly = Grids.Grids.MakeGrid(GridType, GridShape, PrismP, PrismQ); break; } if (ApplyOp) { var o1 = new OpParams { valueA = op1Amount1, valueB = op1Amount2, facesel = op1Facesel }; poly = poly.ApplyOp(op1, o1); } if (PreCanonicalize) { poly = poly.Canonicalize(0.01, 0.01); } if (Canonicalize) { poly = poly.Canonicalize(0.01, 0.01); } if (ApplyOp) { var o2 = new OpParams { valueA = op2Amount1, valueB = op2Amount2, facesel = op2Facesel }; poly = poly.ApplyOp(op2, o2); var o3 = new OpParams { valueA = op3Amount1, valueB = op3Amount2, facesel = op3Facesel }; poly = poly.ApplyOp(op3, o3); } var points = poly.ListVerticesByPoints().ToList(); if (JitterAmount > 0) { for (int i = 0; i < points.Count(); i++) { var point = points[i]; points[i] = new Vector3( point.x + Random.value * JitterAmount, point.y + Random.value * JitterAmount, point.z + Random.value * JitterAmount ); } } var faceIndices = poly.ListFacesByVertexIndices(); // This whole mess is because I can't find a way to regenerate // a probuilder mesh and therefore have to continually create/destroy gameobjects // (which is a mess in edit mode) // If anyone can explain how to simply take an existing probuilder object clear it // and pass in a list of Vector3's and lists of ordered indexes for faces // then please do. if (pbmesh != null && pbmesh.gameObject != null) { if (Application.isPlaying) { Destroy(pbmesh.gameObject); } else { var go = pbmesh.gameObject; UnityEditor.EditorApplication.delayCall += () => { DestroyImmediate(go); }; } } var colors = Enumerable.Range(0, 8).Select(x => Colors.Evaluate(((x / 8f) * ColorRange + ColorOffset) % 1)).ToArray(); pbmesh = ProBuilderMesh.Create(points, new List <Face>()); var faces = new List <PBFace>(); for (var i = 0; i < faceIndices.Length; i++) { var face = faceIndices[i]; var result = AppendElements.CreatePolygon(pbmesh, face, false); if (result != null) { pbmesh.SetFaceColor(result, colors[(int)poly.FaceRoles[i]]); faces.Add(result); } } if (faces.Count < 1 || pbmesh == null) { return; } pbmesh.SetMaterial(faces, material); pbmesh.ToMesh(); pbmesh.Refresh(); }