Ejemplo n.º 1
0
        /**
         *	\brief Collapses all passed indices to a single shared index.
         *
         */
        public static bool MergeVertices(this pb_Object pb, int[] indices)
        {
            Vector3[] verts = pb.vertices;
            Vector3   cen   = Vector3.zero;

            foreach (int i in indices)
            {
                cen += verts[i];
            }

            cen /= (float)indices.Length;

            pb_IntArray[] sharedIndices = pb.sharedIndices;
            int           newIndex      = pb_IntArrayUtility.MergeSharedIndices(ref sharedIndices, indices);

            pb.SetSharedIndices(sharedIndices);

            int firstTriInSharedIndexArr = pb.sharedIndices[newIndex][0];

            pb.SetSharedVertexPosition(firstTriInSharedIndexArr, cen);

            int[] mergedSharedIndex = pb.GetSharedIndices()[newIndex].array;

            int[] removedIndices = pb.RemoveDegenerateTriangles();

            // get a non-deleted index to work with
            int ind = -1;

            for (int i = 0; i < mergedSharedIndex.Length; i++)
            {
                if (!removedIndices.Contains(mergedSharedIndex[i]))
                {
                    ind = mergedSharedIndex[i];
                }
            }


            int t = ind;

            for (int i = 0; i < removedIndices.Length; i++)
            {
                if (ind > removedIndices[i])
                {
                    t--;
                }
            }

            pb.ClearSelection();

            if (t > -1)
            {
                pb.SetSelectedTriangles(new int[1] {
                    t
                });
            }

            return(true);
        }
Ejemplo n.º 2
0
        /**
         *	\brief Collapses all passed indices to a single shared index.  Retains vertex normals.
         *
         */
        public static bool MergeVertices(this pb_Object pb, int[] indices, out int collapsedIndex)
        {
            Vector3[] verts = pb.vertices;
            Vector3   cen   = Vector3.zero;

            foreach (int i in indices)
            {
                cen += verts[i];
            }

            cen /= (float)indices.Length;

            pb_IntArray[] sharedIndices = pb.sharedIndices;
            int           newIndex      = pb_IntArrayUtility.MergeSharedIndices(ref sharedIndices, indices);

            pb.SetSharedIndices(sharedIndices);

            pb.SetSharedVertexPosition(newIndex, cen);

            int[] mergedSharedIndex = pb.GetSharedIndices()[newIndex].array;

            int[] removedIndices;
            pb.RemoveDegenerateTriangles(out removedIndices);

            // get a non-deleted index to work with
            int ind = -1;

            for (int i = 0; i < mergedSharedIndex.Length; i++)
            {
                if (!removedIndices.Contains(mergedSharedIndex[i]))
                {
                    ind = mergedSharedIndex[i];
                }
            }

            int t = ind;

            for (int i = 0; i < removedIndices.Length; i++)
            {
                if (ind > removedIndices[i])
                {
                    t--;
                }
            }

            if (t > -1)
            {
                collapsedIndex = t;
                return(true);
            }
            else
            {
                collapsedIndex = -1;
                return(false);
            }
        }
        public pb_SerializableObject(pb_Object pb)
        {
            this.vertices = pb.vertices;

            // Make sure the mesh is valid, and in sync with current pb_Object
            if(pb.msh == null || pb.msh.vertexCount != pb.vertexCount)
            {
                pb_UpgradeKitUtils.RebuildMesh(pb);
            }

            this.uv = pb.msh != null ? pb.msh.uv : null;

            if(pb.msh != null && pb.msh.colors != null && pb.msh.colors.Length == pb.vertexCount)
            {
                this.color = pb.msh.colors;
            }
            else
            {
                this.color = new Color[pb.vertexCount];
                for(int i = 0; i < this.color.Length; i++)
                    this.color[i] = Color.white;
            }
            this.faces = pb.faces;
            this.sharedIndices = (int[][])pb.GetSharedIndices().ToArray();

            PropertyInfo prop_uv = pb.GetType().GetProperty("sharedIndicesUV", BindingFlags.Instance | BindingFlags.Public);

            if(prop_uv != null)
            {
                var val = prop_uv.GetValue(pb, null);

                if(val != null)
                {
                    pb_IntArray[] sharedUvs = (pb_IntArray[])val;
                    this.sharedIndicesUV =  (int[][])sharedUvs.ToArray();
                }
                else
                {
                    this.sharedIndicesUV = new int[0][];
                }
            }
            else
            {
                this.sharedIndicesUV = new int[0][];
            }

            PropertyInfo prop_userCollisions = pb.GetType().GetProperty("userCollisions", BindingFlags.Instance | BindingFlags.Public);
            userCollisions = prop_userCollisions == null ? false : (bool) prop_userCollisions.GetValue(pb, null);
        }
Ejemplo n.º 4
0
	/**
	 *	\brief Duplicates and returns the passed pb_Object.
	 *	@param pb The pb_Object to duplicate.
	 *	\returns A unique copy of the passed pb_Object.
	 */
	public static pb_Object InitWithObject(pb_Object pb)
	{
		Vector3[] v = new Vector3[pb.vertexCount];
		System.Array.Copy(pb.vertices, v, pb.vertexCount);

		pb_Face[] f = new pb_Face[pb.faces.Length];
		
		for(int i = 0; i < f.Length; i++)
			f[i] = new pb_Face(pb.faces[i]);

		pb_Object p = CreateInstanceWithVerticesFacesSharedIndices(v, f, pb.GetSharedIndices());

		p.gameObject.name = pb.gameObject.name + "-clone";

		return p;
	}
Ejemplo n.º 5
0
    /**
     *	\brief Duplicates and returns the passed pb_Object.
     *	@param pb The pb_Object to duplicate.
     *	\returns A unique copy of the passed pb_Object.
     */
    public static pb_Object InitWithObject(pb_Object pb)
    {
        Vector3[] v = new Vector3[pb.vertexCount];
        System.Array.Copy(pb.vertices, v, pb.vertexCount);

        pb_Face[] f = new pb_Face[pb.faces.Length];

        for (int i = 0; i < f.Length; i++)
        {
            f[i] = new pb_Face(pb.faces[i]);
        }

        pb_Object p = CreateInstanceWithVerticesFacesSharedIndices(v, f, pb.GetSharedIndices());

        p.gameObject.name = pb.gameObject.name + "-clone";

        return(p);
    }
Ejemplo n.º 6
0
	/**
	 *	\brief Duplicates and returns the passed pb_Object.
	 *	@param pb The pb_Object to duplicate.
	 *	\returns A unique copy of the passed pb_Object.
	 */
	public static pb_Object InitWithObject(pb_Object pb)
	{
		Vector3[] v = new Vector3[pb.vertexCount];
		System.Array.Copy(pb.vertices, v, pb.vertexCount);
		
		Vector2[] u = new Vector2[pb.vertexCount];
		System.Array.Copy(pb.uv, u, pb.vertexCount);

		Color[] c = new Color[pb.vertexCount];
		System.Array.Copy(pb.colors, c, pb.vertexCount);

		pb_Face[] f = new pb_Face[pb.faces.Length];
		
		for(int i = 0; i < f.Length; i++)
			f[i] = new pb_Face(pb.faces[i]);

		pb_Object p = CreateInstanceWithElements(v, u, c, f, pb.GetSharedIndices(), pb.GetSharedIndicesUV());

		p.gameObject.name = pb.gameObject.name + "-clone";

		return p;
	}
Ejemplo n.º 7
0
    /**
     *	\brief Duplicates and returns the passed pb_Object.
     *	@param pb The pb_Object to duplicate.
     *	\returns A unique copy of the passed pb_Object.
     */
    public static pb_Object InitWithObject(pb_Object pb)
    {
        Vector3[] v = new Vector3[pb.vertexCount];
        System.Array.Copy(pb.vertices, v, pb.vertexCount);

        Vector2[] u = new Vector2[pb.vertexCount];
        System.Array.Copy(pb.uv, u, pb.vertexCount);

        Color[] c = new Color[pb.vertexCount];
        System.Array.Copy(pb.colors, c, pb.vertexCount);

        pb_Face[] f = new pb_Face[pb.faces.Length];

        for (int i = 0; i < f.Length; i++)
        {
            f[i] = new pb_Face(pb.faces[i]);
        }

        pb_Object p = CreateInstanceWithElements(v, u, c, f, pb.GetSharedIndices(), pb.GetSharedIndicesUV());

        p.gameObject.name = pb.gameObject.name + "-clone";

        return(p);
    }
Ejemplo n.º 8
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();
        }
Ejemplo n.º 9
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);
        }
Ejemplo n.º 10
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);
        }
Ejemplo n.º 11
0
        /**
         * Extrudes passed faces on their normal axis using extrudeDistance.
         */
        public static bool Extrude(this pb_Object pb, pb_Face[] faces, float extrudeDistance, bool extrudeAsGroup, out pb_Face[] appendedFaces)
        {
            appendedFaces = null;

            if (faces == null || faces.Length < 1)
            {
                return(false);
            }

            pb_IntArray[]         sharedIndices = pb.GetSharedIndices();
            Dictionary <int, int> lookup        = sharedIndices.ToDictionary();

            Vector3[] localVerts = pb.vertices;

            pb_Edge[][] perimeterEdges = extrudeAsGroup ? new pb_Edge[1][] { pbMeshUtils.GetPerimeterEdges(pb, lookup, faces).ToArray() } : faces.Select(x => x.edges).ToArray();

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

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

            for (int i = 0; i < perimeterEdges.Length; i++)
            {
                c = 0;
                allEdgeIndices[i] = new int[perimeterEdges[i].Length * 2];
                edgeFaces[i]      = new pb_Face[perimeterEdges[i].Length];

                for (int n = 0; n < perimeterEdges[i].Length; n++)
                {
                    // gets the faces associated with each perimeter edge
                    foreach (pb_Face face in faces)
                    {
                        if (face.edges.Contains(perimeterEdges[i][n]))
                        {
                            edgeFaces[i][n] = face;
                            break;
                        }
                    }

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

            List <pb_Edge>[] extrudedIndices = new List <pb_Edge> [perimeterEdges.Length];
            Vector3[]        normals         = pb.msh.normals;

            List <Vector3[]> append_vertices = new List <Vector3[]>();
            List <Color[]>   append_color    = new List <Color[]>();
            List <Vector2[]> append_uv       = new List <Vector2[]>();
            List <pb_Face>   append_face     = new List <pb_Face>();
            List <int[]>     append_shared   = new List <int[]>();

            /// build out new faces around edges

            for (int i = 0; i < perimeterEdges.Length; i++)
            {
                extrudedIndices[i] = new List <pb_Edge>();

                for (int n = 0; n < perimeterEdges[i].Length; n++)
                {
                    pb_Edge edge = perimeterEdges[i][n];
                    pb_Face face = edgeFaces[i][n];

                    // 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 (Mathf.Abs(extrudeDistance) > Mathf.Epsilon)
                    {
                        if (!extrudeAsGroup)
                        {
                            xnorm = pb_Math.Normal(localVerts[face.indices[0]], localVerts[face.indices[1]], localVerts[face.indices[2]]);
                            ynorm = xnorm;
                        }
                        else
                        {
                            xnorm = Norm(sharedIndices[lookup[edge.x]], allEdgeIndices[i], normals);
                            ynorm = Norm(sharedIndices[lookup[edge.y]], allEdgeIndices[i], normals);
                        }
                    }

                    int x_sharedIndex = lookup[edge.x];
                    int y_sharedIndex = lookup[edge.y];

                    // this could be condensed to a single call with an array of new faces
                    append_vertices.Add(new Vector3[]
                    {
                        localVerts [edge.x],
                        localVerts [edge.y],
                        localVerts [edge.x] + xnorm.normalized * extrudeDistance,
                        localVerts [edge.y] + ynorm.normalized * extrudeDistance
                    });

                    append_color.Add(new Color[]
                    {
                        pb.colors[edge.x],
                        pb.colors[edge.y],
                        pb.colors[edge.x],
                        pb.colors[edge.y]
                    });

                    append_uv.Add(new Vector2[4]);

                    append_face.Add(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
                                        false)                                                  // manualUV flag
                                    );

                    append_shared.Add(new int[4]
                    {
                        x_sharedIndex,
                        y_sharedIndex,
                        -1,
                        -1
                    });

                    extrudedIndices[i].Add(new pb_Edge(x_sharedIndex, -1));
                    extrudedIndices[i].Add(new pb_Edge(y_sharedIndex, -1));
                }
            }

            appendedFaces = pb.AppendFaces(append_vertices.ToArray(), append_color.ToArray(), append_uv.ToArray(), append_face.ToArray(), append_shared.ToArray());

            // x = shared index, y = triangle (only known once faces are appended to pb_Object)
            for (int i = 0, f = 0; i < extrudedIndices.Length; i++)
            {
                for (int n = 0; n < extrudedIndices[i].Count; n += 2)
                {
                    extrudedIndices[i][n + 0].y = appendedFaces[f].indices[2];
                    extrudedIndices[i][n + 1].y = appendedFaces[f++].indices[4];
                }
            }

            pb_IntArray[]         si    = pb.sharedIndices; // leave the sharedIndices copy alone since we need the un-altered version later
            Dictionary <int, int> welds = si.ToDictionary();

            // Weld side-wall top vertices together, both grouped and non-grouped need this.
            for (int f = 0; f < extrudedIndices.Length; f++)
            {
                for (int i = 0; i < extrudedIndices[f].Count - 1; i++)
                {
                    int val = extrudedIndices[f][i].x;
                    for (int n = i + 1; n < extrudedIndices[f].Count; n++)
                    {
                        if (extrudedIndices[f][n].x == val)
                        {
                            welds[extrudedIndices[f][i].y] = welds[extrudedIndices[f][n].y];
                            break;
                        }
                    }
                }
            }

            localVerts = pb.vertices;

            // Remove smoothing and texture group flags
            foreach (pb_Face f in faces)
            {
                f.SetSmoothingGroup(-1);
                f.textureGroup = -1;
            }

            if (extrudeAsGroup)
            {
                foreach (pb_Face f in faces)
                {
                    int[] distinctIndices = f.distinctIndices;

                    // Merge in-group face seams
                    foreach (int ind in distinctIndices)
                    {
                        int oldIndex = si.IndexOf(ind);

                        for (int n = 0; n < allEdgeIndices.Length; n++)
                        {
                            for (int i = 0; i < extrudedIndices[n].Count; i++)
                            {
                                if (oldIndex == extrudedIndices[n][i].x)
                                {
                                    welds[ind] = welds[extrudedIndices[n][i].y];
                                    break;
                                }
                            }
                        }
                    }
                }
            }
            else

            /**
             * If extruding as separate faces, weld each face to the tops of the bridging faces
             */
            {
                // Dictionary<int, int> hold = si.ToDictionary();

                for (int i = 0; i < edgeFaces.Length; i++)
                {
                    foreach (int n in pb_Face.AllTrianglesDistinct(edgeFaces[i]))
                    {
                        int old_si_index = lookup[n];
                        int match        = extrudedIndices[i].FindIndex(x => x.x == old_si_index);

                        if (match < 0)
                        {
                            continue;
                        }

                        int match_tri_index = extrudedIndices[i][match].y;

                        if (welds.ContainsKey(match_tri_index))
                        {
                            welds[n] = welds[match_tri_index];
                        }
                    }
                }
            }

            si = welds.ToSharedIndices();


            pb.SplitUVs(pb_Face.AllTriangles(faces));

            /**
             * Move the inside faces to the top of the extrusion
             *
             * This is a separate loop cause the one above this must completely merge all sharedindices prior to
             * checking the normal averages
             *
             */
            Vector3 norm = Vector3.zero;

            int[] allIndices = pb_Face.AllTrianglesDistinct(faces);
            foreach (pb_Face f in faces)
            {
                if (!extrudeAsGroup)
                {
                    norm = pb_Math.Normal(localVerts[f.indices[0]], localVerts[f.indices[1]], localVerts[f.indices[2]]);
                }

                foreach (int ind in f.distinctIndices)
                {
                    if (extrudeAsGroup)
                    {
                        norm = Norm(sharedIndices[lookup[ind]], allIndices, normals);
                    }

                    localVerts[ind] += norm.normalized * extrudeDistance;
                }
            }

            // Test the winding of the first pulled face, and reverse if it's ccw
            if (pb.GetWindingOrder(faces[0]) == WindingOrder.CounterClockwise)
            {
                foreach (pb_Face face in appendedFaces)
                {
                    face.ReverseIndices();
                }
            }

            pb.SetSharedIndices(si);
            pb.SetVertices(localVerts);


            return(true);
        }