Esempio n. 1
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();
        }