Exemple #1
0
        static void Main(string[] args)
        {
            Printer.WriteLine("INIT", "---------------------------");
            Printer.WriteLine("INIT", "ModelMerger by Scobalula");
            Printer.WriteLine("INIT", "Merges SEModels into 1");
            Printer.WriteLine("INIT", string.Format("Version {0}", Assembly.GetExecutingAssembly().GetName().Version));
            Printer.WriteLine("INIT", "---------------------------");

            try
            {
                var models = LoadModels(args);

                if (models.Count == 0)
                {
                    Printer.WriteLine("USAGE", "Simply drag and drop supported model files onto the exe");
                }
                else
                {
                    var rootModel = GetRootModel(models);

                    if (rootModel == null)
                    {
                        throw new Exception("Failed to obtain root model");
                    }

                    Printer.WriteLine("MERGER", string.Format("Using {0} as root model", rootModel.Name));

                    var merged = new List <Model>(models.Count)
                    {
                        rootModel
                    };

                    var outputFolder = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Merged Models");

                    // Keep looping until we've resolved all models
                    // We do this because some models connect to other
                    // so we need to wait until we've processed that model
                    while (merged.Count < models.Count)
                    {
                        foreach (var model in models)
                        {
                            // Check if we've processed, also considers root as it's added to merged
                            if (merged.Contains(model))
                            {
                                continue;
                            }
                            // If we have a model that doesn't exist, and can be connected, we must wait
                            // for it's parent model to be connected
                            if (!rootModel.HasBone(model.Bones[0].Name) && CanBeConnected(model, models))
                            {
                                continue;
                            }
                            // Add to the group
                            merged.Add(model);

                            Printer.WriteLine("MERGER", string.Format("Merging {0}", model.Name));

                            foreach (var bone in model.Bones)
                            {
                                if (!rootModel.HasBone(bone.Name))
                                {
                                    var nBone = new Model.Bone(bone.Name, bone.ParentIndex, bone.LocalPosition, bone.LocalRotation);

                                    if (bone.ParentIndex > -1)
                                    {
                                        nBone.ParentIndex = rootModel.Bones.FindIndex(x => x.Name == model.Bones[nBone.ParentIndex].Name);
                                    }

                                    rootModel.Bones.Add(nBone);
                                }
                            }

                            // Compute global positions (we need them for offsetting)
                            rootModel.GenerateGlobalBoneData();
                            model.GenerateGlobalBoneData();

                            // Get root and the new root, to compute offsets
                            var root  = model.Bones[0];
                            var nRoot = rootModel.Bones.Find(x => x.Name == root.Name);

                            // TODO: compute this for each bone and utilize weights
                            // but as an option, as it may cause severe deformations
                            // if bones have moved
                            var translation = nRoot.GlobalPosition - root.GlobalPosition;
                            var rotation    = (nRoot.GlobalRotation * root.GlobalRotation.Inverse()).ToMatrix();

                            foreach (var material in model.Materials)
                            {
                                if (rootModel.Materials.Find(x => x.Name == material.Name) == null)
                                {
                                    rootModel.Materials.Add(material);
                                }
                            }

                            foreach (var mesh in model.Meshes)
                            {
                                var nMesh = new Model.Mesh(mesh.Vertices.Count, 0)
                                {
                                    Faces = new List <Model.Face>(mesh.Faces)
                                };

                                foreach (var material in mesh.MaterialIndices)
                                {
                                    nMesh.MaterialIndices.Add(rootModel.Materials.FindIndex(x => x.Name == model.Materials[material].Name));
                                }

                                foreach (var vertex in mesh.Vertices)
                                {
                                    var nVertex = new Model.Vertex(vertex.Position, vertex.Normal, vertex.Tangent)
                                    {
                                        Color   = vertex.Color,
                                        Weights = new List <Model.Vertex.Weight>(vertex.Weights.Count),
                                        UVs     = new List <Vector2>(vertex.UVs)
                                    };

                                    foreach (var weight in vertex.Weights)
                                    {
                                        nVertex.Weights.Add(new Model.Vertex.Weight()
                                        {
                                            Influence = weight.Influence,
                                            BoneIndex = rootModel.Bones.FindIndex(x => x.Name == model.Bones[weight.BoneIndex].Name),
                                        });
                                    }

                                    // Now move it to the new position
                                    nVertex.Position  = rotation.TransformVector(vertex.Position);
                                    nVertex.Normal    = rotation.TransformVector(vertex.Normal);
                                    nVertex.Position += translation;

                                    nMesh.Vertices.Add(nVertex);
                                }

                                rootModel.Meshes.Add(nMesh);
                            }

                            Printer.WriteLine("MERGER", string.Format("Merged {0}", model.Name));
                        }
                    }

                    Printer.WriteLine("MERGER", string.Format("Saving {0}", rootModel.Name));
                    Directory.CreateDirectory(outputFolder);
                    rootModel.Save(Path.Combine(outputFolder, rootModel.Name + ".semodel"));
                    Printer.WriteLine("MERGER", string.Format("Saved {0}", rootModel.Name));
                }
            }
            catch (Exception e)
            {
                Printer.WriteLine("ERROR", "An unhandled exception has occured:", ConsoleColor.DarkRed);
                Console.WriteLine(e);
            }


            Printer.WriteLine("DONE", "Execution complete, press Enter to exit");
            Console.ReadLine();
        }
Exemple #2
0
        private static Model LoadSEModel(string filePath)
        {
            var model = new Model(Path.GetFileNameWithoutExtension(filePath));
            var input = SEModel.Read(filePath);

            Printer.WriteLine("LOADER", string.Format("Loading {0}", model.Name));

            foreach (var bone in input.Bones)
            {
                model.Bones.Add(new Model.Bone(
                                    bone.BoneName,
                                    bone.BoneParent,
                                    new Vector3(
                                        (float)bone.LocalPosition.X,
                                        (float)bone.LocalPosition.Y,
                                        (float)bone.LocalPosition.Z),
                                    new Quaternion(
                                        (float)bone.LocalRotation.X,
                                        (float)bone.LocalRotation.Y,
                                        (float)bone.LocalRotation.Z,
                                        (float)bone.LocalRotation.W),
                                    new Vector3(
                                        (float)bone.GlobalPosition.X,
                                        (float)bone.GlobalPosition.Y,
                                        (float)bone.GlobalPosition.Z),
                                    new Quaternion(
                                        (float)bone.GlobalRotation.X,
                                        (float)bone.GlobalRotation.Y,
                                        (float)bone.GlobalRotation.Z,
                                        (float)bone.GlobalRotation.W)));
            }

            foreach (var semesh in input.Meshes)
            {
                var mesh = new Model.Mesh((int)semesh.VertexCount, (int)semesh.FaceCount);

                foreach (var mtl in semesh.MaterialReferenceIndicies)
                {
                    mesh.MaterialIndices.Add(mtl);
                }

                foreach (var severtex in semesh.Verticies)
                {
                    var vertex = new Model.Vertex(
                        new Vector3((float)severtex.Position.X, (float)severtex.Position.Y, (float)severtex.Position.Z),
                        new Vector3((float)severtex.VertexNormal.X, (float)severtex.VertexNormal.Y, (float)severtex.VertexNormal.Z));

                    foreach (var uv in severtex.UVSets)
                    {
                        vertex.UVs.Add(new Vector2((float)uv.X, (float)uv.Y));
                    }

                    foreach (var weight in severtex.Weights)
                    {
                        vertex.Weights.Add(new Model.Vertex.Weight()
                        {
                            BoneIndex = (int)weight.BoneIndex,
                            Influence = weight.BoneWeight
                        });
                    }

                    vertex.Color = new Vector4(
                        severtex.VertexColor.R / 255.0f,
                        severtex.VertexColor.G / 255.0f,
                        severtex.VertexColor.B / 255.0f,
                        severtex.VertexColor.A / 255.0f);

                    mesh.Vertices.Add(vertex);
                }

                foreach (var face in semesh.Faces)
                {
                    mesh.Faces.Add(new Model.Face((int)face.FaceIndex1, (int)face.FaceIndex2, (int)face.FaceIndex3));
                }

                model.Meshes.Add(mesh);
            }

            foreach (var material in input.Materials)
            {
                model.Materials.Add(new Model.Material(material.Name));
            }

            Printer.WriteLine("LOADER", string.Format("Loaded {0}", model.Name));

            return(model);
        }
Exemple #3
0
        /// <summary>
        /// Loads Meshes from a Resident Evil 2 Mesh
        /// </summary>
        private static List <List <Model> > ConvertRE2(BinaryReader reader)
        {
            var results = new List <List <Model> >(3);

            var header         = reader.ReadStruct <MeshHeaderRE2>();
            var boneDataHeader = new BoneDataHeaderRE2();
            var geometryHeader = new GeometryHeaderRE2();
            var vertexBlocks   = new Dictionary <short, long>();

            short[] skinnedBones = null;

            if (header.BoneDataHeaderPointer > 0)
            {
                boneDataHeader = reader.ReadStruct <BoneDataHeaderRE2>(header.BoneDataHeaderPointer);
                skinnedBones   = reader.ReadArray <short>(header.BoneDataHeaderPointer + 48, boneDataHeader.SkinnedBoneCount);
            }

            if (header.GeometryPointer > 0)
            {
                geometryHeader = reader.ReadStruct <GeometryHeaderRE2>(header.GeometryPointer);
                var blocks = reader.ReadArray <VertexBlockRE2>(geometryHeader.VertexBlocksOffset, geometryHeader.VertexBlockCount);

                foreach (var block in blocks)
                {
                    vertexBlocks[block.ID] = geometryHeader.VertexDataOffset + block.Offset;
                }
            }

            // Parse all strings for bones, materials, etc. into lists to make it easier to pass around, etc.
            var strings = new List <string>(header.StringCount);

            foreach (var offset in reader.ReadArray <long>(header.StringTablePointer, header.StringCount))
            {
                strings.Add(reader.ReadNullTerminatedString(offset));
            }

            var boneNames = new List <string>(boneDataHeader.BoneCount);

            foreach (var boneNameIndex in reader.ReadArray <ushort>(header.BoneNamesPointer, boneDataHeader.BoneCount))
            {
                boneNames.Add(strings[boneNameIndex]);
            }

            var bones = new List <Model.Bone>(boneDataHeader.BoneCount);

            if (header.BoneDataHeaderPointer > 0)
            {
                var boneDatas    = reader.ReadArray <BoneDataRE7>(boneDataHeader.BoneTablePointer, boneDataHeader.BoneCount);
                var boneMatrices = reader.ReadArray <Matrix4x4>(boneDataHeader.MatricesPointer, boneDataHeader.BoneCount);

                for (ushort i = 0; i < boneDataHeader.BoneCount; i++)
                {
                    var bone = new Model.Bone(boneNames[i], boneDatas[i].ParentIndex, new Vector3(
                                                  boneMatrices[i].W.X,
                                                  boneMatrices[i].W.Y,
                                                  boneMatrices[i].W.Z), boneMatrices[i].ToQuaternion());

                    bones.Add(bone);
                }
            }

            bool firstMdlProcessed = false;

            for (int mdl = 0; mdl < 3; mdl++)
            {
                if (header.ModelPointers[mdl] == 0)
                {
                    continue;
                }

                if (firstMdlProcessed)
                {
                    break;
                }

                var lods = new List <Model>();

                var modelHeader = reader.ReadStruct <ModelHeaderRE7>(header.ModelPointers[mdl]);

                reader.BaseStream.Position = header.ModelPointers[mdl] + (firstMdlProcessed ? 16 : 64);
                var materialIndices = reader.ReadArray <short>(header.MaterialNamesPointer, modelHeader.MaterialCount);

                firstMdlProcessed = true;

                var lodPointers = reader.ReadArray <long>(reader.ReadInt64(), modelHeader.LODCount);

                foreach (var lodPointer in lodPointers)
                {
                    var model = new Model()
                    {
                        Bones = bones
                    };

                    var uniqueMaterials = new List <string>(modelHeader.MaterialCount);

                    var lodHeader = reader.ReadStruct <LODHeaderRE7>(lodPointer);

                    var meshPointers = reader.ReadArray <long>(lodHeader.MeshesPointer, lodHeader.MeshCount);

                    foreach (var meshPointer in meshPointers)
                    {
                        var mesh         = reader.ReadStruct <LODMeshRE7>(meshPointer);
                        var subMeshes    = reader.ReadArray <LODSubMeshRE7>(meshPointer + 16, mesh.SubMeshCount);
                        int verticesRead = 0;

                        for (int i = 0; i < subMeshes.Length; i++)
                        {
                            var materialName = strings[materialIndices[subMeshes[i].MaterialIndex]];

                            if (!uniqueMaterials.Contains(materialName))
                            {
                                uniqueMaterials.Add(materialName);
                            }

                            int subMeshVertexCount = 0;
                            int subMeshFaceCount   = subMeshes[i].FaceCount;

                            // Since the counts aren't stored in each, we can use this to determine the counts
                            if (i != subMeshes.Length - 1)
                            {
                                subMeshVertexCount = subMeshes[i + 1].VertexIndex - subMeshes[i].VertexIndex;
                            }
                            else
                            {
                                subMeshVertexCount = mesh.VertexCount - verticesRead;
                            }


                            verticesRead += subMeshVertexCount;


                            var subMesh = new Model.Mesh(subMeshVertexCount, subMeshFaceCount);

                            subMesh.MaterialIndices.Add(uniqueMaterials.IndexOf(materialName));

                            // Positions
                            if (vertexBlocks.TryGetValue(0, out var positionsOffset))
                            {
                                reader.BaseStream.Position = positionsOffset + (12 * subMeshes[i].VertexIndex);

                                for (int v = 0; v < subMeshVertexCount; v++)
                                {
                                    subMesh.Vertices.Add(new Model.Vertex(reader.ReadStruct <Vector3>()));
                                }
                            }
                            // Normals/Tangents
                            if (vertexBlocks.TryGetValue(1, out var normalsTangentsOffset))
                            {
                                reader.BaseStream.Position = normalsTangentsOffset + (8 * subMeshes[i].VertexIndex);

                                for (int v = 0; v < subMeshVertexCount; v++)
                                {
                                    subMesh.Vertices[v].Normal  = reader.ReadStruct <PackedVector3>().Unpack();
                                    subMesh.Vertices[v].Tangent = reader.ReadStruct <PackedVector3>().Unpack();
                                }
                            }
                            // UVs
                            if (vertexBlocks.TryGetValue(2, out var uvsOffset))
                            {
                                reader.BaseStream.Position = uvsOffset + (4 * subMeshes[i].VertexIndex);

                                for (int v = 0; v < subMeshVertexCount; v++)
                                {
                                    subMesh.Vertices[v].UVs.Add(new Vector2(reader.ReadStruct <Half>(), reader.ReadStruct <Half>()));
                                }
                            }
                            // Weights
                            if (vertexBlocks.TryGetValue(4, out var weightsOffset))
                            {
                                reader.BaseStream.Position = weightsOffset + (16 * subMeshes[i].VertexIndex);

                                for (int v = 0; v < subMeshVertexCount; v++)
                                {
                                    var localBoneIndices = reader.ReadBytes(8);
                                    var weights          = reader.ReadBytes(8);
                                    var weightSum        = 0.0f;

                                    for (int w = 0; w < 8 && weights[w] != 0; w++)
                                    {
                                        subMesh.Vertices[v].Weights.Add(new Model.Vertex.Weight()
                                        {
                                            BoneIndex = skinnedBones[localBoneIndices[w]],
                                            Influence = weights[w] / 255.0f
                                        });

                                        weightSum += subMesh.Vertices[v].Weights[w].Influence;
                                    }

                                    var multiplier = 1.0f / weightSum;

                                    foreach (var weight in subMesh.Vertices[v].Weights)
                                    {
                                        weight.Influence *= multiplier;
                                    }
                                }
                            }

                            switch (lodHeader.Flags)
                            {
                            case 0:
                                reader.BaseStream.Position = geometryHeader.FaceBufferOffset + (2 * subMeshes[i].FaceIndex);

                                for (int f = 0; f < subMeshes[i].FaceCount / 3; f++)
                                {
                                    var v1 = reader.ReadUInt16();
                                    var v2 = reader.ReadUInt16();
                                    var v3 = reader.ReadUInt16();

                                    if (v1 != v2 && v2 != v3 && v3 != v1)
                                    {
                                        subMesh.Faces.Add(new Model.Face(v1, v2, v3));
                                    }
                                }
                                break;

                            case 1:
                                reader.BaseStream.Position = geometryHeader.FaceBufferOffset + (4 * subMeshes[i].FaceIndex);

                                for (int f = 0; f < subMeshes[i].FaceCount / 3; f++)
                                {
                                    var v1 = reader.ReadInt32();
                                    var v2 = reader.ReadInt32();
                                    var v3 = reader.ReadInt32();

                                    if (v1 != v2 && v2 != v3 && v3 != v1)
                                    {
                                        subMesh.Faces.Add(new Model.Face(v1, v2, v3));
                                    }
                                }
                                break;
                            }

                            model.Meshes.Add(subMesh);
                        }
                    }


                    foreach (var materialName in uniqueMaterials)
                    {
                        model.Materials.Add(new Model.Material(materialName));
                    }

                    lods.Add(model);
                }

                results.Add(lods);
            }
            return(results);
        }