示例#1
0
/**
 *	\brief
 *	param sharedIndex An optional array that sets the new pb_Face indices to use the _sharedIndices array.
 *	\returns The newly appended pb_Face.
 */
        public static pb_Face AppendFace(this pb_Object pb, Vector3[] v, pb_Face face)
        {
            int[] shared = new int[v.Length];
            for (int i = 0; i < v.Length; i++)
            {
                shared[i] = -1;
            }
            return(pb.AppendFace(v, face, shared));
        }
示例#2
0
        /**
         *	Given a face and a point, this will add a vertex to the pb_Object and retriangulate the face.
         */
        public static bool AppendVerticesToFace(this pb_Object pb, pb_Face face, List <Vector3> points, out pb_Face newFace)
        {
            if (!face.isValid())
            {
                newFace = face;
                return(false);
            }

            // First order of business - project face to 2d
            int[]     distinctIndices = face.distinctIndices;
            Vector3[] verts           = pb.GetVertices(distinctIndices);

            // Get the face normal before modifying the vertex array
            Vector3 nrm      = pb_Math.Normal(pb.GetVertices(face.indices));
            Vector3 projAxis = pb_Math.GetProjectionAxis(nrm).ToVector3();

            // Add the new point
            Vector3[] t_verts = new Vector3[verts.Length + points.Count];
            System.Array.Copy(verts, 0, t_verts, 0, verts.Length);
            System.Array.Copy(points.ToArray(), 0, t_verts, verts.Length, points.Count);

            verts = t_verts;

            // Project
            List <Vector2> plane = new List <Vector2>(pb_Math.VerticesTo2DPoints(verts, projAxis));

            // Save the sharedIndices index for each distinct vertex
            pb_IntArray[] sharedIndices = pb.sharedIndices;
            int[]         sharedIndex   = new int[distinctIndices.Length + points.Count];
            for (int i = 0; i < distinctIndices.Length; i++)
            {
                sharedIndex[i] = sharedIndices.IndexOf(distinctIndices[i]);
            }

            for (int i = distinctIndices.Length; i < distinctIndices.Length + points.Count; i++)
            {
                sharedIndex[i] = -1;            // add the new vertex to it's own sharedIndex
            }
            // Triangulate the face with the new point appended
            int[] tris = Delauney.Triangulate(plane).ToIntArray();

            // Check to make sure the triangulated face is facing the same direction, and flip if not
            Vector3 del = Vector3.Cross(verts[tris[2]] - verts[tris[0]], verts[tris[1]] - verts[tris[0]]).normalized;

            if (Vector3.Dot(nrm, del) > 0)
            {
                System.Array.Reverse(tris);
            }

            // Compose new face
            newFace = pb.AppendFace(verts, new pb_Face(tris, face.material, new pb_UV(face.uv), face.smoothingGroup, face.textureGroup, -1, face.color), sharedIndex);

            // And delete the old
            pb.DeleteFace(face);

            return(true);
        }
示例#3
0
        /**
         *	Given a face and a point, this will add a vertex to the pb_Object and retriangulate the face.
         */
        public static bool AppendVerticesToFace(this pb_Object pb, pb_Face face, Vector3[] points, Color[] addColors, out pb_Face newFace)
        {
            if (!face.IsValid())
            {
                newFace = face;
                return(false);
            }

            // First order of business - project face to 2d
            int[]     distinctIndices = face.distinctIndices;
            Vector3[] verts           = pb.GetVertices(distinctIndices);
            Color[]   cols            = pbUtil.ValuesWithIndices(pb.colors, distinctIndices);
            Vector2[] uvs             = new Vector2[distinctIndices.Length + points.Length];
            System.Array.Copy(pb.GetUVs(distinctIndices), 0, uvs, 0, distinctIndices.Length);

            // Add the new point
            Vector3[] t_verts = new Vector3[verts.Length + points.Length];
            System.Array.Copy(verts, 0, t_verts, 0, verts.Length);
            System.Array.Copy(points, 0, t_verts, verts.Length, points.Length);
            verts = t_verts;

            // Add the new color
            Color[] t_col = new Color[cols.Length + addColors.Length];
            System.Array.Copy(cols, 0, t_col, 0, cols.Length);
            System.Array.Copy(addColors, 0, t_col, cols.Length, addColors.Length);
            cols = t_col;

            // Get the face normal before modifying the vertex array
            Vector3 nrm      = pb_Math.Normal(pb.GetVertices(face.indices));
            Vector3 projAxis = pb_Math.ProjectionAxisToVector(pb_Math.VectorToProjectionAxis(nrm));

            // Project
            List <Vector2> plane = new List <Vector2>(pb_Math.PlanarProject(verts, projAxis));

            // Save the sharedIndices index for each distinct vertex
            pb_IntArray[] sharedIndices = pb.sharedIndices;
            int[]         sharedIndex   = new int[distinctIndices.Length + points.Length];
            for (int i = 0; i < distinctIndices.Length; i++)
            {
                sharedIndex[i] = sharedIndices.IndexOf(distinctIndices[i]);
            }

            for (int i = distinctIndices.Length; i < distinctIndices.Length + points.Length; i++)
            {
                sharedIndex[i] = -1;            // add the new vertex to it's own sharedIndex
            }
            // Triangulate the face with the new point appended
            int[] tris = Delaunay.Triangulate(plane).ToIntArray();

            // Check to make sure the triangulated face is facing the same direction, and flip if not
            Vector3 del = Vector3.Cross(verts[tris[2]] - verts[tris[0]], verts[tris[1]] - verts[tris[0]]).normalized;

            if (Vector3.Dot(nrm, del) > 0)
            {
                System.Array.Reverse(tris);
            }

            // Build the new face
            pb_Face triangulated_face = new pb_Face(tris, face.material, new pb_UV(face.uv), face.smoothingGroup, face.textureGroup, -1, face.manualUV);

            /**
             * Attempt to figure out where the new UV point(s) should go (if auto uv'ed face)
             */
            if (triangulated_face.manualUV)
            {
                for (int n = distinctIndices.Length; n < uvs.Length; n++)
                {
                    // these are the two vertices that are split by the new vertex
                    int[] adjacent_vertex = System.Array.FindAll(triangulated_face.edges, x => x.Contains(n)).Select(x => x.x != n ? x.x : x.y).ToArray();

                    if (adjacent_vertex.Length == 2)
                    {
                        uvs[n] = (uvs[adjacent_vertex[0]] + uvs[adjacent_vertex[1]]) / 2f;
                    }
                    else
                    {
                        Debug.LogWarning("Failed to find appropriate UV coordinate for new vertex point.  Setting face to AutoUV.");
                        triangulated_face.manualUV = false;
                    }
                }
            }

            // Compose new face
            newFace = pb.AppendFace(verts, cols, uvs, triangulated_face, sharedIndex);

            // And delete the old
            pb.DeleteFace(face);

            return(true);
        }
示例#4
0
        public static void Extrude(this pb_Object pb, pb_Face[] faces, float extrudeDistance)
        {
            if (faces == null || faces.Length < 1)
            {
                return;
            }

            pb_IntArray[] sharedIndices = pb.GetSharedIndices();

            Vector3[] localVerts = pb.vertices;
            Vector3[] oNormals   = pb.msh.normals;

            pb_Edge[] perimeterEdges = pb.GetPerimeterEdges(faces);

            if (perimeterEdges == null || perimeterEdges.Length < 3)
            {
                Debug.LogWarning("No perimeter edges found.  Try deselecting and reselecting this object and trying again.");
                return;
            }

            pb_Face[] edgeFaces      = new pb_Face[perimeterEdges.Length];      // can't assume faces and perimiter edges will be 1:1 - so calculate perimeters then extrace face information
            int[]     allEdgeIndices = new int[perimeterEdges.Length * 2];
            int       c = 0;

            for (int i = 0; i < perimeterEdges.Length; i++)
            {
                // wtf does this do
                edgeFaces[i] = faces[0];
                foreach (pb_Face face in faces)
                {
                    if (face.edges.Contains(perimeterEdges[i]))
                    {
                        edgeFaces[i] = face;
                    }
                }

                allEdgeIndices[c++] = perimeterEdges[i].x;
                allEdgeIndices[c++] = perimeterEdges[i].y;
            }

            List <pb_Edge> extrudedIndices = new List <pb_Edge>();

            /// build out new faces around edges
            for (int i = 0; i < perimeterEdges.Length; i++)
            {
                pb_Edge edge = perimeterEdges[i];
                pb_Face face = edgeFaces[i];

                // Averages the normals using only vertices that are on the edge
                Vector3 xnorm = Vector3.zero;
                Vector3 ynorm = Vector3.zero;

                // don't bother getting vertex normals if not auto-extruding
                if (extrudeDistance > Mathf.Epsilon)
                {
                    xnorm = Norm(edge.x, sharedIndices, allEdgeIndices, oNormals);
                    ynorm = Norm(edge.y, sharedIndices, allEdgeIndices, oNormals);
                }

                int x_sharedIndex = sharedIndices.IndexOf(edge.x);
                int y_sharedIndex = sharedIndices.IndexOf(edge.y);

                pb_Face newFace = pb.AppendFace(
                    new Vector3[4]
                {
                    localVerts [edge.x],
                    localVerts [edge.y],
                    localVerts [edge.x] + xnorm.normalized * extrudeDistance,
                    localVerts [edge.y] + ynorm.normalized * extrudeDistance
                },
                    new pb_Face(
                        new int[6] {
                    0, 1, 2, 1, 3, 2
                },                                                                      // indices
                        face.material,                                                  // material
                        new pb_UV(face.uv),                                             // UV material
                        face.smoothingGroup,                                            // smoothing group
                        -1,                                                             // texture group
                        -1,                                                             // uv element group
                        face.colors[0]),                                                // colors
                    new int[4] {
                    x_sharedIndex, y_sharedIndex, -1, -1
                });

                extrudedIndices.Add(new pb_Edge(x_sharedIndex, newFace.indices[2]));
                extrudedIndices.Add(new pb_Edge(y_sharedIndex, newFace.indices[4]));
            }

            // merge extruded vertex indices with each other
            pb_IntArray[] si = pb.sharedIndices;        // leave the sharedIndices copy alone since we need the un-altered version later
            for (int i = 0; i < extrudedIndices.Count; i++)
            {
                int val = extrudedIndices[i].x;
                for (int n = 0; n < extrudedIndices.Count; n++)
                {
                    if (n == i)
                    {
                        continue;
                    }

                    if (extrudedIndices[n].x == val)
                    {
                        pb_IntArrayUtility.MergeSharedIndices(ref si, extrudedIndices[n].y, extrudedIndices[i].y);
                        break;
                    }
                }
            }

            // Move extruded faces to top
            localVerts = pb.vertices;
            Dictionary <int, int> remappedTexGroups = new Dictionary <int, int>();

            foreach (pb_Face f in faces)
            {
                // Remap texture groups
                if (f.textureGroup > 0)
                {
                    if (remappedTexGroups.ContainsKey(f.textureGroup))
                    {
                        f.textureGroup = remappedTexGroups[f.textureGroup];
                    }
                    else
                    {
                        int newTexGroup = pb.UnusedTextureGroup();
                        remappedTexGroups.Add(f.textureGroup, newTexGroup);
                        f.textureGroup = newTexGroup;
                    }
                }

                int[] distinctIndices = f.distinctIndices;

                foreach (int ind in distinctIndices)
                {
                    int oldIndex = si.IndexOf(ind);
                    for (int i = 0; i < extrudedIndices.Count; i++)
                    {
                        if (oldIndex == extrudedIndices[i].x)
                        {
                            pb_IntArrayUtility.MergeSharedIndices(ref si, extrudedIndices[i].y, ind);
                            break;
                        }
                    }
                }
            }

            // this is a separate loop cause the one above this must completely merge all sharedindices prior to
            // checking the normal averages
            foreach (pb_Face f in faces)
            {
                foreach (int ind in f.distinctIndices)
                {
                    Vector3 norm = Norm(ind, si, allEdgeIndices, oNormals);
                    localVerts[ind] += norm.normalized * extrudeDistance;
                }
            }

            pb.SetSharedIndices(si);
            pb.SetVertices(localVerts);
            pb.RebuildFaceCaches();
        }
示例#5
0
        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);
        }
示例#6
0
        /**
         *	Edge extrusion override
         */
        public static pb_Edge[] Extrude(this pb_Object pb, pb_Edge[] edges, float extrudeDistance, bool enforcePerimiterEdgesOnly)
        {
            pb_IntArray[] sharedIndices = pb.sharedIndices;

            List <pb_Edge> validEdges = new List <pb_Edge>();
            List <pb_Face> edgeFaces  = new List <pb_Face>();

            foreach (pb_Edge e in edges)
            {
                int     faceCount = 0;
                pb_Face fa        = null;
                foreach (pb_Face f in pb.faces)
                {
                    if (f.edges.IndexOf(e, sharedIndices) > -1)
                    {
                        fa = f;
                        if (++faceCount > 1)
                        {
                            break;
                        }
                    }
                }

                if (!enforcePerimiterEdgesOnly || faceCount < 2)
                {
                    validEdges.Add(e);
                    edgeFaces.Add(fa);
                }
            }

            if (validEdges.Count < 1)
            {
                return(null);
            }

            Vector3[] localVerts = pb.vertices;
            Vector3[] oNormals   = pb.msh.normals;

            int[] allEdgeIndices = new int[validEdges.Count * 2];
            int   c = 0;        // har har har

            for (int i = 0; i < validEdges.Count; i++)
            {
                allEdgeIndices[c++] = validEdges[i].x;
                allEdgeIndices[c++] = validEdges[i].y;
            }

            List <pb_Edge> extrudedIndices = new List <pb_Edge>();
            List <pb_Edge> newEdges        = new List <pb_Edge>();      // used to set the editor selection to the newly created edges

            /// build out new faces around validEdges

            for (int i = 0; i < validEdges.Count; i++)
            {
                pb_Edge edge = validEdges[i];
                pb_Face face = edgeFaces[i];

                // Averages the normals using only vertices that are on the edge
                Vector3 xnorm = Norm(edge.x, sharedIndices, allEdgeIndices, oNormals);
                Vector3 ynorm = Norm(edge.y, sharedIndices, allEdgeIndices, oNormals);

                int x_sharedIndex = sharedIndices.IndexOf(edge.x);
                int y_sharedIndex = sharedIndices.IndexOf(edge.y);

                pb_Face newFace = pb.AppendFace(
                    new Vector3[4]
                {
                    localVerts [edge.x],
                    localVerts [edge.y],
                    localVerts [edge.x] + xnorm.normalized * extrudeDistance,
                    localVerts [edge.y] + ynorm.normalized * extrudeDistance
                },
                    new pb_Face(new int[6] {
                    2, 1, 0, 2, 3, 1
                }, face.material, new pb_UV(), 0, -1, -1, face.colors[0]),
                    new int[4] {
                    x_sharedIndex, y_sharedIndex, -1, -1
                });

                newEdges.Add(new pb_Edge(newFace.indices[3], newFace.indices[4]));

                extrudedIndices.Add(new pb_Edge(x_sharedIndex, newFace.indices[3]));
                extrudedIndices.Add(new pb_Edge(y_sharedIndex, newFace.indices[4]));
            }

            sharedIndices = pb.sharedIndices;

            // merge extruded vertex indices with each other
            for (int i = 0; i < extrudedIndices.Count; i++)
            {
                int val = extrudedIndices[i].x;
                for (int n = 0; n < extrudedIndices.Count; n++)
                {
                    if (n == i)
                    {
                        continue;
                    }

                    if (extrudedIndices[n].x == val)
                    {
                        pb_IntArrayUtility.MergeSharedIndices(ref sharedIndices, extrudedIndices[n].y, extrudedIndices[i].y);
                        break;
                    }
                }
            }

            pb.SetSharedIndices(sharedIndices);
            pb.RebuildFaceCaches();

            return(newEdges.ToArray());
        }
示例#7
0
        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);
        }