Exemple #1
0
        internal static void ApplySmoothingGroups(ProBuilderMesh mesh, IEnumerable <Face> faces, float angleThreshold, Vector3[] normals)
        {
            if (mesh == null || faces == null)
            {
                throw new System.ArgumentNullException("mesh");
            }

            // Reset the selected faces to no smoothing group
            bool anySmoothed = false;

            foreach (Face face in faces)
            {
                if (face.smoothingGroup != smoothingGroupNone)
                {
                    anySmoothed = true;
                }

                face.smoothingGroup = Smoothing.smoothingGroupNone;
            }

            // if a set of normals was not supplied, get a new set of normals
            // with no prior smoothing groups applied.
            if (normals == null)
            {
                if (anySmoothed)
                {
                    mesh.mesh.normals = null;
                }
                normals = mesh.GetNormals();
            }

            float             threshold = Mathf.Abs(Mathf.Cos(Mathf.Clamp(angleThreshold, 0f, 89.999f) * Mathf.Deg2Rad));
            HashSet <int>     used      = new HashSet <int>(mesh.facesInternal.Select(x => x.smoothingGroup));
            int               group     = GetNextUnusedSmoothingGroup(1, used);
            HashSet <Face>    processed = new HashSet <Face>();
            List <WingedEdge> wings     = WingedEdge.GetWingedEdges(mesh, faces, true);

            foreach (WingedEdge wing in wings)
            {
                // Already part of a group
                if (!processed.Add(wing.face))
                {
                    continue;
                }

                wing.face.smoothingGroup = group;

                if (FindSoftEdgesRecursive(normals, wing, threshold, processed))
                {
                    used.Add(group);
                    group = GetNextUnusedSmoothingGroup(group, used);
                }
                else
                {
                    wing.face.smoothingGroup = Smoothing.smoothingGroupNone;
                }
            }
        }
Exemple #2
0
        /// <summary>
        /// Builds a list of predecessors from a given face index to all other faces
        /// Uses the Djikstra pathfinding algorithm
        /// </summary>
        /// <param name="mesh">The mesh of the object</param>
        /// <param name="start">The index of the starting face</param>
        /// <returns>A list of predecessors from a face index to all other faces</returns>
        private static int[] Dijkstra(ProBuilderMesh mesh, int start)
        {
            HashSet <int> visited = new HashSet <int>();
            HashSet <int> toVisit = new HashSet <int>();

            if (s_cachedMesh != mesh || s_cachedFacesCount != mesh.faceCount)
            {
                s_cachedWings = WingedEdge.GetWingedEdges(mesh, true);
                s_cachedFacesIndex.Clear();
                s_cachedFacesCount = mesh.faceCount;

                for (int i = 0; i < mesh.facesInternal.Length; i++)
                {
                    s_cachedFacesIndex.Add(mesh.facesInternal[i], i);
                }
            }
            int wingCount = s_cachedWings.Count;

            float[] weights      = new float[wingCount];
            int[]   predecessors = new int[wingCount];

            for (int i = 0; i < wingCount; i++)
            {
                weights[i]      = float.MaxValue;
                predecessors[i] = -1;
            }

            int current = start;

            weights[current] = 0;
            visited.Add(current);

            // Construct the paths between the start face and every other faces
            while (visited.Count < wingCount)
            {
                var currentWing = s_cachedWings[current];
                var otherWing   = currentWing;
                // Update the weight array for each face next to the current one
                do
                {
                    var opposite = otherWing.opposite;
                    if (opposite == null)
                    {
                        otherWing = otherWing.next;
                        continue;
                    }

                    var idx    = s_cachedFacesIndex[opposite.face];
                    var weight = GetWeight(current, idx, mesh);
                    // Change the predecessor and weight if the new path found if shorter
                    if (weights[current] + weight < weights[idx])
                    {
                        weights[idx]      = weights[current] + weight;
                        predecessors[idx] = current;
                    }
                    // Add the face to the ones we can visit next, if not yet visited
                    if (!toVisit.Contains(idx) && !visited.Contains(idx))
                    {
                        toVisit.Add(idx);
                    }

                    otherWing = otherWing.next;
                } while (otherWing != currentWing);

                // This means there is an isolated face
                if (toVisit.Count == 0)
                {
                    return(predecessors);
                }
                // Look for the next face to visit, choosing the one with less weight
                float min = float.MaxValue;
                foreach (var i in toVisit)
                {
                    if (weights[i] < min)
                    {
                        min     = weights[i];
                        current = i;
                    }
                }
                visited.Add(current);
                toVisit.Remove(current);
            }

            return(predecessors);
        }