Example #1
0
        /// <summary>
        /// Exports the specified model as an obj file with a texture
        /// </summary>
        /// <param name="models">The models to combine and export</param>
        public void ExportModelsAsObj(List <VModel> models)
        {
            var objMeshes = new List <ObjMesh>();

            var animations = GetAllAnimations(models[0]);
            var animation  = animations.First(a => a.Name.Contains("idle"));

            foreach (var model in models)
            {
                var objMesh = new ObjMesh();

                // Load mesh
                var meshes = LoadModelMeshes(model);
                var mesh   = meshes[0].Mesh;
                LoadVMeshIntoMesh(objMesh, mesh);

                // Apply animation
                var animMatrices = animation.GetAnimationMatrices(0, model.GetSkeleton(0));
                if (objMesh.BlendWeights.Count == 0 && objMesh.BlendIndices.Count != 0)
                {
                    objMesh.BlendWeights = objMesh.BlendIndices.Select(idxs => new Vector4((float)0.25, (float)0.25, (float)0.25, (float)0.25)).ToList();
                }
                for (int i = 0; i < objMesh.VertexCount; i++)
                {
                    var     position      = objMesh.Positions[i];
                    var     resultVectors = new List <Vector3>();
                    float[] weights       = new float[]
                    {
                        objMesh.BlendWeights[i].X,
                        objMesh.BlendWeights[i].Y,
                        objMesh.BlendWeights[i].Z,
                        objMesh.BlendWeights[i].W,
                    };
                    for (int m = 0; m < 4; m++)
                    {
                        var matrixIndex = (int)objMesh.BlendIndices[i][m];
                        resultVectors.Add(Vector3.Multiply(Vector3.Transform(position, animMatrices[matrixIndex]), weights[m]));
                    }
                    objMesh.Positions[i] = resultVectors.Aggregate((v1, v2) => Vector3.Add(v1, v2));
                }
                // Add to list
                objMeshes.Add(objMesh);
            }

            // Merge all objMeshes into one
            // - merge textures and fix tex coords
            // - create one final merged texture
            // - append all vertex points, and fix indexes
            // - also make sure original v texcoords start in 0-1(wrapping dont work well with our new method)
            //
            var finalMesh = new ObjMesh();

            // Take the initial material as the base of the merged materials
            finalMesh.Material = objMeshes.FirstOrDefault().Material.Clone();
            var textureImages = objMeshes.Select(o => o.Material.TextureImage).ToList();

            finalMesh.Material.TextureImage  = ObjMaterial.StackImages(objMeshes.Select(o => o.Material.TextureImage).ToList());
            finalMesh.Material.NormalsImage  = ObjMaterial.StackImages(objMeshes.Select(o => o.Material.NormalsImage).ToList());
            finalMesh.Material.SpecularImage = ObjMaterial.StackImages(objMeshes.Select(o => o.Material.SpecularImage).ToList());

            float vCoord = 0;

            foreach (var objMesh in objMeshes)
            {
                var startIndex = finalMesh.VertexCount;
                finalMesh.Positions.AddRange(objMesh.Positions);
                finalMesh.Normals.AddRange(objMesh.Normals);

                float textureHeightModifier = (float)objMesh.Material.TextureImage.Height / finalMesh.Material.TextureImage.Height;
                finalMesh.TextureCoords.AddRange(objMesh.TextureCoords.Select(uv =>
                {
                    var v = uv.Y;
                    // Lock in to 0-1
                    while (v > 1)
                    {
                        v -= 1;
                    }
                    while (v < 0)
                    {
                        v += 1;
                    }
                    // Adjust for merged image
                    v = (v * textureHeightModifier) + vCoord;
                    return(new Vector2(uv.X, v));
                }));
                vCoord += textureHeightModifier;

                objMesh.Faces.ForEach(f => f.ForEach(v => v.IncreaseIndexing(startIndex)));
                finalMesh.Faces.AddRange(objMesh.Faces);
            }

            // Transform to be smaller and upright
            //finalMesh.Positions = finalMesh.Positions.Select(v => v = Vector3.Transform(v, TRANSFORMSOURCETOSTANDARD)).ToList();

            finalMesh.WriteToFiles("out");
        }
Example #2
0
        /// <summary>
        /// Loads the VMesh into our Objmesh
        /// </summary>
        /// <param name="objMesh">The objmesh to load into</param>
        /// <param name="mesh">The VMesh to load</param>
        private void LoadVMeshIntoMesh(ObjMesh objMesh, VMesh mesh)
        {
            var data = mesh.GetData();
            var vbib = mesh.VBIB;

            foreach (var sceneObject in data.GetArray("m_sceneObjects"))
            {
                foreach (var drawCall in sceneObject.GetArray("m_drawCalls"))
                {
                    var startingVertexCount = objMesh.Positions.Count;                 // Set this so we can offset the indicies for triangles correctly
                    var vertexBufferInfo    = drawCall.GetArray("m_vertexBuffers")[0]; // In what situation can we have more than 1 vertex buffer per draw call?
                    var vertexBufferIndex   = (int)vertexBufferInfo.GetIntegerProperty("m_hBuffer");
                    var vertexBuffer        = vbib.VertexBuffers[vertexBufferIndex];

                    var indexBufferInfo  = drawCall.GetSubCollection("m_indexBuffer");
                    var indexBufferIndex = (int)indexBufferInfo.GetIntegerProperty("m_hBuffer");
                    var indexBuffer      = vbib.IndexBuffers[indexBufferIndex];

                    // Set vertex attributes
                    foreach (var attribute in vertexBuffer.Attributes)
                    {
                        var buffer        = ReadAttributeBuffer(vertexBuffer, attribute);
                        var numComponents = buffer.Length / vertexBuffer.Count;


                        if (attribute.Name == "BLENDINDICES")
                        {
                            var byteBuffer    = buffer.Select(f => (byte)f).ToArray();
                            var rawBufferData = new byte[buffer.Length];
                            System.Buffer.BlockCopy(byteBuffer, 0, rawBufferData, 0, rawBufferData.Length);

                            var blendIndices = rawBufferData.ChunkBy(4);

                            objMesh.BlendIndices.AddRange(blendIndices);

                            continue;
                        }

                        if (attribute.Name == "BLENDWEIGHT")
                        {
                            var vectors = ToVector4Array(buffer);
                            objMesh.BlendWeights.AddRange(vectors);
                        }

                        if (attribute.Name == "POSITION")
                        {
                            var vectors = ToVector3Array(buffer);
                            objMesh.Positions.AddRange(vectors);
                        }

                        if (attribute.Name == "NORMAL")
                        {
                            if (VMesh.IsCompressedNormalTangent(drawCall))
                            {
                                var vectors = ToVector4Array(buffer);
                                var(normals, tangents) = DecompressNormalTangents(vectors);
                                objMesh.Normals.AddRange(normals);
                            }
                            else
                            {
                                var vectors = ToVector3Array(buffer);
                                objMesh.Normals.AddRange(vectors);
                            }
                            continue;
                        }

                        if (attribute.Name == "TEXCOORD")
                        {
                            if (numComponents != 2)
                            {
                                // ignore textcoords that arent 2
                                continue;
                            }
                            var vectors = ToVector2Array(buffer);
                            objMesh.TextureCoords.AddRange(vectors);
                        }
                    }

                    // Set index buffer
                    var startIndex = (int)drawCall.GetIntegerProperty("m_nStartIndex");
                    var indexCount = (int)drawCall.GetIntegerProperty("m_nIndexCount");
                    var indices    = ReadIndices(indexBuffer, startIndex, indexCount);
                    var newFaces   = indices.ChunkBy(3).Select(idxList => idxList.Select(idx => new ObjFaceVertex(idx + startingVertexCount)).ToList()).ToList();
                    objMesh.Faces.AddRange(newFaces);

                    var materialPath     = drawCall.GetProperty <string>("m_material");
                    var materialResource = VpkLoader.LoadFile(materialPath + "_c");
                    var renderMaterial   = (VMaterial)materialResource.DataBlock;
                    var matName          = Path.GetFileNameWithoutExtension(materialPath);
                    if (objMesh.Material == null)
                    {
                        objMesh.Material = ObjMaterial.FromVMaterial(renderMaterial, Path.GetFileNameWithoutExtension(materialPath), VpkLoader);
                    }
                    else if (matName != objMesh.Material.Name)
                    {
                        // throw new Exception("2 different mats in same object");
                    }
                }
            }
        }