Compresses and decompresses vertex data.
예제 #1
0
        private void CompressVertices()
        {
            var compressionInfo = BuildCompressionInfo();
            var compressor      = new VertexCompressor(compressionInfo);

            // TODO: Refactor how vertices work, this is just ugly

            foreach (var mesh in Meshes)
            {
                if (mesh.RigidVertices != null)
                {
                    foreach (var v in mesh.RigidVertices)
                    {
                        v.Position = compressor.CompressPosition(v.Position);
                        v.Texcoord = compressor.CompressUv(v.Texcoord);
                    }
                }
                else if (mesh.SkinnedVertices != null)
                {
                    foreach (var v in mesh.SkinnedVertices)
                    {
                        v.Position = compressor.CompressPosition(v.Position);
                        v.Texcoord = compressor.CompressUv(v.Texcoord);
                    }
                }
            }
        }
예제 #2
0
 /// <summary>
 /// Decompresses vertex data in-place.
 /// </summary>
 /// <param name="vertices">The vertices to decompress in-place.</param>
 /// <param name="compressor">The compressor to use.</param>
 private static void DecompressVertices(IEnumerable<ObjVertex> vertices, VertexCompressor compressor)
 {
     foreach (var vertex in vertices)
     {
         vertex.Position = compressor.DecompressPosition(vertex.Position);
         vertex.TexCoords = compressor.DecompressUv(vertex.TexCoords);
     }
 }
예제 #3
0
 /// <summary>
 /// Decompresses vertex data in-place.
 /// </summary>
 /// <param name="vertices">The vertices to decompress in-place.</param>
 /// <param name="compressor">The compressor to use.</param>
 private static void DecompressVertices(IEnumerable <ObjVertex> vertices, VertexCompressor compressor)
 {
     foreach (var vertex in vertices)
     {
         vertex.Position  = compressor.DecompressPosition(vertex.Position);
         vertex.TexCoords = compressor.DecompressUv(vertex.TexCoords);
     }
 }
예제 #4
0
        /// <summary>
        /// Decompresses vertex data in-place.
        /// </summary>
        /// <param name="vertices">The vertices to decompress in-place.</param>
        /// <param name="compressor">The compressor to use.</param>
        private static void DecompressVertices(IEnumerable <GenericVertex> vertices, VertexCompressor compressor)
        {
            if (compressor == null)
            {
                return;
            }

            foreach (var vertex in vertices)
            {
                vertex.Position  = ToVector3D(compressor.DecompressPosition(new RealQuaternion(vertex.Position.X, vertex.Position.Y, vertex.Position.Z, 1)));
                vertex.TexCoords = ToVector3D(compressor.DecompressUv(new RealVector2d(vertex.TexCoords.X, vertex.TexCoords.Y)));
            }
        }
예제 #5
0
        /// <summary>
        /// Writes mesh data to the .obj.
        /// </summary>
        /// <param name="reader">The mesh reader to use.</param>
        /// <param name="compressor">The vertex compressor to use.</param>
        /// <param name="resourceStream">A stream open on the resource data.</param>
        public void ExtractMesh(MeshReader reader, VertexCompressor compressor, Stream resourceStream)
        {
            // Read the vertex buffer and decompress each vertex
            var vertices = ReadVertices(reader, resourceStream);
            DecompressVertices(vertices, compressor);

            // Write out the vertices
            WriteVertices(vertices);

            // Read and write out the triangles for each part
            foreach (var part in reader.Mesh.Parts)
            {
                var indexes = ReadIndexes(reader, part, resourceStream);
                WriteTriangles(indexes);
            }
            _baseIndex += (uint)vertices.Count;
        }
예제 #6
0
        /// <summary>
        /// Writes mesh data to the .obj.
        /// </summary>
        /// <param name="reader">The mesh reader to use.</param>
        /// <param name="compressor">The vertex compressor to use.</param>
        /// <param name="resourceStream">A stream open on the resource data.</param>
        public void ExtractMesh(MeshReader reader, VertexCompressor compressor, Stream resourceStream)
        {
            // Read the vertex buffer and decompress each vertex
            var vertices = ReadVertices(reader, resourceStream);

            DecompressVertices(vertices, compressor);

            // Write out the vertices
            WriteVertices(vertices);

            // Read and write out the triangles for each part
            foreach (var part in reader.Mesh.Parts)
            {
                var indexes = ReadIndexes(reader, part, resourceStream);
                WriteTriangles(indexes);
            }
            _baseIndex += (uint)vertices.Count;
        }
예제 #7
0
        private Assimp.Mesh ExtractMeshPartGeometry(int meshIndex, int partIndex)
        {
            // create new assimp mesh

            Assimp.Mesh mesh = new Assimp.Mesh();

            // Add support for multiple UV layers
            var textureCoordinateIndex = 0;

            mesh.UVComponentCount[textureCoordinateIndex] = 2;

            // prepare vertex extraction
            var meshReader       = new MeshReader(CacheContext.Version, RenderModel.Geometry.Meshes[meshIndex], RenderModelResourceDefinition);
            var vertexCompressor = new VertexCompressor(RenderModel.Geometry.Compression[0]);

            var geometryMesh = RenderModel.Geometry.Meshes[meshIndex];
            var geometryPart = geometryMesh.Parts[partIndex];

            mesh.MaterialIndex = geometryPart.MaterialIndex;

            // optimize this part to not load and decompress all mesh vertices everytime
            var vertices = ReadVertices(meshReader, RenderModelResourceStream);

            DecompressVertices(vertices, vertexCompressor);
            // get offset in the list of all vertices for the mesh
            var vertexOffset = GetPartVertexOffset(meshIndex, partIndex);

            //vertices = vertices.GetRange(vertexOffset, geometryPart.VertexCount);

            var indices = ReadIndices(meshReader, geometryPart, RenderModelResourceStream);

            var int_indices = indices.Select(b => (int)b).ToArray();

            var indexCount = indices.Length;

            if (indexCount == 0)
            {
                Console.WriteLine($"Failed to extract mesh, no indices.");
                return(null);
            }

            // set index list, maybe require adjustment for vertex buffer offset

            mesh.SetIndices(int_indices, 3);

            // build skeleton for each mesh (meh)

            // create a list of all the mesh bones available in the scene
            foreach (var node in RenderModel.Nodes)
            {
                Bone bone = new Bone();
                bone.Name         = CacheContext.GetString(node.Name);
                bone.OffsetMatrix = new Matrix4x4();
                mesh.Bones.Add(bone);
            }

            for (int i = vertexOffset; i < vertexOffset + geometryPart.VertexCount; i++)
            {
                var vertex = vertices[i];
                mesh.Vertices.Add(vertex.Position);

                if (vertex.Normal != null)
                {
                    mesh.Normals.Add(vertex.Normal);
                }

                if (vertex.TexCoords != null)
                {
                    mesh.TextureCoordinateChannels[textureCoordinateIndex].Add(vertex.TexCoords);
                }

                if (vertex.Tangents != null)
                {
                    mesh.Tangents.Add(vertex.Tangents);
                }

                if (vertex.Binormals != null)
                {
                    mesh.BiTangents.Add(vertex.Binormals);
                }

                if (vertex.Indices != null)
                {
                    for (int j = 0; j < vertex.Indices.Length; j++)
                    {
                        var       index            = vertex.Indices[j];
                        var       bone             = mesh.Bones[index];
                        Matrix4x4 inverseTransform = new Matrix4x4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);


                        var currentNode = BoneNodes[index];
                        while (currentNode != null)
                        {
                            Matrix4x4 inverse = (currentNode.Transform.DeepClone());
                            inverse.Inverse();
                            inverseTransform = inverse * inverseTransform;
                            currentNode      = currentNode.Parent;
                        }
                        bone.OffsetMatrix = inverseTransform;
                        bone.VertexWeights.Add(new VertexWeight(i - vertexOffset, vertex.Weights[j]));
                    }
                }

                // Add skinned mesh support and more
            }

            // create faces
            mesh.Faces.Clear();

            GenerateFaces(int_indices, vertexOffset, mesh.Faces);

            return(mesh);
        }
예제 #8
0
        /// <summary>
        /// Writes mesh data to the .obj.
        /// </summary>
        /// <param name="reader">The mesh reader to use.</param>
        /// <param name="compressor">The vertex compressor to use.</param>
        /// <param name="resourceStream">A stream open on the resource data.</param>
        /// <param name="name">The name of the mesh.</param>
        public void ExtractMesh(MeshReader reader, VertexCompressor compressor, Stream resourceStream, string name = null)
        {
            var vertices = ReadVertices(reader, resourceStream);

            DecompressVertices(vertices, compressor);

            var indicesList = new List <ushort[]>();
            var indexCount  = 0;

            for (var i = 0; i < (reader?.Mesh?.Parts?.Count ?? -1); i++)
            {
                var part    = reader.Mesh.Parts[i];
                var indices = ReadIndices(reader, part, resourceStream);

                indicesList.Add(indices);

                if (part.IndexCountOld > 0)
                {
                    indexCount += indices.Length;
                }
            }

            if (indexCount == 0)
            {
                return;
            }

            foreach (var vertex in vertices)
            {
                _writer.WriteLine("v {0} {1} {2}", vertex.Position.I, vertex.Position.J, vertex.Position.K);
            }

            foreach (var vertex in vertices)
            {
                _writer.WriteLine("vn {0} {1} {2}", vertex.Normal.I, vertex.Normal.J, vertex.Normal.K);
            }

            foreach (var vertex in vertices)
            {
                _writer.WriteLine("vt {0} {1}", vertex.TexCoords.I, 1 - vertex.TexCoords.J);
            }

            var partIndex = 0;

            foreach (var indices in indicesList)
            {
                var triangles = GenerateTriangles(indices);

                if (triangles.Count() != 0)
                {
                    _writer.WriteLine($"g {name}_part_{partIndex++}");
                }

                foreach (var triangle in triangles)
                {
                    _writer.WriteLine(triangle);
                }
            }

            _baseIndex += (uint)vertices.Count;
        }
예제 #9
0
        public override bool Execute(List<string> args)
        {
            if (args.Count != 3)
                return false;

            var variantName = args[0];
            var fileType = args[1];
            var fileName = args[2];

            if (fileType != "obj" && fileType != "amf")
                return false;

            // Find the variant to extract
            if (Definition.RenderModel == null)
            {
                Console.WriteLine("The model does not have a render model associated with it.");
                return true;
            }

            var variant = Definition.Variants.FirstOrDefault(v => (Info.StringIDs.GetString(v.Name) ?? v.Name.ToString()) == variantName);
            if (variant == null && Definition.Variants.Count > 0)
            {
                Console.WriteLine("Unable to find variant \"{0}\"", variantName);
                Console.WriteLine("Use \"listvariants\" to list available variants.");
                return true;
            }

            if (fileType == "amf")
                return ExtractAMF(variant, fileName);

            // Load resource caches
            Console.WriteLine("Loading resource caches...");
            var resourceManager = new ResourceDataManager();
            try
            {
                resourceManager.LoadCachesFromDirectory(Info.CacheFile.DirectoryName);
            }
            catch
            {
                Console.WriteLine("Unable to load the resource .dat files.");
                Console.WriteLine("Make sure that they all exist and are valid.");
                return true;
            }

            // Deserialize the render model tag
            Console.WriteLine("Reading model data...");
            RenderModel renderModel;
            using (var cacheStream = Info.CacheFile.OpenRead())
            {
                var renderModelContext = new TagSerializationContext(cacheStream, Info.Cache, Info.StringIDs, Definition.RenderModel);
                renderModel = Info.Deserializer.Deserialize<RenderModel>(renderModelContext);
            }

            if (renderModel.Geometry.Resource == null)
            {
                Console.WriteLine("Render model does not have a resource associated with it");
                return true;
            }

            // Deserialize the resource definition
            var resourceContext = new ResourceSerializationContext(renderModel.Geometry.Resource);
            var definition = Info.Deserializer.Deserialize<RenderGeometryResourceDefinition>(resourceContext);

            using (var resourceStream = new MemoryStream())
            {
                // Extract the resource data
                resourceManager.Extract(renderModel.Geometry.Resource, resourceStream);

                Directory.CreateDirectory(Path.GetDirectoryName(fileName));

                using (var objFile = new StreamWriter(File.Open(fileName, FileMode.Create, FileAccess.Write)))
                {
                    var objExtractor = new ObjExtractor(objFile);
                    var vertexCompressor = new VertexCompressor(renderModel.Geometry.Compression[0]); // Create a (de)compressor from the first compression block

                    if (variant != null)
                    {
                        // Extract each region in the variant
                        foreach (var region in variant.Regions)
                        {
                            // Get the corresonding region in the render model tag
                            if (region.RenderModelRegionIndex >= renderModel.Regions.Count)
                                continue;

                            var renderModelRegion = renderModel.Regions[region.RenderModelRegionIndex];

                            // Get the corresponding permutation in the render model tag
                            // (Just extract the first permutation for now)
                            if (region.Permutations.Count == 0)
                                continue;

                            var permutation = region.Permutations[0];

                            if (permutation.RenderModelPermutationIndex < 0 ||
                                permutation.RenderModelPermutationIndex >= renderModelRegion.Permutations.Count)
                                continue;

                            var renderModelPermutation = renderModelRegion.Permutations[permutation.RenderModelPermutationIndex];

                            // Extract each mesh in the permutation
                            var meshIndex = renderModelPermutation.MeshIndex;
                            var meshCount = renderModelPermutation.MeshCount;
                            var regionName = Info.StringIDs.GetString(region.Name) ?? region.Name.ToString();
                            var permutationName = Info.StringIDs.GetString(permutation.Name) ?? permutation.Name.ToString();

                            Console.WriteLine("Extracting {0} mesh(es) for {1}:{2}...", meshCount, regionName, permutationName);

                            for (var i = 0; i < meshCount; i++)
                            {
                                // Create a MeshReader for the mesh and pass it to the obj extractor
                                var meshReader = new MeshReader(Info.Version, renderModel.Geometry.Meshes[meshIndex + i], definition);
                                objExtractor.ExtractMesh(meshReader, vertexCompressor, resourceStream);
                            }
                        }
                    }
                    else
                    {
                        // No variant - just extract every mesh
                        Console.WriteLine("Extracting {0} mesh(es)...", renderModel.Geometry.Meshes.Count);

                        foreach (var mesh in renderModel.Geometry.Meshes)
                        {
                            // Create a MeshReader for the mesh and pass it to the obj extractor
                            var meshReader = new MeshReader(Info.Version, mesh, definition);
                            objExtractor.ExtractMesh(meshReader, vertexCompressor, resourceStream);
                        }
                    }

                    objExtractor.Finish();
                }
            }
            Console.WriteLine("Done!");
            return true;
        }