Example #1
0
        /// <summary>
        /// Splits the mesh into submeshes that use <paramref name="maxVertexCount"/> or less vertices.
        /// </summary>
        /// <param name="mesh"></param>
        /// <param name="maxVertexCount"></param>
        /// <returns></returns>
        public static List <Assimp.Mesh> SplitMeshByVertexCount(Assimp.Mesh mesh, int maxVertexCount)
        {
            if (mesh.VertexCount <= maxVertexCount)
            {
                return new List <Assimp.Mesh> {
                           mesh
                }
            }
            ;

            var vertexWeights  = mesh.HasBones ? mesh.GetVertexWeights() : null;
            var remainingFaces = mesh.Faces.ToList();
            var subMeshes      = new List <Assimp.Mesh>();

            while (remainingFaces.Count > 0)
            {
                // Build submesh
                var subMesh = new Assimp.Mesh()
                {
                    MaterialIndex = mesh.MaterialIndex,
                    //MorphMethod = mesh.MorphMethod,
                    Name          = mesh.Name + $"_submesh{subMeshes.Count}",
                    PrimitiveType = mesh.PrimitiveType,
                };

                var processedFaces = new List <Face>();
                var vertexCache    = new List <Vertex>();

                // Get faces that fit inside the new mesh
                foreach (var face in remainingFaces)
                {
                    var newVertices = new List <Vertex>();
                    var newFace     = new Face();
                    foreach (var i in face.Indices)
                    {
                        var cacheIndex = FindVertexCacheIndex(mesh, i, vertexWeights, vertexCache, out var vertex);
                        if (cacheIndex == -1)
                        {
                            // This vertex is new
                            cacheIndex = vertexCache.Count + newVertices.Count;
                            newVertices.Add(vertex);
                        }

                        newFace.Indices.Add(cacheIndex);
                    }

                    if (vertexCache.Count + newVertices.Count > maxVertexCount)
                    {
                        // Doesn't fit
                        continue;
                    }

                    // It does fit \(^o^)/
                    subMesh.Faces.Add(newFace);
                    processedFaces.Add(face);
                    foreach (var vertex in newVertices)
                    {
                        vertexCache.Add(vertex);
                    }

                    Debug.Assert(vertexCache.Count <= maxVertexCount);

                    if (vertexCache.Count == maxVertexCount)
                    {
                        // We're done for sure
                        break;
                    }
                }

                // Remove the faces we processed from the remaining list
                foreach (var face in processedFaces)
                {
                    remainingFaces.Remove(face);
                }

                PopulateSubMeshVertexData(mesh, subMesh, vertexCache);

#if DEBUG
                CheckIfAllVerticesHaveWeights(subMesh);
#endif

                subMeshes.Add(subMesh);
            }

            return(subMeshes);
        }
Example #2
0
        /// <summary>
        /// Splits the mesh into submeshes that use <paramref name="maxBoneCount"/> or less bones.
        /// </summary>
        /// <param name="scene"></param>
        /// <param name="mesh"></param>
        /// <param name="maxBoneCount"></param>
        /// <returns></returns>
        public static List <Assimp.Mesh> SplitMeshByBoneCount(Assimp.Mesh mesh, int maxBoneCount)
        {
            if (mesh.BoneCount <= maxBoneCount)
            {
                return new List <Assimp.Mesh> {
                           mesh
                }
            }
            ;

            var vertexWeights  = mesh.GetVertexWeights();
            var subMeshes      = new List <Assimp.Mesh>();
            var remainingFaces = mesh.Faces.ToList();

            while (remainingFaces.Count > 0)
            {
                var usedBones = new HashSet <Assimp.Bone>();

                var faces = new List <Face>();

                // Get faces that fit inside the new mesh
                foreach (var face in remainingFaces)
                {
                    var faceUsedBones           = face.Indices.SelectMany(y => vertexWeights[y].Select(z => z.Item1)).ToList();
                    var faceUniqueUsedBoneCount = faceUsedBones.Count(x => !usedBones.Contains(x));
                    if ((usedBones.Count + faceUniqueUsedBoneCount) > maxBoneCount)
                    {
                        // Skip
                        continue;
                    }

                    // It does fit \(^o^)/
                    faces.Add(face);
                    foreach (var node in faceUsedBones)
                    {
                        usedBones.Add(node);
                    }

                    Debug.Assert(usedBones.Count <= maxBoneCount);
                }

                if (faces.Count == 0)
                {
                    if (remainingFaces.All(x => x.Indices.SelectMany(y => vertexWeights[y].Select(z => z.Item1)).Count() > maxBoneCount))
                    {
                        // Need to reduce weights per face
                        Debug.Assert(false);   // would need averaging..
                    }
                }

                // Remove the faces we claimed from the pool
                foreach (var face in faces)
                {
                    remainingFaces.Remove(face);
                }

                // Build submesh
                var subMesh = new Assimp.Mesh()
                {
                    MaterialIndex = mesh.MaterialIndex,
                    //MorphMethod = mesh.MorphMethod,
                    Name          = mesh.Name + $"_submesh{subMeshes.Count}",
                    PrimitiveType = mesh.PrimitiveType,
                };
                var vertexCache = new List <Vertex>();
                foreach (var face in faces)
                {
                    var newFace = new Face();

                    foreach (var index in face.Indices)
                    {
                        var cacheIndex = FindVertexCacheIndex(mesh, index, vertexWeights, vertexCache, out var vertex);
                        if (cacheIndex == -1)
                        {
                            // This vertex is new
#if DEBUG
                            for (int i = 0; i < vertex.Weights.Count; i++)
                            {
                                Debug.Assert(usedBones.Contains(vertex.Weights[i].Item1));
                            }
#endif
                            cacheIndex = vertexCache.Count;
                            vertexCache.Add(vertex);
                        }

                        newFace.Indices.Add(cacheIndex);
                    }

                    subMesh.Faces.Add(newFace);
                }

                PopulateSubMeshVertexData(mesh, subMesh, vertexCache);

#if DEBUG
                CheckIfAllVerticesHaveWeights(subMesh);
#endif

                subMeshes.Add(subMesh);
            }

            return(subMeshes);
        }