Exemple #1
0
        public override ActionResult DoAction()
        {
            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);
        }
        static ActionResult DetachFacesToObject()
        {
            int detachedFaceCount      = 0;
            List <GameObject> detached = new List <GameObject>();

            foreach (ProBuilderMesh mesh in MeshSelection.topInternal)
            {
                if (mesh.selectedFaceCount < 1 || mesh.selectedFaceCount == mesh.facesInternal.Length)
                {
                    continue;
                }

                var primary = mesh.selectedFaceIndexes.ToArray();
                detachedFaceCount += primary.Length;

                List <int> inverse = new List <int>();

                for (int i = 0; i < mesh.facesInternal.Length; i++)
                {
                    if (!primary.Contains(i))
                    {
                        inverse.Add(i);
                    }
                }

                ProBuilderMesh copy = Object.Instantiate(mesh.gameObject, mesh.transform.parent).GetComponent <ProBuilderMesh>();
                copy.MakeUnique();

#if !UNITY_2018_3_OR_NEWER
                // if is prefab, break connection and destroy children
                if (EditorUtility.IsPrefabInstance(copy.gameObject) || EditorUtility.IsPrefabAsset(copy.gameObject))
                {
                    PrefabUtility.DisconnectPrefabInstance(copy.gameObject);
                }
#endif

                if (copy.transform.childCount > 0)
                {
                    for (int i = copy.transform.childCount - 1; i > -1; i--)
                    {
                        Object.DestroyImmediate(copy.transform.GetChild(i).gameObject);
                    }

                    foreach (var child in mesh.transform.GetComponentsInChildren <ProBuilderMesh>())
                    {
                        EditorUtility.SynchronizeWithMeshFilter(child);
                    }
                }

                Undo.RegisterCreatedObjectUndo(copy.gameObject, "Detach Selection");

                copy.transform.position      = mesh.transform.position;
                copy.transform.localScale    = mesh.transform.localScale;
                copy.transform.localRotation = mesh.transform.localRotation;

                mesh.DeleteFaces(primary);
                copy.DeleteFaces(inverse);

                mesh.Rebuild();
                copy.Rebuild();

                mesh.Optimize();
                copy.Optimize();

                mesh.ClearSelection();
                copy.ClearSelection();

                copy.gameObject.name = mesh.gameObject.name + "-detach";
                detached.Add(copy.gameObject);
            }

            MeshSelection.SetSelection(detached.ToArray());
            ProBuilderEditor.Refresh();

            if (detachedFaceCount > 0)
            {
                return(new ActionResult(ActionResult.Status.Success, "Detach " + detachedFaceCount + " faces to new Object"));
            }

            return(new ActionResult(ActionResult.Status.Failure, "No Faces Selected"));
        }
        public override ActionResult DoAction()
        {
            if (MeshSelection.selectedObjectCount < 1)
            {
                return(ActionResult.NoSelection);
            }

            UndoUtility.RecordSelection("Offset Elements(s)");

            var handleRotation = MeshSelection.GetHandleRotation();

            foreach (var group in MeshSelection.elementSelection)
            {
                var mesh      = group.mesh;
                var positions = mesh.positionsInternal;
                var offset    = s_Translation.value;

                switch (s_CoordinateSpace.value)
                {
                case CoordinateSpace.World:
                case CoordinateSpace.Handle:
                {
                    var pre  = mesh.transform.localToWorldMatrix;
                    var post = mesh.transform.worldToLocalMatrix;

                    if (s_CoordinateSpace.value == CoordinateSpace.Handle)
                    {
                        offset = handleRotation * offset;
                    }

                    foreach (var index in mesh.selectedCoincidentVertices)
                    {
                        var p = pre.MultiplyPoint3x4(positions[index]);
                        p += offset;
                        positions[index] = post.MultiplyPoint3x4(p);
                    }
                    break;
                }

                case CoordinateSpace.Local:
                {
                    foreach (var index in mesh.selectedCoincidentVertices)
                    {
                        positions[index] += offset;
                    }
                    break;
                }

                case CoordinateSpace.Element:
                {
                    foreach (var elements in group.elementGroups)
                    {
                        var rotation = Quaternion.Inverse(mesh.transform.rotation) * elements.rotation;
                        var o        = rotation * offset;
                        foreach (var index in elements.indices)
                        {
                            positions[index] += o;
                        }
                    }
                    break;
                }
                }

                mesh.Rebuild();
                mesh.Optimize();
                ProBuilderEditor.Refresh();
            }

            if (ProBuilderEditor.selectMode.ContainsFlag(SelectMode.Edge | SelectMode.TextureEdge))
            {
                return(new ActionResult(ActionResult.Status.Success, "Move " + MeshSelection.selectedEdgeCount + (MeshSelection.selectedEdgeCount > 1 ? " Edges" : " Edge")));
            }
            if (ProBuilderEditor.selectMode.ContainsFlag(SelectMode.Face | SelectMode.TextureFace))
            {
                return(new ActionResult(ActionResult.Status.Success, "Move " + MeshSelection.selectedFaceCount + (MeshSelection.selectedFaceCount > 1 ? " Faces" : " Face")));
            }
            return(new ActionResult(ActionResult.Status.Success, "Move " + MeshSelection.selectedVertexCount + (MeshSelection.selectedVertexCount > 1 ? " Vertices" : " Vertex")));
        }
        protected override ActionResult PerformActionImplementation()
        {
            if (MeshSelection.selectedObjectCount < 1)
            {
                return(ActionResult.NoSelection);
            }

            UndoUtility.RecordSelection("Grow Selection");

            int   grown              = 0;
            bool  angleGrow          = m_GrowSelectionWithAngle;
            bool  iterative          = m_GrowSelectionAngleIterative;
            float growSelectionAngle = m_GrowSelectionAngleValue;

            if (!angleGrow && !iterative)
            {
                iterative = true;
            }

            foreach (ProBuilderMesh pb in InternalUtility.GetComponents <ProBuilderMesh>(Selection.transforms))
            {
                int previousTriCount = pb.selectedVertexCount;

                switch (ProBuilderEditor.selectMode)
                {
                case SelectMode.Vertex:
                    pb.SetSelectedEdges(ElementSelection.GetConnectedEdges(pb, pb.selectedIndexesInternal));
                    break;

                case SelectMode.Edge:
                    pb.SetSelectedEdges(ElementSelection.GetConnectedEdges(pb, pb.selectedIndexesInternal));
                    break;

                case SelectMode.TextureFace:
                case SelectMode.Face:

                    Face[] selectedFaces = pb.GetSelectedFaces();

                    HashSet <Face> sel;

                    if (iterative)
                    {
                        sel = ElementSelection.GrowSelection(pb, selectedFaces, angleGrow ? growSelectionAngle : -1f);
                        sel.UnionWith(selectedFaces);
                    }
                    else
                    {
                        sel = ElementSelection.FloodSelection(pb, selectedFaces, angleGrow ? growSelectionAngle : -1f);
                    }

                    pb.SetSelectedFaces(sel.ToArray());

                    break;
                }

                grown += pb.selectedVertexCount - previousTriCount;
            }

            ProBuilderEditor.Refresh();
            SceneView.RepaintAll();

            if (grown > 0)
            {
                return(new ActionResult(ActionResult.Status.Success, "Grow Selection"));
            }

            return(new ActionResult(ActionResult.Status.Failure, "Nothing to Grow"));
        }
        public override ActionResult DoAction()
        {
            if (MeshSelection.selectedObjectCount < 1)
            {
                return(ActionResult.NoSelection);
            }

            ActionResult res = ActionResult.NoSelection;

            UndoUtility.RecordSelection("Weld Vertices");

            int weldCount = 0;

            foreach (ProBuilderMesh mesh in MeshSelection.topInternal)
            {
                weldCount += mesh.sharedVerticesInternal.Length;

                if (mesh.selectedIndexesInternal.Length > 1)
                {
                    mesh.ToMesh();

                    var   selectedVertices = mesh.GetCoincidentVertices(mesh.selectedVertices);
                    int[] welds            = mesh.WeldVertices(mesh.selectedIndexesInternal, m_WeldDistance);
                    res = welds != null ? new ActionResult(ActionResult.Status.Success, "Weld Vertices") : new ActionResult(ActionResult.Status.Failure, "Failed Weld Vertices");

                    if (res)
                    {
                        var newSelection = welds ?? new int[0] {
                        };


                        if (MeshValidation.ContainsDegenerateTriangles(mesh))
                        {
                            List <int> removedIndices = new List <int>();

                            if (MeshValidation.RemoveDegenerateTriangles(mesh, removedIndices))
                            {
                                var newlySelectedVertices = new List <int>();
                                selectedVertices.Sort();
                                removedIndices.Sort();

                                int count = 0;

                                for (int i = 0; i < selectedVertices.Count; i++)
                                {
                                    if (count >= removedIndices.Count || selectedVertices[i] != removedIndices[count])
                                    {
                                        newlySelectedVertices.Add(selectedVertices[i] - UnityEngine.ProBuilder.ArrayUtility.NearestIndexPriorToValue(removedIndices, selectedVertices[i]) - 1);
                                    }
                                    else
                                    {
                                        ++count;
                                    }
                                }

                                newSelection = newlySelectedVertices.ToArray();
                            }
                            mesh.ToMesh();
                        }
                        mesh.SetSelectedVertices(newSelection);
                    }

                    mesh.Refresh();
                    mesh.Optimize();
                }

                weldCount -= mesh.sharedVerticesInternal.Length;
            }

            ProBuilderEditor.Refresh();

            if (res && weldCount > 0)
            {
                return(new ActionResult(ActionResult.Status.Success, "Weld " + weldCount + (weldCount > 1 ? " Vertices" : " Vertex")));
            }

            return(new ActionResult(ActionResult.Status.Failure, "Nothing to Weld"));
        }
        static ActionResult DetachFacesToObject()
        {
            int detachedFaceCount      = 0;
            List <GameObject> detached = new List <GameObject>();

            foreach (ProBuilderMesh mesh in MeshSelection.topInternal)
            {
                if (mesh.selectedFaceCount < 1 || mesh.selectedFaceCount == mesh.facesInternal.Length)
                {
                    continue;
                }

                var primary = mesh.selectedFaceIndexes;
                detachedFaceCount += primary.Count;

                List <int> inverse = new List <int>();

                for (int i = 0; i < mesh.facesInternal.Length; i++)
                {
                    if (!primary.Contains(i))
                    {
                        inverse.Add(i);
                    }
                }

                ProBuilderMesh copy = Object.Instantiate(mesh.gameObject, mesh.transform.parent).GetComponent <ProBuilderMesh>();
                EditorUtility.SynchronizeWithMeshFilter(copy);

                if (copy.transform.childCount > 0)
                {
                    for (int i = copy.transform.childCount - 1; i > -1; i--)
                    {
                        Object.DestroyImmediate(copy.transform.GetChild(i).gameObject);
                    }

                    foreach (var child in mesh.transform.GetComponentsInChildren <ProBuilderMesh>())
                    {
                        EditorUtility.SynchronizeWithMeshFilter(child);
                    }
                }

                Undo.RegisterCreatedObjectUndo(copy.gameObject, "Detach Selection");

                mesh.DeleteFaces(primary);
                copy.DeleteFaces(inverse);

                mesh.Rebuild();
                copy.Rebuild();

                mesh.Optimize();
                copy.Optimize();

                mesh.ClearSelection();
                copy.ClearSelection();

                copy.SetSelectedFaces(copy.faces);

                copy.gameObject.name = GameObjectUtility.GetUniqueNameForSibling(mesh.transform.parent, mesh.gameObject.name);;
                detached.Add(copy.gameObject);
            }

            MeshSelection.SetSelection(detached);
            ProBuilderEditor.Refresh();

            if (detachedFaceCount > 0)
            {
                return(new ActionResult(ActionResult.Status.Success, "Detach " + detachedFaceCount + " faces to new Object"));
            }

            return(new ActionResult(ActionResult.Status.Failure, "No Faces Selected"));
        }
        public override ActionResult DoAction()
        {
            UndoUtility.RecordSelection("Select Faces with Vertex Colors");

            HashSet <Color32> colors = new HashSet <Color32>();

            foreach (ProBuilderMesh pb in MeshSelection.topInternal)
            {
                Color[] mesh_colors = pb.colorsInternal;

                if (mesh_colors == null || mesh_colors.Length != pb.vertexCount)
                {
                    continue;
                }

                foreach (int i in pb.selectedIndexesInternal)
                {
                    colors.Add(mesh_colors[i]);
                }
            }

            List <GameObject> newSelection = new List <GameObject>();
            bool selectionOnly             = m_SearchSelectedObjectsOnly;

            IEnumerable <ProBuilderMesh> pool;

            if (selectionOnly)
            {
                pool = MeshSelection.topInternal;
            }
            else
            {
                pool = Object.FindObjectsOfType <ProBuilderMesh>();
            }

            //If the original selection does not have colors assigned we will select faces without colors
            if (colors.Count == 0)
            {
                foreach (ProBuilderMesh pb in pool)
                {
                    if (pb.colorsInternal == null)
                    {
                        List <Face> matches = new List <Face>();
                        Face[]      faces   = pb.facesInternal;

                        foreach (var face in faces)
                        {
                            matches.Add(face);
                        }

                        if (matches.Count > 0)
                        {
                            newSelection.Add(pb.gameObject);
                            pb.SetSelectedFaces(matches);
                        }
                    }
                }
            }
            else
            {
                foreach (ProBuilderMesh pb in pool)
                {
                    Color[] mesh_colors = pb.colorsInternal;

                    if (mesh_colors == null || mesh_colors.Length != pb.vertexCount)
                    {
                        continue;
                    }

                    List <Face> matches = new List <Face>();
                    Face[]      faces   = pb.facesInternal;

                    for (int i = 0; i < faces.Length; i++)
                    {
                        int[] tris = faces[i].distinctIndexesInternal;

                        for (int n = 0; n < tris.Length; n++)
                        {
                            if (colors.Contains((Color32)mesh_colors[tris[n]]))
                            {
                                matches.Add(faces[i]);
                                break;
                            }
                        }
                    }

                    if (matches.Count > 0)
                    {
                        newSelection.Add(pb.gameObject);
                        pb.SetSelectedFaces(matches);
                    }
                }
            }

            Selection.objects = newSelection.ToArray();

            ProBuilderEditor.Refresh();

            return(new ActionResult(ActionResult.Status.Success, "Select Faces with Vertex Colors"));
        }