/** * \brief Returns faces that share an edge with any of @c selFcaes. */ public static pb_Face[] GetNeighborFaces(pb_Object pb, Dictionary <int, int> sharedIndicesLookup, pb_Face[] selFaces) { List <pb_Face> perimeterFaces = new List <pb_Face>(); pb_Edge[] perimeterEdges = pbMeshUtils.GetPerimeterEdges(pb, sharedIndicesLookup, selFaces).ToArray(); pb_Edge[] universalEdges = new pb_Edge[perimeterEdges.Length]; for (int i = 0; i < perimeterEdges.Length; i++) { universalEdges[i] = new pb_Edge(sharedIndicesLookup[perimeterEdges[i].x], sharedIndicesLookup[perimeterEdges[i].y]); } pb_Edge edge_u = new pb_Edge(-1, -1); HashSet <pb_Face> skip = new HashSet <pb_Face>(selFaces); foreach (pb_Face face in pb.faces) { if (skip.Contains(face)) { skip.Remove(face); continue; } foreach (pb_Edge edge in face.edges) { edge_u.x = sharedIndicesLookup[edge.x]; edge_u.y = sharedIndicesLookup[edge.y]; if (universalEdges.Contains(edge_u)) { perimeterFaces.Add(face); break; } } } return(perimeterFaces.ToArray()); }
public static bool Bridge(this pb_Object pb, pb_Edge a, pb_Edge b, bool enforcePerimiterEdgesOnly) { pb_IntArray[] sharedIndices = pb.GetSharedIndices(); // Check to see if a face already exists if(enforcePerimiterEdgesOnly) { if( pbMeshUtils.GetConnectedFaces(pb, a).Count > 1 || pbMeshUtils.GetConnectedFaces(pb, b).Count > 1 ) { Debug.LogWarning("Both edges are not on perimeter! You may turn off this Bridging restriction in Preferences/ProBuilder/Bridge Perimiter Edges Only"); return false; } } else { foreach(pb_Face face in pb.faces) { if(face.edges.IndexOf(a, sharedIndices) >= 0 && face.edges.IndexOf(b, sharedIndices) >= 0) { Debug.LogWarning("Face already exists between these two edges!"); return false; } } } Vector3[] verts = pb.vertices; Vector3[] v; int[] s; pb_UV uvs = new pb_UV(); Color32 color = (Color32)Color.white; Material mat = pb_Constant.DefaultMaterial; // Get material and UV stuff from the first edge face foreach(pb_Face face in pb.faces) { if(face.edges.Contains(a)) { uvs = new pb_UV(face.uv); mat = face.material; color = face.colors[0]; break; } } // Bridge will form a triangle if( a.Contains(b.x, sharedIndices) || a.Contains(b.y, sharedIndices) ) { v = new Vector3[3]; s = new int[3]; bool axbx = System.Array.IndexOf(sharedIndices[sharedIndices.IndexOf(a.x)], b.x) > -1; bool axby = System.Array.IndexOf(sharedIndices[sharedIndices.IndexOf(a.x)], b.y) > -1; bool aybx = System.Array.IndexOf(sharedIndices[sharedIndices.IndexOf(a.y)], b.x) > -1; bool ayby = System.Array.IndexOf(sharedIndices[sharedIndices.IndexOf(a.y)], b.y) > -1; if(axbx) { v[0] = verts[a.x]; s[0] = sharedIndices.IndexOf(a.x); v[1] = verts[a.y]; s[1] = sharedIndices.IndexOf(a.y); v[2] = verts[b.y]; s[2] = sharedIndices.IndexOf(b.y); } else if(axby) { v[0] = verts[a.x]; s[0] = sharedIndices.IndexOf(a.x); v[1] = verts[a.y]; s[1] = sharedIndices.IndexOf(a.y); v[2] = verts[b.x]; s[2] = sharedIndices.IndexOf(b.x); } else if(aybx) { v[0] = verts[a.y]; s[0] = sharedIndices.IndexOf(a.y); v[1] = verts[a.x]; s[1] = sharedIndices.IndexOf(a.x); v[2] = verts[b.y]; s[2] = sharedIndices.IndexOf(b.y); } else if(ayby) { v[0] = verts[a.y]; s[0] = sharedIndices.IndexOf(a.y); v[1] = verts[a.x]; s[1] = sharedIndices.IndexOf(a.x); v[2] = verts[b.x]; s[2] = sharedIndices.IndexOf(b.x); } pb.AppendFace( v, new pb_Face( axbx || axby ? new int[3] {2, 1, 0} : new int[3] {0, 1, 2}, mat, uvs, 0, -1, -1, color ), s); pb.RebuildFaceCaches(); pb.Refresh(); return true; } // Else, bridge will form a quad v = new Vector3[4]; s = new int[4]; // shared indices index to add to v[0] = verts[a.x]; s[0] = sharedIndices.IndexOf(a.x); v[1] = verts[a.y]; s[1] = sharedIndices.IndexOf(a.y); Vector3 nrm = Vector3.Cross( verts[b.x]-verts[a.x], verts[a.y]-verts[a.x] ).normalized; Vector2[] planed = pb_Math.VerticesTo2DPoints( new Vector3[4] {verts[a.x], verts[a.y], verts[b.x], verts[b.y] }, nrm ); Vector2 ipoint = Vector2.zero; bool interescts = pb_Math.GetLineSegmentIntersect(planed[0], planed[2], planed[1], planed[3], ref ipoint); if(!interescts) { v[2] = verts[b.x]; s[2] = sharedIndices.IndexOf(b.x); v[3] = verts[b.y]; s[3] = sharedIndices.IndexOf(b.y); } else { v[2] = verts[b.y]; s[2] = sharedIndices.IndexOf(b.y); v[3] = verts[b.x]; s[3] = sharedIndices.IndexOf(b.x); } pb.AppendFace( v, new pb_Face( new int[6] {2, 1, 0, 2, 3, 1 }, mat, uvs, 0, -1, -1, color ), s); pb.RebuildFaceCaches(); return true; }
public static bool Bridge(this pb_Object pb, pb_Edge a, pb_Edge b, bool enforcePerimiterEdgesOnly) { pb_IntArray[] sharedIndices = pb.GetSharedIndices(); // Check to see if a face already exists if (enforcePerimiterEdgesOnly) { if (pbMeshUtils.GetConnectedFaces(pb, a).Count > 1 || pbMeshUtils.GetConnectedFaces(pb, b).Count > 1) { Debug.LogWarning("Both edges are not on perimeter! You may turn off this Bridging restriction in Preferences/ProBuilder/Bridge Perimiter Edges Only"); return(false); } } else { foreach (pb_Face face in pb.faces) { if (face.edges.IndexOf(a, sharedIndices) >= 0 && face.edges.IndexOf(b, sharedIndices) >= 0) { Debug.LogWarning("Face already exists between these two edges!"); return(false); } } } Vector3[] verts = pb.vertices; Vector3[] v; int[] s; pb_UV uvs = new pb_UV(); Color32 color = (Color32)Color.white; Material mat = pb_Constant.DefaultMaterial; // Get material and UV stuff from the first edge face foreach (pb_Face face in pb.faces) { if (face.edges.Contains(a)) { uvs = new pb_UV(face.uv); mat = face.material; color = face.colors[0]; break; } } // Bridge will form a triangle if (a.Contains(b.x, sharedIndices) || a.Contains(b.y, sharedIndices)) { v = new Vector3[3]; s = new int[3]; bool axbx = System.Array.IndexOf(sharedIndices[sharedIndices.IndexOf(a.x)], b.x) > -1; bool axby = System.Array.IndexOf(sharedIndices[sharedIndices.IndexOf(a.x)], b.y) > -1; bool aybx = System.Array.IndexOf(sharedIndices[sharedIndices.IndexOf(a.y)], b.x) > -1; bool ayby = System.Array.IndexOf(sharedIndices[sharedIndices.IndexOf(a.y)], b.y) > -1; if (axbx) { v[0] = verts[a.x]; s[0] = sharedIndices.IndexOf(a.x); v[1] = verts[a.y]; s[1] = sharedIndices.IndexOf(a.y); v[2] = verts[b.y]; s[2] = sharedIndices.IndexOf(b.y); } else if (axby) { v[0] = verts[a.x]; s[0] = sharedIndices.IndexOf(a.x); v[1] = verts[a.y]; s[1] = sharedIndices.IndexOf(a.y); v[2] = verts[b.x]; s[2] = sharedIndices.IndexOf(b.x); } else if (aybx) { v[0] = verts[a.y]; s[0] = sharedIndices.IndexOf(a.y); v[1] = verts[a.x]; s[1] = sharedIndices.IndexOf(a.x); v[2] = verts[b.y]; s[2] = sharedIndices.IndexOf(b.y); } else if (ayby) { v[0] = verts[a.y]; s[0] = sharedIndices.IndexOf(a.y); v[1] = verts[a.x]; s[1] = sharedIndices.IndexOf(a.x); v[2] = verts[b.x]; s[2] = sharedIndices.IndexOf(b.x); } pb.AppendFace( v, new pb_Face(axbx || axby ? new int[3] { 2, 1, 0 } : new int[3] { 0, 1, 2 }, mat, uvs, 0, -1, -1, color), s); pb.RebuildFaceCaches(); pb.Refresh(); return(true); } // Else, bridge will form a quad v = new Vector3[4]; s = new int[4]; // shared indices index to add to v[0] = verts[a.x]; s[0] = sharedIndices.IndexOf(a.x); v[1] = verts[a.y]; s[1] = sharedIndices.IndexOf(a.y); Vector3 nrm = Vector3.Cross(verts[b.x] - verts[a.x], verts[a.y] - verts[a.x]).normalized; Vector2[] planed = pb_Math.VerticesTo2DPoints(new Vector3[4] { verts[a.x], verts[a.y], verts[b.x], verts[b.y] }, nrm); Vector2 ipoint = Vector2.zero; bool interescts = pb_Math.GetLineSegmentIntersect(planed[0], planed[2], planed[1], planed[3], ref ipoint); if (!interescts) { v[2] = verts[b.x]; s[2] = sharedIndices.IndexOf(b.x); v[3] = verts[b.y]; s[3] = sharedIndices.IndexOf(b.y); } else { v[2] = verts[b.y]; s[2] = sharedIndices.IndexOf(b.y); v[3] = verts[b.x]; s[3] = sharedIndices.IndexOf(b.x); } pb.AppendFace( v, new pb_Face(new int[6] { 2, 1, 0, 2, 3, 1 }, mat, uvs, 0, -1, -1, color), s); pb.RebuildFaceCaches(); return(true); }
public static bool Bridge(this pb_Object pb, pb_Edge a, pb_Edge b, bool enforcePerimiterEdgesOnly) { pb_IntArray[] sharedIndices = pb.GetSharedIndices(); Dictionary<int, int> lookup = sharedIndices.ToDictionary(); // Check to see if a face already exists if(enforcePerimiterEdgesOnly) { if( pbMeshUtils.GetNeighborFaces(pb, a).Count > 1 || pbMeshUtils.GetNeighborFaces(pb, b).Count > 1 ) { return false; } } foreach(pb_Face face in pb.faces) { if(face.edges.IndexOf(a, lookup) >= 0 && face.edges.IndexOf(b, lookup) >= 0) { Debug.LogWarning("Face already exists between these two edges!"); return false; } } Vector3[] verts = pb.vertices; Vector3[] v; Color[] c; int[] s; pb_UV uvs = new pb_UV(); Material mat = pb_Constant.DefaultMaterial; // Get material and UV stuff from the first edge face foreach(pb_Face face in pb.faces) { if(face.edges.Contains(a)) { uvs = new pb_UV(face.uv); mat = face.material; break; } } // Bridge will form a triangle if( a.Contains(b.x, sharedIndices) || a.Contains(b.y, sharedIndices) ) { v = new Vector3[3]; c = new Color[3]; s = new int[3]; bool axbx = System.Array.IndexOf(sharedIndices[sharedIndices.IndexOf(a.x)], b.x) > -1; bool axby = System.Array.IndexOf(sharedIndices[sharedIndices.IndexOf(a.x)], b.y) > -1; bool aybx = System.Array.IndexOf(sharedIndices[sharedIndices.IndexOf(a.y)], b.x) > -1; bool ayby = System.Array.IndexOf(sharedIndices[sharedIndices.IndexOf(a.y)], b.y) > -1; if(axbx) { v[0] = verts[a.x]; c[0] = pb.colors[a.x]; s[0] = sharedIndices.IndexOf(a.x); v[1] = verts[a.y]; c[1] = pb.colors[a.y]; s[1] = sharedIndices.IndexOf(a.y); v[2] = verts[b.y]; c[2] = pb.colors[b.y]; s[2] = sharedIndices.IndexOf(b.y); } else if(axby) { v[0] = verts[a.x]; c[0] = pb.colors[a.x]; s[0] = sharedIndices.IndexOf(a.x); v[1] = verts[a.y]; c[1] = pb.colors[a.y]; s[1] = sharedIndices.IndexOf(a.y); v[2] = verts[b.x]; c[2] = pb.colors[b.x]; s[2] = sharedIndices.IndexOf(b.x); } else if(aybx) { v[0] = verts[a.y]; c[0] = pb.colors[a.y]; s[0] = sharedIndices.IndexOf(a.y); v[1] = verts[a.x]; c[1] = pb.colors[a.x]; s[1] = sharedIndices.IndexOf(a.x); v[2] = verts[b.y]; c[2] = pb.colors[b.y]; s[2] = sharedIndices.IndexOf(b.y); } else if(ayby) { v[0] = verts[a.y]; c[0] = pb.colors[a.y]; s[0] = sharedIndices.IndexOf(a.y); v[1] = verts[a.x]; c[1] = pb.colors[a.x]; s[1] = sharedIndices.IndexOf(a.x); v[2] = verts[b.x]; c[2] = pb.colors[b.x]; s[2] = sharedIndices.IndexOf(b.x); } pb.AppendFace( v, c, new Vector2[v.Length], new pb_Face( axbx || axby ? new int[3] {2, 1, 0} : new int[3] {0, 1, 2}, mat, uvs, 0, -1, -1, false ), s); return true; } // Else, bridge will form a quad v = new Vector3[4]; c = new Color[4]; s = new int[4]; // shared indices index to add to v[0] = verts[a.x]; c[0] = pb.colors[a.x]; s[0] = sharedIndices.IndexOf(a.x); v[1] = verts[a.y]; c[1] = pb.colors[a.y]; s[1] = sharedIndices.IndexOf(a.y); Vector3 nrm = Vector3.Cross( verts[b.x]-verts[a.x], verts[a.y]-verts[a.x] ).normalized; Vector2[] planed = pb_Math.PlanarProject( new Vector3[4] {verts[a.x], verts[a.y], verts[b.x], verts[b.y] }, nrm ); Vector2 ipoint = Vector2.zero; bool interescts = pb_Math.GetLineSegmentIntersect(planed[0], planed[2], planed[1], planed[3], ref ipoint); if(!interescts) { v[2] = verts[b.x]; c[2] = pb.colors[b.x]; s[2] = sharedIndices.IndexOf(b.x); v[3] = verts[b.y]; c[3] = pb.colors[b.y]; s[3] = sharedIndices.IndexOf(b.y); } else { v[2] = verts[b.y]; c[2] = pb.colors[b.y]; s[2] = sharedIndices.IndexOf(b.y); v[3] = verts[b.x]; c[3] = pb.colors[b.x]; s[3] = sharedIndices.IndexOf(b.x); } pb.AppendFace( v, c, new Vector2[v.Length], new pb_Face( new int[6] {2, 1, 0, 2, 3, 1 }, mat, uvs, 0, -1, -1, false ), s); return true; }
public static bool Bridge(this pb_Object pb, pb_Edge a, pb_Edge b, bool enforcePerimiterEdgesOnly) { pb_IntArray[] sharedIndices = pb.GetSharedIndices(); Dictionary <int, int> lookup = sharedIndices.ToDictionary(); // Check to see if a face already exists if (enforcePerimiterEdgesOnly) { if (pbMeshUtils.GetNeighborFaces(pb, a).Count > 1 || pbMeshUtils.GetNeighborFaces(pb, b).Count > 1) { return(false); } } foreach (pb_Face face in pb.faces) { if (face.edges.IndexOf(a, lookup) >= 0 && face.edges.IndexOf(b, lookup) >= 0) { Debug.LogWarning("Face already exists between these two edges!"); return(false); } } Vector3[] verts = pb.vertices; Vector3[] v; Color[] c; int[] s; pb_UV uvs = new pb_UV(); Material mat = pb_Constant.DefaultMaterial; // Get material and UV stuff from the first edge face foreach (pb_Face face in pb.faces) { if (face.edges.Contains(a)) { uvs = new pb_UV(face.uv); mat = face.material; break; } } // Bridge will form a triangle if (a.Contains(b.x, sharedIndices) || a.Contains(b.y, sharedIndices)) { v = new Vector3[3]; c = new Color[3]; s = new int[3]; bool axbx = System.Array.IndexOf(sharedIndices[sharedIndices.IndexOf(a.x)], b.x) > -1; bool axby = System.Array.IndexOf(sharedIndices[sharedIndices.IndexOf(a.x)], b.y) > -1; bool aybx = System.Array.IndexOf(sharedIndices[sharedIndices.IndexOf(a.y)], b.x) > -1; bool ayby = System.Array.IndexOf(sharedIndices[sharedIndices.IndexOf(a.y)], b.y) > -1; if (axbx) { v[0] = verts[a.x]; c[0] = pb.colors[a.x]; s[0] = sharedIndices.IndexOf(a.x); v[1] = verts[a.y]; c[1] = pb.colors[a.y]; s[1] = sharedIndices.IndexOf(a.y); v[2] = verts[b.y]; c[2] = pb.colors[b.y]; s[2] = sharedIndices.IndexOf(b.y); } else if (axby) { v[0] = verts[a.x]; c[0] = pb.colors[a.x]; s[0] = sharedIndices.IndexOf(a.x); v[1] = verts[a.y]; c[1] = pb.colors[a.y]; s[1] = sharedIndices.IndexOf(a.y); v[2] = verts[b.x]; c[2] = pb.colors[b.x]; s[2] = sharedIndices.IndexOf(b.x); } else if (aybx) { v[0] = verts[a.y]; c[0] = pb.colors[a.y]; s[0] = sharedIndices.IndexOf(a.y); v[1] = verts[a.x]; c[1] = pb.colors[a.x]; s[1] = sharedIndices.IndexOf(a.x); v[2] = verts[b.y]; c[2] = pb.colors[b.y]; s[2] = sharedIndices.IndexOf(b.y); } else if (ayby) { v[0] = verts[a.y]; c[0] = pb.colors[a.y]; s[0] = sharedIndices.IndexOf(a.y); v[1] = verts[a.x]; c[1] = pb.colors[a.x]; s[1] = sharedIndices.IndexOf(a.x); v[2] = verts[b.x]; c[2] = pb.colors[b.x]; s[2] = sharedIndices.IndexOf(b.x); } pb.AppendFace( v, c, new Vector2[v.Length], new pb_Face(axbx || axby ? new int[3] { 2, 1, 0 } : new int[3] { 0, 1, 2 }, mat, uvs, 0, -1, -1, false), s); return(true); } // Else, bridge will form a quad v = new Vector3[4]; c = new Color[4]; s = new int[4]; // shared indices index to add to v[0] = verts[a.x]; c[0] = pb.colors[a.x]; s[0] = sharedIndices.IndexOf(a.x); v[1] = verts[a.y]; c[1] = pb.colors[a.y]; s[1] = sharedIndices.IndexOf(a.y); Vector3 nrm = Vector3.Cross(verts[b.x] - verts[a.x], verts[a.y] - verts[a.x]).normalized; Vector2[] planed = pb_Math.PlanarProject(new Vector3[4] { verts[a.x], verts[a.y], verts[b.x], verts[b.y] }, nrm); Vector2 ipoint = Vector2.zero; bool interescts = pb_Math.GetLineSegmentIntersect(planed[0], planed[2], planed[1], planed[3], ref ipoint); if (!interescts) { v[2] = verts[b.x]; c[2] = pb.colors[b.x]; s[2] = sharedIndices.IndexOf(b.x); v[3] = verts[b.y]; c[3] = pb.colors[b.y]; s[3] = sharedIndices.IndexOf(b.y); } else { v[2] = verts[b.y]; c[2] = pb.colors[b.y]; s[2] = sharedIndices.IndexOf(b.y); v[3] = verts[b.x]; c[3] = pb.colors[b.x]; s[3] = sharedIndices.IndexOf(b.x); } pb.AppendFace( v, c, new Vector2[v.Length], new pb_Face(new int[6] { 2, 1, 0, 2, 3, 1 }, mat, uvs, 0, -1, -1, false), s); return(true); }
/** * Returns the indices of perimeter vertices in selection. */ public static int[] GetPerimeterVertices(pb_Object pb, int[] indices, pb_Edge[] universal_edges_all) { int len = indices.Length; pb_IntArray[] sharedIndices = pb.sharedIndices; int[] universal = new int[len]; for(int i = 0; i < len; i++) universal[i] = sharedIndices.IndexOf(indices[i]); int[] connections = new int[indices.Length]; for(int i = 0; i < indices.Length - 1; i++) { for(int n = i+1; n < indices.Length; n++) { if(universal_edges_all.Contains(universal[i], universal[n])) { connections[i]++; connections[n]++; } } } int min = pb_Math.Min(connections); List<int> perimeter = new List<int>(); for(int i = 0; i < len; i++) { if(connections[i] <= min) perimeter.Add(i); } return perimeter.Count < len ? perimeter.ToArray() : new int[] {}; }
/** * \brief Returns faces that share an edge with any of @c selFcaes. */ public static pb_Face[] GetNeighborFaces(pb_Object pb, Dictionary<int, int> sharedIndicesLookup, pb_Face[] selFaces) { List<pb_Face> perimeterFaces = new List<pb_Face>(); pb_Edge[] perimeterEdges = pbMeshUtils.GetPerimeterEdges(pb, sharedIndicesLookup, selFaces).ToArray(); pb_Edge[] universalEdges = new pb_Edge[perimeterEdges.Length]; for(int i = 0; i < perimeterEdges.Length; i++) universalEdges[i] = new pb_Edge( sharedIndicesLookup[perimeterEdges[i].x], sharedIndicesLookup[perimeterEdges[i].y]); pb_Edge edge_u = new pb_Edge(-1, -1); HashSet<pb_Face> skip = new HashSet<pb_Face>(selFaces); foreach(pb_Face face in pb.faces) { if(skip.Contains(face)) { skip.Remove(face); continue; } foreach(pb_Edge edge in face.edges) { edge_u.x = sharedIndicesLookup[edge.x]; edge_u.y = sharedIndicesLookup[edge.y]; if(universalEdges.Contains(edge_u)) { perimeterFaces.Add(face); break; } } } return perimeterFaces.ToArray(); }