Esempio n. 1
0
        /// <summary>
        /// Condense co-incident vertex positions per-face. vertices must already be marked as shared in the sharedIndexes
        /// array to be considered. This method is really only useful after merging faces.
        /// </summary>
        /// <param name="mesh"></param>
        /// <param name="faces"></param>
        internal static void CollapseCoincidentVertices(ProBuilderMesh mesh, IEnumerable <Face> faces)
        {
            Dictionary <int, int> lookup  = mesh.sharedVertexLookup;
            Dictionary <int, int> matches = new Dictionary <int, int>();

            foreach (Face face in faces)
            {
                matches.Clear();

                for (int i = 0; i < face.indexesInternal.Length; i++)
                {
                    int common = lookup[face.indexesInternal[i]];

                    if (matches.ContainsKey(common))
                    {
                        face.indexesInternal[i] = matches[common];
                    }
                    else
                    {
                        matches.Add(common, face.indexesInternal[i]);
                    }
                }

                face.InvalidateCache();
            }

            MeshValidation.RemoveUnusedVertices(mesh);
        }
Esempio n. 2
0
        public static int[] RemoveUnusedVertices(this ProBuilderMesh mesh)
        {
            List <int> removed = new List <int>();

            MeshValidation.RemoveUnusedVertices(mesh, removed);
            return(removed.ToArray());
        }
Esempio n. 3
0
        public static int[] RemoveDegenerateTriangles(this ProBuilderMesh mesh)
        {
            List <int> removed = new List <int>();

            MeshValidation.RemoveDegenerateTriangles(mesh, removed);
            return(removed.ToArray());
        }
Esempio n. 4
0
        /// <summary>
        /// Collapses all passed indexes to a single shared index.
        /// </summary>
        /// <remarks>
        /// Retains vertex normals.
        /// </remarks>
        /// <param name="mesh">Target mesh.</param>
        /// <param name="indexes">The indexes to merge to a single shared vertex.</param>
        /// <param name="collapseToFirst">If true, instead of merging all vertices to the average position, the vertices will be collapsed onto the first vertex position.</param>
        /// <returns>The first available local index created as a result of the merge. -1 if action is unsuccessfull.</returns>
        public static int MergeVertices(this ProBuilderMesh mesh, int[] indexes, bool collapseToFirst = false)
        {
            if (mesh == null)
            {
                throw new ArgumentNullException("mesh");
            }

            if (indexes == null)
            {
                throw new ArgumentNullException("indexes");
            }

            Vertex[] vertices = mesh.GetVertices();
            Vertex   cen      = collapseToFirst ? vertices[indexes[0]] : Vertex.Average(vertices, indexes);

            mesh.SetVerticesCoincident(indexes);
            UVEditing.SplitUVs(mesh, indexes);
            int sharedVertexHandle = mesh.GetSharedVertexHandle(indexes.First());

            mesh.SetSharedVertexValues(sharedVertexHandle, cen);

            SharedVertex merged         = mesh.sharedVerticesInternal[sharedVertexHandle];
            List <int>   removedIndexes = new List <int>();

            MeshValidation.RemoveDegenerateTriangles(mesh, removedIndexes);

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

            for (int i = 0; i < merged.Count; i++)
            {
                if (!removedIndexes.Contains(merged[i]))
                {
                    ind = merged[i];
                }
            }

            int res = ind;

            for (int i = 0; i < removedIndexes.Count; i++)
            {
                if (ind > removedIndexes[i])
                {
                    res--;
                }
            }

            return(res);
        }
Esempio n. 5
0
        /// <summary>
        /// Inserts new edges on a face starting from the center of each edge to a new vertex in the center of the face.
        ///
        /// This is the equivalent of the [Connect Edges](../manual/Edge_Connect.html) action.
        /// </summary>
        /// <param name="mesh">Target mesh.</param>
        /// <param name="faces">The faces to affect.</param>
        /// <returns>The faces created as a result of inserting new edges.</returns>
        public static Face[] Connect(this ProBuilderMesh mesh, IEnumerable <Face> faces)
        {
            var            split = MeshValidation.EnsureFacesAreComposedOfContiguousTriangles(mesh, faces);
            HashSet <Face> mask  = new HashSet <Face>(faces);

            if (split.Count > 0)
            {
                foreach (var face in split)
                {
                    mask.Add(face);
                }
            }
            IEnumerable <Edge> edges = mask.SelectMany(x => x.edgesInternal);

            Edge[] empty;
            Face[] res;
            Connect(mesh, edges, out res, out empty, true, false, mask);
            return(res);
        }
        /// <summary>
        /// Merge a collection of <see cref="ProBuilderMesh"/> objects to as few meshes as possible. It will re-use the meshTarget object as the first
        /// destination for the first <see cref="ProBuilderMesh.maxVertexCount"/> -1 vertices. If the sum of vertices is above <see cref="ProBuilderMesh.maxVertexCount"/> - 1
        /// it will generate new meshes unless there is a single mesh left in which case it will append it to the return list.
        /// </summary>
        /// <param name="meshes">A collection of meshes to be merged. Note: it is expected that meshes includes meshTarget.</param>
        /// <param name="meshTarget">A mesh which will be used as the starting point for merging and which will be kept as reference/target.</param>
        /// <returns>
        /// A list of merged meshes. In most cases this will be a single mesh corresponding to meshTarget. However it can be multiple in cases
        /// where the resulting vertex count exceeds the maximum allowable value.
        /// </returns>
        public static List <ProBuilderMesh> Combine(IEnumerable <ProBuilderMesh> meshes, ProBuilderMesh meshTarget)
        {
            if (meshes == null)
            {
                throw new ArgumentNullException("meshes");
            }

            if (meshTarget == null)
            {
                throw new ArgumentNullException("meshTarget");
            }

            if (!meshes.Any() || meshes.Count() < 2)
            {
                return(null);
            }

            if (!meshes.Contains(meshTarget))
            {
                return(null);
            }

            var vertices        = new List <Vertex>(meshTarget.GetVertices());
            var faces           = new List <Face>(meshTarget.facesInternal);
            var sharedVertices  = new List <SharedVertex>(meshTarget.sharedVertices);
            var sharedTextures  = new List <SharedVertex>(meshTarget.sharedTextures);
            int offset          = meshTarget.vertexCount;
            var materialMap     = new List <Material>(meshTarget.renderer.sharedMaterials);
            var targetTransform = meshTarget.transform;

            var firstMeshContributors     = new List <ProBuilderMesh>();
            var remainderMeshContributors = new List <ProBuilderMesh>();

            var currentMeshVertexCount = offset;

            foreach (var mesh in meshes)
            {
                if (mesh != meshTarget)
                {
                    if (currentMeshVertexCount + mesh.vertexCount < ProBuilderMesh.maxVertexCount)
                    {
                        currentMeshVertexCount += mesh.vertexCount;
                        firstMeshContributors.Add(mesh);
                    }
                    else
                    {
                        remainderMeshContributors.Add(mesh);
                    }
                }
            }

            var autoUvFaces = new List <Face>();

            AccumulateMeshesInfo(
                firstMeshContributors,
                offset,
                ref vertices,
                ref faces,
                ref autoUvFaces,
                ref sharedVertices,
                ref sharedTextures,
                ref materialMap,
                targetTransform
                );

            meshTarget.SetVertices(vertices);
            meshTarget.faces          = faces;
            meshTarget.sharedVertices = sharedVertices;
            meshTarget.sharedTextures = sharedTextures != null?sharedTextures.ToArray() : null;

            meshTarget.renderer.sharedMaterials = materialMap.ToArray();
            meshTarget.ToMesh();
            meshTarget.Refresh();
            UvUnwrapping.SetAutoAndAlignUnwrapParamsToUVs(meshTarget, autoUvFaces);

            MeshValidation.EnsureMeshIsValid(meshTarget, out int removedVertices);

            var returnedMesh = new List <ProBuilderMesh>()
            {
                meshTarget
            };

            if (remainderMeshContributors.Count > 1)
            {
                var newMeshes = CombineToNewMeshes(remainderMeshContributors);
                foreach (var mesh in newMeshes)
                {
                    MeshValidation.EnsureMeshIsValid(mesh, out removedVertices);
                    returnedMesh.Add(mesh);
                }
            }
            else if (remainderMeshContributors.Count == 1)
            {
                returnedMesh.Add(remainderMeshContributors[0]);
            }

            return(returnedMesh);
        }