Beispiel #1
0
        public override IOModel ImportFromFile(string filename)
        {
            var model     = new IOModel();
            var materials = new List <string>();
            var positions = new List <Vector3>();
            var textures  = new Dictionary <int, Texture>();

            using (var reader = new StreamReader(File.OpenRead(filename)))
            {
                var line = reader.ReadLine();
                if (line.Trim() != "Metasequoia Document")
                {
                    logger.Error("Not a valid Metasequoia file");
                    return(null);
                }

                while (!reader.EndOfStream)
                {
                    line = reader.ReadLine().Trim();
                    if (line == "" || line == "}")
                    {
                        continue;
                    }

                    // Parse chunks
                    var chunk = line.Split(' ')[0];
                    if (chunk == "Format")
                    {
                    }
                    else if (chunk == "Thumbnail")
                    {
                        IgnoreChunk(reader);
                    }
                    else if (chunk == "Scene")
                    {
                        IgnoreChunk(reader);
                    }
                    else if (chunk == "Material")
                    {
                        var numMaterials = int.Parse(line.Split(' ')[1]);
                        if (numMaterials == 0)
                        {
                            return(null);
                        }
                        for (var i = 0; i < numMaterials; i++)
                        {
                            var materialString = reader.ReadLine().Trim();
                            var tokensMaterial = materialString.Split(' ');
                            var material       = new IOMaterial(tokensMaterial[0]);

                            for (var j = 0; j < tokensMaterial.Length; j++)
                            {
                                var texturePath = "";
                                if (tokensMaterial[j].StartsWith("tex"))
                                {
                                    texturePath = tokensMaterial[j].Substring(5, tokensMaterial[j].Length - 7);
                                    if (texturePath != "")
                                    {
                                        string basePath = Path.GetDirectoryName(filename);
                                        if (!File.Exists(Path.Combine(basePath, texturePath)))
                                        {
                                            basePath = Path.Combine(Path.GetDirectoryName(filename), "Texture");
                                        }
                                        if (!File.Exists(Path.Combine(basePath, texturePath)))
                                        {
                                            throw new FileNotFoundException("Texture " + texturePath + " could not be found");
                                        }

                                        textures.Add(i, GetTexture(basePath, texturePath));
                                    }

                                    material.Texture = textures[i];
                                    break;
                                }
                            }

                            model.Materials.Add(material);
                        }
                    }
                    else if (chunk == "Object")
                    {
                        var name       = line.Split(' ')[1];
                        var mesh       = new IOMesh(name.Replace("\"", ""));
                        var tokensName = mesh.Name.Split('_');
                        positions = new List <Vector3>();

                        if (name.Contains("TeRoom_"))
                        {
                            model.HasMultipleRooms = true;
                        }

                        var lastVertex  = 0;
                        var translation = Vector3.Zero;

                        while (!reader.EndOfStream)
                        {
                            line = reader.ReadLine().Trim();
                            var tokens = line.Split(' ');

                            if (tokens[0] == "translation" && model.HasMultipleRooms)
                            {
                                translation = ApplyAxesTransforms(new Vector3(ParseFloatCultureInvariant(tokens[1]),
                                                                              ParseFloatCultureInvariant(tokens[2]),
                                                                              ParseFloatCultureInvariant(tokens[3])));
                            }
                            else if (tokens[0] == "vertex")
                            {
                                var numVertices = int.Parse(tokens[1]);
                                for (var i = 0; i < numVertices; i++)
                                {
                                    var tokensPosition = reader.ReadLine().Trim().Split(' ');
                                    var newPos         = ApplyAxesTransforms(new Vector3(ParseFloatCultureInvariant(tokensPosition[0]),
                                                                                         ParseFloatCultureInvariant(tokensPosition[1]),
                                                                                         ParseFloatCultureInvariant(tokensPosition[2]))
                                                                             );
                                    positions.Add(newPos);
                                }
                                line = reader.ReadLine().Trim();
                            }
                            else if (tokens[0] == "face")
                            {
                                var numFaces = int.Parse(tokens[1]);
                                for (var i = 0; i < numFaces; i++)
                                {
                                    line = reader.ReadLine().Trim();

                                    var numVerticesInFace = int.Parse(line.Substring(0, line.IndexOf(' ')));
                                    var poly = new IOPolygon(numVerticesInFace == 3 ? IOPolygonShape.Triangle : IOPolygonShape.Quad);

                                    // We MUST have vertices
                                    var stringVertices = GetSubBlock(line, "V");
                                    if (stringVertices == "")
                                    {
                                        return(null);
                                    }
                                    var tokensVertices = stringVertices.Split(' ');
                                    for (var k = 0; k < numVerticesInFace; k++)
                                    {
                                        var index = int.Parse(tokensVertices[k]);
                                        mesh.Positions.Add(positions[index]);
                                        poly.Indices.Add(lastVertex);
                                        lastVertex++;
                                    }

                                    // Change vertex winding
                                    if (_settings.InvertFaces)
                                    {
                                        poly.Indices.Reverse();
                                    }

                                    // UV
                                    var stringUV = GetSubBlock(line, "UV");
                                    if (stringUV != "")
                                    {
                                        var tokensUV = stringUV.Split(' ');
                                        for (var k = 0; k < numVerticesInFace; k++)
                                        {
                                            var uv = ApplyUVTransform(new Vector2(ParseFloatCultureInvariant(tokensUV[2 * k]),
                                                                                  ParseFloatCultureInvariant(tokensUV[2 * k + 1])),
                                                                      textures[0].Image.Width,
                                                                      textures[0].Image.Height);
                                            mesh.UV.Add(uv);
                                        }
                                    }

                                    // Colors
                                    var stringColor = GetSubBlock(line, "COL");
                                    if (stringColor != "")
                                    {
                                        var tokensColor = stringColor.Split(' ');
                                        for (var k = 0; k < numVerticesInFace; k++)
                                        {
                                            var color = ApplyColorTransform(GetColor(long.Parse(tokensColor[k])));
                                            mesh.Colors.Add(color);
                                        }
                                    }
                                    else
                                    {
                                        for (var k = 0; k < numVerticesInFace; k++)
                                        {
                                            var color = ApplyColorTransform(Vector4.One);
                                            mesh.Colors.Add(color);
                                        }
                                    }

                                    // Material index
                                    var stringMaterialIndex = GetSubBlock(line, "M");
                                    var materialIndex       = 0;
                                    if (stringMaterialIndex != "")
                                    {
                                        materialIndex = int.Parse(stringMaterialIndex);
                                    }

                                    // Add polygon to the submesh (and add submesh if not existing yet)
                                    var material = model.Materials[materialIndex];
                                    if (!mesh.Submeshes.ContainsKey(material))
                                    {
                                        mesh.Submeshes.Add(material, new IOSubmesh(material));
                                    }

                                    mesh.Submeshes[material].Polygons.Add(poly);
                                }
                                line = reader.ReadLine().Trim();
                            }
                            else if (tokens[0] == "vertexattr")
                            {
                                // section to ignore
                                IgnoreChunk(reader);
                            }
                            else if (tokens[0] == "}")
                            {
                                break;
                            }
                        }

                        model.Meshes.Add(mesh);
                    }
                }
            }

            CalculateNormals(model);

            return(model);
        }
Beispiel #2
0
        /// <summary>
        ///
        /// </summary>
        /// <returns></returns>
        public IOMaterial LoadMaterial(Material mat)
        {
            var effectURL = mat.Instance_Effect?.URL;

            if (effectURL == null)
            {
                return(null);
            }

            var effect = _collada.Library_Effects.Effect.ToList().Find(e => e.ID == ColladaHelper.SanitizeID(effectURL));

            IOMaterial material = new IOMaterial()
            {
                Name  = mat.ID,
                Label = mat.Name
            };

            if (effect != null && effect.Profile_COMMON != null && effect.Profile_COMMON.Length > 0)
            {
                var prof = effect.Profile_COMMON[0];

                var phong   = prof.Technique.Phong;
                var blinn   = prof.Technique.Blinn;
                var lambert = prof.Technique.Lambert;

                if (phong != null)
                {
                    if (phong.Transparency != null)
                    {
                        material.Alpha = phong.Transparency.Float.Value;
                    }

                    if (phong.Shininess != null)
                    {
                        material.Shininess = phong.Shininess.Float.Value;
                    }

                    if (phong.Diffuse != null)
                    {
                        if (ReadEffectColorType(prof, phong.Diffuse, out Vector4 color, out IOTexture texture))
                        {
                            material.DiffuseColor = color;
                        }

                        if (texture != null)
                        {
                            material.DiffuseMap = texture;
                        }
                    }

                    if (phong.Ambient != null)
                    {
                        if (ReadEffectColorType(prof, phong.Ambient, out Vector4 color, out IOTexture texture))
                        {
                            material.AmbientColor = color;
                        }

                        if (texture != null)
                        {
                            material.AmbientMap = texture;
                        }
                    }

                    if (phong.Specular != null)
                    {
                        if (ReadEffectColorType(prof, phong.Specular, out Vector4 color, out IOTexture texture))
                        {
                            material.SpecularColor = color;
                        }

                        if (texture != null)
                        {
                            material.SpecularMap = texture;
                        }
                    }

                    if (phong.Reflective != null)
                    {
                        if (ReadEffectColorType(prof, phong.Reflective, out Vector4 color, out IOTexture texture))
                        {
                            material.ReflectiveColor = color;
                        }

                        if (texture != null)
                        {
                            material.ReflectiveMap = texture;
                        }
                    }
                }


                if (lambert != null)
                {
                    if (lambert.Transparency != null)
                    {
                        material.Alpha = lambert.Transparency.Float.Value;
                    }

                    if (lambert.Diffuse != null)
                    {
                        if (ReadEffectColorType(prof, lambert.Diffuse, out Vector4 color, out IOTexture texture))
                        {
                            material.DiffuseColor = color;
                        }

                        if (texture != null)
                        {
                            material.DiffuseMap = texture;
                        }
                    }

                    if (lambert.Ambient != null)
                    {
                        if (ReadEffectColorType(prof, lambert.Ambient, out Vector4 color, out IOTexture texture))
                        {
                            material.AmbientColor = color;
                        }

                        if (texture != null)
                        {
                            material.AmbientMap = texture;
                        }
                    }

                    if (lambert.Reflective != null)
                    {
                        if (ReadEffectColorType(prof, lambert.Reflective, out Vector4 color, out IOTexture texture))
                        {
                            material.ReflectiveColor = color;
                        }

                        if (texture != null)
                        {
                            material.ReflectiveMap = texture;
                        }
                    }
                }


                if (blinn != null)
                {
                    if (blinn.Transparency != null)
                    {
                        material.Alpha = blinn.Transparency.Float.Value;
                    }

                    if (blinn.Shininess != null)
                    {
                        material.Shininess = blinn.Shininess.Float.Value;
                    }

                    if (blinn.Diffuse != null)
                    {
                        if (ReadEffectColorType(prof, blinn.Diffuse, out Vector4 color, out IOTexture texture))
                        {
                            material.DiffuseColor = color;
                        }

                        if (texture != null)
                        {
                            material.DiffuseMap = texture;
                        }
                    }

                    if (blinn.Ambient != null)
                    {
                        if (ReadEffectColorType(prof, blinn.Ambient, out Vector4 color, out IOTexture texture))
                        {
                            material.AmbientColor = color;
                        }

                        if (texture != null)
                        {
                            material.AmbientMap = texture;
                        }
                    }

                    if (blinn.Specular != null)
                    {
                        if (ReadEffectColorType(prof, blinn.Specular, out Vector4 color, out IOTexture texture))
                        {
                            material.SpecularColor = color;
                        }

                        if (texture != null)
                        {
                            material.SpecularMap = texture;
                        }
                    }

                    if (blinn.Reflective != null)
                    {
                        if (ReadEffectColorType(prof, blinn.Reflective, out Vector4 color, out IOTexture texture))
                        {
                            material.ReflectiveColor = color;
                        }

                        if (texture != null)
                        {
                            material.ReflectiveMap = texture;
                        }
                    }
                }
            }

            return(material);
        }
Beispiel #3
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="settings"></param>
        /// <param name="material"></param>
        /// <returns></returns>
        private HSD_MOBJ GenerateMaterial(IOMaterial material)
        {
            // create blank mobj
            var Mobj = new HSD_MOBJ();

            Mobj.Material = new HSD_Material()
            {
                AMB_A         = 0xFF,
                AMB_R         = 0x7F,
                AMB_G         = 0x7F,
                AMB_B         = 0x7F,
                DiffuseColor  = System.Drawing.Color.White,
                SpecularColor = System.Drawing.Color.White,
                Shininess     = 50,
                Alpha         = 1
            };

            // detect and set flags
            if (Settings.ImportVertexColor)
            {
                Mobj.RenderFlags |= RENDER_MODE.VERTEX;
            }

            if (Settings.EnableDiffuse)
            {
                Mobj.RenderFlags |= RENDER_MODE.DIFFUSE;
            }

            if (Settings.EnableConstant)
            {
                Mobj.RenderFlags |= RENDER_MODE.CONSTANT;
            }

            // Properties
            if (material != null && Settings.ImportMaterialInfo)
            {
                Mobj.Material.Shininess = material.Shininess;
                Mobj.Material.Alpha     = material.Alpha;

                Mobj.Material.AMB_R = (byte)(material.AmbientColor.X * 255);
                Mobj.Material.AMB_G = (byte)(material.AmbientColor.Y * 255);
                Mobj.Material.AMB_B = (byte)(material.AmbientColor.Z * 255);
                Mobj.Material.AMB_A = (byte)(material.AmbientColor.W * 255);

                Mobj.Material.DIF_R = (byte)(material.DiffuseColor.X * 255);
                Mobj.Material.DIF_G = (byte)(material.DiffuseColor.Y * 255);
                Mobj.Material.DIF_B = (byte)(material.DiffuseColor.Z * 255);
                Mobj.Material.DIF_A = (byte)(material.DiffuseColor.W * 255);

                Mobj.Material.SPC_R = (byte)(material.SpecularColor.X * 255);
                Mobj.Material.SPC_G = (byte)(material.SpecularColor.Y * 255);
                Mobj.Material.SPC_B = (byte)(material.SpecularColor.Z * 255);
                Mobj.Material.SPC_A = (byte)(material.SpecularColor.W * 255);
            }

            // Textures
            if (material != null && Settings.ImportTexture)
            {
                if (material.DiffuseMap != null && !string.IsNullOrEmpty(material.DiffuseMap.FilePath))
                {
                    var texturePath = material.DiffuseMap.FilePath;

                    if (texturePath.Contains("file://"))
                    {
                        texturePath = texturePath.Replace("file://", "");
                    }

                    if (File.Exists(Path.Combine(_cache.FolderPath, texturePath)))
                    {
                        texturePath = Path.Combine(_cache.FolderPath, texturePath);
                    }

                    if (File.Exists(material.DiffuseMap.FilePath))
                    {
                        texturePath = material.DiffuseMap.FilePath;
                    }

                    if (File.Exists(texturePath + ".png"))
                    {
                        texturePath = texturePath + ".png";
                    }


                    var mobjPath = Path.Combine(Path.GetDirectoryName(texturePath), Path.GetFileNameWithoutExtension(texturePath)) + ".mobj";

                    if (Settings.ImportMOBJ && File.Exists(mobjPath))
                    {
                        var dat = new HSDRaw.HSDRawFile(mobjPath);
                        Mobj._s = dat.Roots[0].Data._s;
                        return(Mobj);
                    }
                    else
                    /// special mobj loading
                    if (Path.GetExtension(texturePath).ToLower() == ".mobj")
                    {
                        var dat = new HSDRaw.HSDRawFile(texturePath);
                        Mobj._s = dat.Roots[0].Data._s;
                        return(Mobj);
                    }
                    else
                    if (File.Exists(texturePath) && (texturePath.ToLower().EndsWith(".png") || texturePath.ToLower().EndsWith(".bmp")))
                    {
                        Mobj.RenderFlags |= RENDER_MODE.TEX0;

                        var tobj = TOBJConverter.ImportTOBJFromFile(texturePath, Settings.TextureFormat, Settings.PaletteFormat);
                        tobj.Flags = TOBJ_FLAGS.LIGHTMAP_DIFFUSE | TOBJ_FLAGS.COORD_UV | TOBJ_FLAGS.COLORMAP_MODULATE;

                        tobj.GXTexGenSrc = 4;
                        tobj.TexMapID    = GXTexMapID.GX_TEXMAP0;

                        tobj.WrapS = ToGXWrapMode(material.DiffuseMap.WrapS);
                        tobj.WrapT = ToGXWrapMode(material.DiffuseMap.WrapT);

                        if (TOBJConverter.IsTransparent(tobj))
                        {
                            _cache.HasXLU     = true;
                            Mobj.RenderFlags |= RENDER_MODE.XLU;
                            tobj.Flags       |= TOBJ_FLAGS.ALPHAMAP_MODULATE;
                        }

                        Mobj.Textures = tobj;
                    }
                }
            }

            return(Mobj);
        }
Beispiel #4
0
        /// <summary>
        ///
        /// </summary>
        /// <returns></returns>
        public List <IOMaterial> GetMaterials()
        {
            List <IOMaterial> materials = new List <IOMaterial>();

            foreach (var m in _document.GetNodesByName("Material"))
            {
                // generate material
                IOMaterial mat = new IOMaterial()
                {
                    Name = GetNameWithoutNamespace(m.Properties[NodeDescSize - 2].ToString())
                };

                // load material attributes
                if (m["ShadingModel"] != null && m["ShadingModel"].Properties[0].ToString().ToLower() == "phong")//ToLower Because it's sometimes "Phong"
                {
                    var properties = m.GetNodesByName("P");
                    if (properties.Length == 0)
                    {
                        properties = m.GetNodesByName("Property");
                    }

                    foreach (var prop in properties)
                    {
                        switch (prop.Properties[0].ToString())
                        {
                        case "AmbientColor":
                            mat.AmbientColor = GetColor(prop);
                            break;

                        case "DiffuseColor":
                            mat.DiffuseColor = GetColor(prop);
                            break;

                        case "SpecularColor":
                            mat.SpecularColor = GetColor(prop);
                            break;

                        case "ReflectionColor":
                            mat.ReflectiveColor = GetColor(prop);
                            break;

                        case "Emissive":
                            mat.EmissionColor = GetColor(prop);
                            break;

                        case "Shininess":
                            mat.Shininess = (float)(double)prop.Properties[PropertyDescSize];
                            break;

                        case "Opacity":
                            mat.Alpha = (float)(double)prop.Properties[PropertyDescSize];
                            break;
                        }
                    }
                }

                // get textures

                var children = GetChildConnections(m).Where(e => e.Name == "Texture");

                foreach (var t in children)
                {
                    // the property is stored in the connections
                    // for now always map it to diffuse

                    mat.DiffuseMap = new IOTexture()
                    {
                        Name     = t.Properties[NodeDescSize - 2].ToString(),
                        FilePath = t["FileName"].Properties[0].ToString()
                    };
                }

                materials.Add(mat);
            }

            return(materials);
        }
Beispiel #5
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="filePath"></param>
        /// <returns></returns>
        public IOScene GetScene(string filePath)
        {
            IOScene scene = new IOScene();

            IOModel model = new IOModel();

            scene.Models.Add(model);

            using (FileStream stream = new FileStream(filePath, FileMode.Open))
                using (StreamReader r = new StreamReader(stream))
                {
                    Dictionary <string, IOMesh> nameToMesh  = new Dictionary <string, IOMesh>();
                    HashSet <IOBone>            meshBones   = new HashSet <IOBone>();
                    Dictionary <int, IOBone>    idxToBone   = new Dictionary <int, IOBone>();
                    Dictionary <int, int>       idxToParent = new Dictionary <int, int>();

                    string mode = "";
                    int    time = 0;

                    while (!r.EndOfStream)
                    {
                        // read and clean line args
                        var line = r.ReadLine().Trim();
                        var args = Regex.Replace(line, @"\s+", " ").Split(' ');

                        // check for grouping
                        switch (args[0])
                        {
                        case "nodes":
                        case "skeleton":
                        case "triangles":
                        case "end":
                            mode = args[0];
                            break;
                        }

                        switch (mode)
                        {
                        case "nodes":
                            if (args.Length >= 3)
                            {
                                args = line.Split('"');

                                var index       = int.Parse(args[0].Trim());
                                var name        = args[1];
                                var parentIndex = int.Parse(args[2].Trim());

                                IOBone bone = new IOBone()
                                {
                                    Name = name
                                };

                                idxToBone.Add(index, bone);
                                idxToParent.Add(index, parentIndex);
                            }
                            break;

                        case "skeleton":
                            if (args.Length == 2 && args[0] == "time")
                            {
                                int.TryParse(args[1], out time);
                            }
                            if (args.Length == 7)
                            {
                                var index = int.Parse(args[0]);

                                if (time == 0)
                                {
                                    idxToBone[index].Translation   = new System.Numerics.Vector3(float.Parse(args[1]), float.Parse(args[2]), float.Parse(args[3]));
                                    idxToBone[index].RotationEuler = new System.Numerics.Vector3(float.Parse(args[4]), float.Parse(args[5]), float.Parse(args[6]));
                                }
                            }
                            break;

                        case "triangles":
                        {
                            if (args.Length > 0 && args.Length < 9 && args[0] != "triangles")
                            {
                                var material = string.Join(" ", args);

                                var v1 = ParseVertex(r.ReadLine(), idxToBone, out IOBone parent);
                                var v2 = ParseVertex(r.ReadLine(), idxToBone, out parent);
                                var v3 = ParseVertex(r.ReadLine(), idxToBone, out parent);

                                var meshName = parent.Name + material;

                                if (!meshBones.Contains(parent))
                                {
                                    meshBones.Add(parent);
                                }

                                meshName = Regex.Replace(meshName.Trim(), @"\s+", "_").Replace("#", "");

                                if (!nameToMesh.ContainsKey(meshName))
                                {
                                    // create and load material
                                    IOMaterial mat = new IOMaterial()
                                    {
                                        Name = material
                                    };
                                    scene.Materials.Add(mat);

                                    // create io mesh
                                    var iomesh = new IOMesh()
                                    {
                                        Name = meshName
                                    };

                                    // create triangle polygon
                                    iomesh.Polygons.Add(new IOPolygon()
                                        {
                                            MaterialName  = material,
                                            PrimitiveType = IOPrimitive.TRIANGLE
                                        });

                                    nameToMesh.Add(meshName, iomesh);
                                }

                                var mesh = nameToMesh[meshName];
                                mesh.Polygons[0].Indicies.Add(mesh.Vertices.Count);
                                mesh.Polygons[0].Indicies.Add(mesh.Vertices.Count + 1);
                                mesh.Polygons[0].Indicies.Add(mesh.Vertices.Count + 2);
                                mesh.Vertices.Add(v1);
                                mesh.Vertices.Add(v2);
                                mesh.Vertices.Add(v3);
                            }
                        }
                        break;
                        }
                    }

                    // create skeleton hierarchy
                    foreach (var bone in idxToBone)
                    {
                        var parent = idxToParent[bone.Key];

                        if (parent == -1)
                        {
                            if (meshBones.Count > 1 && meshBones.Contains(bone.Value))
                            {
                                continue;
                            }
                            else
                            {
                                model.Skeleton.RootBones.Add(bone.Value);
                            }
                        }
                        else
                        {
                            idxToBone[parent].AddChild(bone.Value);
                        }
                    }

                    // dump mesh
                    model.Meshes.AddRange(nameToMesh.Values);
                }

            return(scene);
        }
Beispiel #6
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="mat"></param>
        private void ProcessMaterial(IOMaterial mat)
        {
            // create phong shading
            var phong = new Phong()
            {
                Shininess = new FX_Common_Float_Or_Param_Type {
                    Float = new IONET.Collada.Types.SID_Float()
                    {
                        sID = "shininess", Value = mat.Shininess
                    }
                },
                Transparency = new FX_Common_Float_Or_Param_Type()
                {
                    Float = new IONET.Collada.Types.SID_Float()
                    {
                        sID = "transparency", Value = mat.Alpha
                    }
                },
                Reflectivity = new FX_Common_Float_Or_Param_Type()
                {
                    Float = new IONET.Collada.Types.SID_Float()
                    {
                        sID = "reflectivity", Value = mat.Reflectivity
                    }
                },
                Ambient    = GenerateTextureInfo("ambient", mat.AmbientColor, mat.AmbientMap),
                Diffuse    = GenerateTextureInfo("diffuse", mat.DiffuseColor, mat.DiffuseMap),
                Specular   = GenerateTextureInfo("specular", mat.SpecularColor, mat.SpecularMap),
                Emission   = GenerateTextureInfo("emission", mat.EmissionColor, mat.EmissionMap),
                Reflective = GenerateTextureInfo("reflective", mat.ReflectiveColor, mat.ReflectiveMap),
            };

            // create effect
            Effect effect = new Effect()
            {
                ID             = GetUniqueID(mat.Name + "-effect"),
                Name           = mat.Name,
                Profile_COMMON = new IONET.Collada.FX.Profiles.COMMON.Profile_COMMON[]
                {
                    new IONET.Collada.FX.Profiles.COMMON.Profile_COMMON()
                    {
                        Technique = new IONET.Collada.FX.Profiles.COMMON.Effect_Technique_COMMON()
                        {
                            sID   = "standard",
                            Phong = phong
                        },
                    }
                }
            };

            // create material
            Material material = new Material()
            {
                ID              = GetUniqueID(mat.Name),
                Name            = mat.Name,
                Instance_Effect = new Instance_Effect()
                {
                    URL = "#" + effect.ID
                }
            };

            // add effect to effect library
            if (_collada.Library_Effects == null)
            {
                _collada.Library_Effects = new Library_Effects();
            }

            if (_collada.Library_Effects.Effect == null)
            {
                _collada.Library_Effects.Effect = new Effect[0];
            }

            Array.Resize(ref _collada.Library_Effects.Effect, _collada.Library_Effects.Effect.Length + 1);

            _collada.Library_Effects.Effect[_collada.Library_Effects.Effect.Length - 1] = effect;

            // add material to material library
            if (_collada.Library_Materials == null)
            {
                _collada.Library_Materials = new Library_Materials();
            }

            if (_collada.Library_Materials.Material == null)
            {
                _collada.Library_Materials.Material = new Material[0];
            }

            Array.Resize(ref _collada.Library_Materials.Material, _collada.Library_Materials.Material.Length + 1);

            _collada.Library_Materials.Material[_collada.Library_Materials.Material.Length - 1] = material;
        }
Beispiel #7
0
        public IOModel GetIOModel()
        {
            IOModel outModel = new IOModel();

            Mesh meshFile     = null;
            Matl materialFile = null;

            foreach (FileNode n in Parent.Nodes)
            {
                if (n.Text.Equals(model.MeshString))
                {
                    meshFile = ((NumsbhNode)n).mesh;
                }
                if (n.Text.Equals(model.SkeletonFileName))
                {
                    outModel.Skeleton = (RSkeleton)((SkelNode)n).GetRenderableNode();
                }
                if (n.Text.Equals(model.MaterialFileNames[0].MaterialFileName))
                {
                    materialFile = ((MatlNode)n).Material;
                }
            }

            Dictionary <string, int> indexByBoneName = new Dictionary <string, int>();

            if (outModel.Skeleton != null)
            {
                for (int i = 0; i < outModel.Skeleton.Bones.Count; i++)
                {
                    indexByBoneName.Add(outModel.Skeleton.Bones[i].Name, i);
                }
            }

            Dictionary <string, int> materialNameToIndex = new Dictionary <string, int>();

            if (materialFile != null)
            {
                int materialIndex = 0;
                foreach (var entry in materialFile.Entries)
                {
                    materialNameToIndex.Add(entry.ShaderLabel, materialIndex++);
                    IOMaterial material = new IOMaterial
                    {
                        Name = entry.ShaderLabel
                    };
                    outModel.Materials.Add(material);

                    foreach (var attr in entry.Attributes)
                    {
                        if (attr.ParamId == MatlEnums.ParamId.Texture0)
                        {
                            IOTexture dif = new IOTexture
                            {
                                Name = attr.DataObject.ToString()
                            };
                            material.DiffuseTexture = dif;
                        }
                    }
                }
            }

            if (meshFile != null)
            {
                SsbhVertexAccessor vertexAccessor = new SsbhVertexAccessor(meshFile);
                {
                    SsbhRiggingAccessor riggingAccessor = new SsbhRiggingAccessor(meshFile);
                    foreach (MeshObject obj in meshFile.Objects)
                    {
                        IOMesh outMesh = new IOMesh()
                        {
                            Name = obj.Name,
                        };
                        outModel.Meshes.Add(outMesh);

                        // get material
                        if (materialFile != null)
                        {
                            foreach (var entry in model.ModelEntries)
                            {
                                if (entry.MeshName.Equals(obj.Name) && entry.SubIndex == obj.SubMeshIndex)
                                {
                                    outMesh.MaterialIndex = materialNameToIndex[entry.MaterialLabel];
                                    break;
                                }
                            }
                        }

                        IOVertex[] vertices = new IOVertex[obj.VertexCount];
                        for (int i = 0; i < vertices.Length; i++)
                        {
                            vertices[i] = new IOVertex();
                        }

                        foreach (MeshAttribute attr in obj.Attributes)
                        {
                            SsbhVertexAttribute[] values = vertexAccessor.ReadAttribute(attr.AttributeStrings[0].Name, 0, obj.VertexCount, obj);

                            if (attr.AttributeStrings[0].Name.Equals("Position0"))
                            {
                                outMesh.HasPositions = true;
                                for (int i = 0; i < values.Length; i++)
                                {
                                    vertices[i].Position = new OpenTK.Vector3(values[i].X, values[i].Y, values[i].Z);
                                }
                            }
                            if (attr.AttributeStrings[0].Name.Equals("Normal0"))
                            {
                                outMesh.HasNormals = true;
                                for (int i = 0; i < values.Length; i++)
                                {
                                    vertices[i].Normal = new OpenTK.Vector3(values[i].X, values[i].Y, values[i].Z);
                                }
                            }

                            // Flip UVs vertically for export.
                            if (attr.AttributeStrings[0].Name.Equals("map1"))
                            {
                                outMesh.HasUV0 = true;
                                for (int i = 0; i < values.Length; i++)
                                {
                                    vertices[i].UV0 = new OpenTK.Vector2(values[i].X, 1 - values[i].Y);
                                }
                            }
                            if (attr.AttributeStrings[0].Name.Equals("uvSet"))
                            {
                                outMesh.HasUV1 = true;
                                for (int i = 0; i < values.Length; i++)
                                {
                                    vertices[i].UV1 = new OpenTK.Vector2(values[i].X, 1 - values[i].Y);
                                }
                            }
                            if (attr.AttributeStrings[0].Name.Equals("uvSet1"))
                            {
                                outMesh.HasUV2 = true;
                                for (int i = 0; i < values.Length; i++)
                                {
                                    vertices[i].UV2 = new OpenTK.Vector2(values[i].X, 1 - values[i].Y);
                                }
                            }
                            if (attr.AttributeStrings[0].Name.Equals("uvSet2"))
                            {
                                outMesh.HasUV3 = true;
                                for (int i = 0; i < values.Length; i++)
                                {
                                    vertices[i].UV3 = new OpenTK.Vector2(values[i].X, 1 - values[i].Y);
                                }
                            }
                            if (attr.AttributeStrings[0].Name.Equals("colorSet1"))
                            {
                                outMesh.HasColor = true;
                                for (int i = 0; i < values.Length; i++)
                                {
                                    vertices[i].Color = new OpenTK.Vector4(values[i].X, values[i].Y, values[i].Z, values[i].W) / 127f;
                                }
                            }
                        }

                        // Fix SingleBinds
                        if (outModel.Skeleton != null && !obj.ParentBoneName.Equals(""))
                        {
                            int parentIndex = outModel.Skeleton.GetBoneIndex(obj.ParentBoneName);
                            if (parentIndex != -1)
                            {
                                for (int i = 0; i < vertices.Length; i++)
                                {
                                    vertices[i].Position      = OpenTK.Vector3.TransformPosition(vertices[i].Position, outModel.Skeleton.Bones[parentIndex].WorldTransform);
                                    vertices[i].Normal        = OpenTK.Vector3.TransformNormal(vertices[i].Normal, outModel.Skeleton.Bones[parentIndex].WorldTransform);
                                    vertices[i].BoneIndices.X = indexByBoneName[obj.ParentBoneName];
                                    vertices[i].BoneWeights.X = 1;
                                    outMesh.HasBoneWeights    = true;
                                }
                            }
                        }

                        // Apply Rigging
                        SsbhVertexInfluence[] influences = riggingAccessor.ReadRiggingBuffer(obj.Name, (int)obj.SubMeshIndex);

                        foreach (SsbhVertexInfluence influence in influences)
                        {
                            outMesh.HasBoneWeights = true;

                            // Some influences refer to bones that don't exist in the skeleton.
                            // _eff bones?
                            if (!indexByBoneName.ContainsKey(influence.BoneName))
                            {
                                continue;
                            }

                            if (vertices[influence.VertexIndex].BoneWeights.X == 0)
                            {
                                vertices[influence.VertexIndex].BoneIndices.X = indexByBoneName[influence.BoneName];
                                vertices[influence.VertexIndex].BoneWeights.X = influence.Weight;
                            }
                            else if (vertices[influence.VertexIndex].BoneWeights.Y == 0)
                            {
                                vertices[influence.VertexIndex].BoneIndices.Y = indexByBoneName[influence.BoneName];
                                vertices[influence.VertexIndex].BoneWeights.Y = influence.Weight;
                            }
                            else if (vertices[influence.VertexIndex].BoneWeights.Z == 0)
                            {
                                vertices[influence.VertexIndex].BoneIndices.Z = indexByBoneName[influence.BoneName];
                                vertices[influence.VertexIndex].BoneWeights.Z = influence.Weight;
                            }
                            else if (vertices[influence.VertexIndex].BoneWeights.W == 0)
                            {
                                vertices[influence.VertexIndex].BoneIndices.W = indexByBoneName[influence.BoneName];
                                vertices[influence.VertexIndex].BoneWeights.W = influence.Weight;
                            }
                        }

                        outMesh.Vertices.AddRange(vertices);
                        outMesh.Indices.AddRange(vertexAccessor.ReadIndices(0, obj.IndexCount, obj));
                    }
                }
            }


            return(outModel);
        }
Beispiel #8
0
        public override bool ExportToFile(IOModel model, string filename)
        {
            var path         = Path.GetDirectoryName(filename);
            var materialPath = path + "\\" + Path.GetFileNameWithoutExtension(filename) + ".mtl";

            using (var writer = new StreamWriter(filename, false))
            {
                writer.WriteLine("# Exported by Tomb Editor " + Assembly.GetExecutingAssembly().GetName().Version.ToString() + "\n");
                writer.WriteLine("mtllib " + Path.GetFileNameWithoutExtension(filename) + ".mtl" + "\n");

                // Optimize all data
                var poscol        = new List <Vector3[]>();
                var poscolIndices = new Dictionary <int, int>();

                var normals       = new List <Vector3>();
                var normalIndices = new Dictionary <int, int>();

                var uvs       = new List <Vector2>();
                var uvIndices = new Dictionary <int, int>();

                // Pack positions and colours
                int meshCount = 0;
                foreach (var mesh in model.Meshes)
                {
                    if (mesh.Positions.Count == 0)
                    {
                        continue;
                    }

                    for (int i = 0; i < mesh.Positions.Count; i++)
                    {
                        var position = ApplyAxesTransforms(mesh.Positions[i]);
                        var colour   = ApplyColorTransform(mesh.Colors.Count > i ? mesh.Colors[i] : new Vector4(2)).To3();

                        int found = -1;
                        for (int j = 0; j < poscol.Count; j++)
                        {
                            if (poscol[j][0] == position &&
                                poscol[j][1] == colour)
                            {
                                found = j;
                                break;
                            }
                        }

                        if (found == -1)
                        {
                            found = poscol.Count;
                            poscol.Add(new Vector3[2] {
                                position, colour
                            });
                        }

                        poscolIndices.Add(i + meshCount, found);
                    }
                    meshCount += mesh.Positions.Count;
                }

                // Pack normals
                meshCount = 0;
                foreach (var mesh in model.Meshes)
                {
                    if (mesh.Normals.Count == 0)
                    {
                        mesh.CalculateNormals();
                    }

                    for (int i = 0; i < mesh.Normals.Count; i++)
                    {
                        var normal = mesh.Normals[i];
                        int found  = -1;
                        for (int j = 0; j < normals.Count; j++)
                        {
                            if (normals[j] == normal)
                            {
                                found = j;
                                break;
                            }
                        }

                        if (found == -1)
                        {
                            found = normals.Count;
                            normals.Add(normal);
                        }

                        normalIndices.Add(i + meshCount, found);
                    }
                    meshCount += mesh.Normals.Count;
                }

                // Pack UV coords
                meshCount = 0;
                foreach (var mesh in model.Meshes)
                {
                    if (mesh.UV.Count == 0)
                    {
                        continue;
                    }

                    for (int i = 0; i < mesh.UV.Count; i++)
                    {
                        var uv    = mesh.UV[i];
                        int found = -1;
                        for (int j = 0; j < uvs.Count; j++)
                        {
                            if (uvs[j] == uv)
                            {
                                found = j;
                                break;
                            }
                        }

                        if (found == -1)
                        {
                            found = uvs.Count;
                            uvs.Add(uv);
                        }

                        uvIndices.Add(i + meshCount, found);
                    }
                    meshCount += mesh.UV.Count;
                }

                // Save vertices
                if (!_settings.UseVertexColor)
                {
                    foreach (var pc in poscol)
                    {
                        writer.WriteLine("v " + pc[0].X.ToString(CultureInfo.InvariantCulture) + " " +
                                         pc[0].Y.ToString(CultureInfo.InvariantCulture) + " " +
                                         pc[0].Z.ToString(CultureInfo.InvariantCulture));
                    }
                }
                else
                {
                    // Include vertex colour, it may be parsed correctly by some software, e.g. MeshMixer and MeshLab.
                    foreach (var pc in poscol)
                    {
                        writer.WriteLine("v " + pc[0].X.ToString(CultureInfo.InvariantCulture) + " " +
                                         pc[0].Y.ToString(CultureInfo.InvariantCulture) + " " +
                                         pc[0].Z.ToString(CultureInfo.InvariantCulture) + " " +
                                         pc[1].X.ToString(CultureInfo.InvariantCulture) + " " +
                                         pc[1].Y.ToString(CultureInfo.InvariantCulture) + " " +
                                         pc[1].Z.ToString(CultureInfo.InvariantCulture));
                    }
                }
                writer.WriteLine("# " + poscol.Count + " vertices total.\n");

                // Save normals
                foreach (var normal in normals)
                {
                    writer.WriteLine("vn " + normal.X.ToString(CultureInfo.InvariantCulture) + " " +
                                     normal.Y.ToString(CultureInfo.InvariantCulture) + " " +
                                     normal.Z.ToString(CultureInfo.InvariantCulture));
                }
                writer.WriteLine("# " + normals.Count + " normals total.\n");

                // Save UVs
                foreach (var uv in uvs)
                {
                    writer.WriteLine("vt " + uv.X.ToString(CultureInfo.InvariantCulture) + " " +
                                     (1.0f - uv.Y).ToString(CultureInfo.InvariantCulture) + " 0.000");
                }
                writer.WriteLine("# " + uvs.Count + " UVs total.\n");

                int pCount = 0;
                int uCount = 0;
                int nCount = 0;

                foreach (var mesh in model.Meshes)
                {
                    writer.WriteLine("o " + mesh.Name + "\n");

                    // Save faces
                    IOMaterial lastMaterial = null;
                    int        faceCount    = 0;

                    foreach (var submesh in mesh.Submeshes)
                    {
                        if (submesh.Value.Polygons.Count == 0)
                        {
                            continue;
                        }

                        if (lastMaterial == null || lastMaterial != submesh.Key)
                        {
                            lastMaterial = submesh.Key;
                            writer.WriteLine("\n" + "usemtl " + lastMaterial.Name.ToString());
                        }

                        foreach (var poly in submesh.Value.Polygons)
                        {
                            var indices = new List <int>();
                            indices.Add(poly.Indices[0]);
                            indices.Add(poly.Indices[1]);
                            indices.Add(poly.Indices[2]);
                            if (poly.Shape == IOPolygonShape.Quad)
                            {
                                indices.Add(poly.Indices[3]);
                            }

                            // Change vertex winding
                            if (_settings.InvertFaces)
                            {
                                indices.Reverse();
                            }

                            var v1 = indices[0];
                            var v2 = indices[1];
                            var v3 = indices[2];
                            var v4 = (poly.Shape == IOPolygonShape.Quad ? indices[3] : 0);

                            if (poly.Shape == IOPolygonShape.Triangle)
                            {
                                writer.WriteLine("f  " + (poscolIndices[v1 + pCount] + 1) + "/"
                                                 + (uvIndices    [v1 + uCount] + 1) + "/"
                                                 + (normalIndices[v1 + nCount] + 1) + " "
                                                 + (poscolIndices[v2 + pCount] + 1) + "/"
                                                 + (uvIndices    [v2 + uCount] + 1) + "/"
                                                 + (normalIndices[v2 + nCount] + 1) + " "
                                                 + (poscolIndices[v3 + pCount] + 1) + "/"
                                                 + (uvIndices    [v3 + uCount] + 1) + "/"
                                                 + (normalIndices[v3 + nCount] + 1));
                            }
                            else
                            {
                                writer.WriteLine("f  " + (poscolIndices[v1 + pCount] + 1) + "/"
                                                 + (uvIndices    [v1 + uCount] + 1) + "/"
                                                 + (normalIndices[v1 + nCount] + 1) + " "
                                                 + (poscolIndices[v2 + pCount] + 1) + "/"
                                                 + (uvIndices    [v2 + uCount] + 1) + "/"
                                                 + (normalIndices[v2 + nCount] + 1) + " "
                                                 + (poscolIndices[v3 + pCount] + 1) + "/"
                                                 + (uvIndices    [v3 + uCount] + 1) + "/"
                                                 + (normalIndices[v3 + nCount] + 1) + " "
                                                 + (poscolIndices[v4 + pCount] + 1) + "/"
                                                 + (uvIndices    [v4 + uCount] + 1) + "/"
                                                 + (normalIndices[v4 + nCount] + 1));
                            }
                            faceCount++;
                        }
                    }
                    pCount += mesh.Positions.Count;
                    uCount += mesh.UV.Count;
                    nCount += mesh.Normals.Count;

                    writer.WriteLine("# " + faceCount + " faces total.\n");
                }
            }

            using (var writer = new StreamWriter(materialPath, false))
            {
                writer.WriteLine("# Exported by Tomb Editor " +
                                 Assembly.GetExecutingAssembly().GetName().Version.ToString() + "\n");

                foreach (var material in model.UsedMaterials)
                {
                    writer.WriteLine("newmtl " + material.Name);
                    writer.WriteLine("    Ka 1.000000 1.000000 1.000000");
                    writer.WriteLine("    Kd 1.000000 1.000000 1.000000");
                    writer.WriteLine("    Ni 1.000000");
                    writer.WriteLine("    Ns 10.000000");
                    writer.WriteLine("    d " + (material.AdditiveBlending ? "0.500000" : "1.000000"));
                    writer.WriteLine("    illum 2");
                    writer.WriteLine("    map_Ka " + material.TexturePath);
                    writer.WriteLine("    map_Kd " + material.TexturePath);
                    writer.WriteLine("\n");
                }
            }

            return(true);
        }
Beispiel #9
0
        public override IOScene GetIOModel()
        {
            IOScene scene = new IOScene();

            IOModel iomodel = new IOModel();

            scene.Models.Add(iomodel);

            iomodel.Skeleton = ((SBSkeleton)Skeleton).ToIOSkeleton();

            // bone indices
            List <SBHsdBone> bones = new List <SBHsdBone>();

            foreach (SBHsdBone bone in Skeleton.Bones)
            {
                bones.Add(bone);
            }


            // gather textures
            Dictionary <HSDStruct, string> tobjToName = new Dictionary <HSDStruct, string>();

            List <SBSurface> textures = new List <SBSurface>();

            foreach (var tex in tobjToSurface)
            {
                tex.Value.Name = $"TOBJ_{textures.Count}";
                tobjToName.Add(tex.Key, tex.Value.Name);
                textures.Add(tex.Value);
            }


            // process mesh
            foreach (SBHsdMesh me in GetMeshObjects())
            {
                var dobj = me.DOBJ;

                var parent = Skeleton.Bones[0];
                foreach (var b in Skeleton.Bones)
                {
                    if (b is SBHsdBone bone)
                    {
                        if (bone.GetJOBJ().Dobj != null)
                        {
                            if (bone.GetJOBJ().Dobj.List.Contains(dobj))
                            {
                                parent = b;
                                break;
                            }
                        }
                    }
                }

                var iomesh = new IOMesh();
                iomesh.Name = me.Name;
                iomodel.Meshes.Add(iomesh);
                IOPolygon poly = new IOPolygon();
                iomesh.Polygons.Add(poly);

                if (dobj.Pobj != null)
                {
                    foreach (var pobj in dobj.Pobj.List)
                    {
                        var dl       = pobj.ToDisplayList();
                        var vertices = GX_VertexAccessor.GetDecodedVertices(dl, pobj);

                        HSD_Envelope[] bindGroups = null;;
                        if (pobj.EnvelopeWeights != null)
                        {
                            bindGroups = pobj.EnvelopeWeights;
                        }

                        var offset = 0;
                        foreach (var v in dl.Primitives)
                        {
                            List <GX_Vertex> strip = new List <GX_Vertex>();
                            for (int i = 0; i < v.Count; i++)
                            {
                                strip.Add(vertices[offset + i]);
                            }
                            offset += v.Count;
                            iomesh.Vertices.AddRange(ConvertGXDLtoTriangleList(v.PrimitiveType, SBHsdMesh.GXVertexToHsdVertex(strip, bones, bindGroups), (SBHsdBone)parent));
                        }
                    }
                }


                // flip faces
                for (int i = 0; i < iomesh.Vertices.Count; i += 3)
                {
                    if (i + 2 < iomesh.Vertices.Count)
                    {
                        poly.Indicies.Add(i + 2);
                        poly.Indicies.Add(i + 1);
                        poly.Indicies.Add(i);
                    }
                    else
                    {
                        break;
                    }
                }

                poly.MaterialName = iomesh.Name + "_material";


                // create material
                IOMaterial mat = new IOMaterial();

                mat.Name = iomesh.Name + "_material";
                if (dobj.Mobj.Material != null)
                {
                    mat.DiffuseColor = new System.Numerics.Vector4(
                        dobj.Mobj.Material.DiffuseColor.R / 255f,
                        dobj.Mobj.Material.DiffuseColor.G / 255f,
                        dobj.Mobj.Material.DiffuseColor.B / 255f,
                        dobj.Mobj.Material.DiffuseColor.A / 255f);
                    mat.SpecularColor = new System.Numerics.Vector4(
                        dobj.Mobj.Material.SpecularColor.R / 255f,
                        dobj.Mobj.Material.SpecularColor.G / 255f,
                        dobj.Mobj.Material.SpecularColor.B / 255f,
                        dobj.Mobj.Material.SpecularColor.A / 255f);
                    mat.AmbientColor = new System.Numerics.Vector4(
                        dobj.Mobj.Material.AmbientColor.R / 255f,
                        dobj.Mobj.Material.AmbientColor.G / 255f,
                        dobj.Mobj.Material.AmbientColor.B / 255f,
                        dobj.Mobj.Material.AmbientColor.A / 255f);
                    mat.Alpha     = dobj.Mobj.Material.Alpha;
                    mat.Shininess = dobj.Mobj.Material.Shininess;
                }

                if (dobj.Mobj.Textures != null)
                {
                    mat.DiffuseMap = new IOTexture()
                    {
                        Name     = tobjToName[dobj.Mobj.Textures._s],
                        FilePath = tobjToName[dobj.Mobj.Textures._s]
                    }
                }
                ;
                scene.Materials.Add(mat);
            }

            return(scene);
        }
Beispiel #10
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="scene"></param>
        /// <param name="filePath"></param>
        private void LoadMaterialLibrary(IOScene scene, string filePath)
        {
            using (FileStream stream = new FileStream(filePath, FileMode.Open))
                using (StreamReader r = new StreamReader(stream))
                {
                    IOMaterial currentMaterial = new IOMaterial();

                    while (!r.EndOfStream)
                    {
                        var args = Regex.Replace(r.ReadLine().Trim(), @"\s+", " ").Split(' ');

                        if (args.Length == 0)
                        {
                            continue;
                        }

                        switch (args[0])
                        {
                        case "newmtl":
                            currentMaterial = new IOMaterial()
                            {
                                Name = args[1]
                            };
                            scene.Materials.Add(currentMaterial);
                            break;

                        case "Ka":
                            currentMaterial.AmbientColor = new Vector4(float.Parse(args[1]), float.Parse(args[2]), float.Parse(args[3]), 1);
                            break;

                        case "Kd":
                            currentMaterial.DiffuseColor = new Vector4(float.Parse(args[1]), float.Parse(args[2]), float.Parse(args[3]), 1);
                            break;

                        case "Ks":
                            currentMaterial.SpecularColor = new Vector4(float.Parse(args[1]), float.Parse(args[2]), float.Parse(args[3]), 1);
                            break;

                        case "Ns":
                            currentMaterial.Shininess = float.Parse(args[1]);
                            break;

                        case "d":
                            currentMaterial.Alpha = float.Parse(args[1]);
                            break;

                        case "Tr":
                            currentMaterial.Alpha = 1 - float.Parse(args[1]);
                            break;

                        case "map_Ka":
                            currentMaterial.AmbientMap = new IOTexture()
                            {
                                Name     = currentMaterial.Name + "_texture",
                                FilePath = string.Join(" ", args, 1, args.Length - 1)
                            };
                            break;

                        case "map_Kd":
                            currentMaterial.DiffuseMap = new IOTexture()
                            {
                                Name     = currentMaterial.Name + "_texture",
                                FilePath = string.Join(" ", args, 1, args.Length - 1)
                            };
                            break;

                        case "map_Ks":
                            currentMaterial.SpecularMap = new IOTexture()
                            {
                                Name     = currentMaterial.Name + "_texture",
                                FilePath = string.Join(" ", args, 1, args.Length - 1)
                            };
                            break;
                        }
                    }
                }
        }
Beispiel #11
0
        public override IOModel ImportFromFile(string filename)
        {
            string path = Path.GetDirectoryName(filename);

            // Use Assimp.NET for importing model
            AssimpContext context = new AssimpContext();

            context.SetConfig(new NormalSmoothingAngleConfig(90.0f));
            Scene scene = context.ImportFile(filename, PostProcessPreset.TargetRealTimeMaximumQuality);

            var newModel = new IOModel();
            var textures = new Dictionary <int, Texture>();

            if (_settings.ProcessGeometry)
            {
                var tmpList = new List <IOMesh>();

                // Create the list of materials to load
                for (int i = 0; i < scene.Materials.Count; i++)
                {
                    var mat      = scene.Materials[i];
                    var material = new IOMaterial(mat.HasName ? mat.Name : "Material_" + i);

                    var diffusePath = mat.HasTextureDiffuse ? mat.TextureDiffuse.FilePath : null;
                    if (string.IsNullOrWhiteSpace(diffusePath))
                    {
                        continue;
                    }

                    // Don't add materials with missing textures
                    var texture = GetTexture(path, diffusePath);
                    if (texture == null)
                    {
                        logger.Warn("Texture for material " + mat.Name + " is missing. Meshes referencing this material won't be imported.");
                        continue;
                    }
                    else
                    {
                        textures.Add(i, texture);
                    }

                    // Create the new material
                    material.Texture          = textures[i];
                    material.AdditiveBlending = (mat.HasBlendMode && mat.BlendMode == global::Assimp.BlendMode.Additive) || mat.Opacity < 1.0f;
                    material.DoubleSided      = mat.HasTwoSided && mat.IsTwoSided;
                    material.Shininess        = mat.HasShininess ? (int)mat.Shininess : 0;
                    newModel.Materials.Add(material);
                }

                var lastBaseVertex = 0;

                // Loop for each mesh loaded in scene
                foreach (var mesh in scene.Meshes)
                {
                    // Discard nullmeshes
                    if (!mesh.HasFaces || !mesh.HasVertices || mesh.VertexCount < 3 ||
                        mesh.TextureCoordinateChannelCount == 0 || !mesh.HasTextureCoords(0))
                    {
                        logger.Warn("Mesh \"" + (mesh.Name ?? "") + "\" has no faces, no texture coordinates or wrong vertex count.");
                        continue;
                    }

                    // Import only textured meshes with valid materials
                    Texture faceTexture;
                    if (!textures.TryGetValue(mesh.MaterialIndex, out faceTexture))
                    {
                        logger.Warn("Mesh \"" + (mesh.Name ?? "") + "\" does have material index " + mesh.MaterialIndex + " which is unsupported or can't be found.");
                        continue;
                    }

                    // Make sure we have appropriate material in list. If not, skip mesh and warn user.
                    var material = newModel.Materials.FirstOrDefault(mat => mat.Name.Equals(scene.Materials[mesh.MaterialIndex].Name));
                    if (material == null)
                    {
                        logger.Warn("Can't find material with specified index (" + mesh.MaterialIndex + "). Probably you're missing textures or using non-diffuse materials only for this mesh.");
                        continue;
                    }

                    // Assimp's mesh is our IOSubmesh so we import meshes with just one submesh
                    var newMesh    = new IOMesh(mesh.Name);
                    var newSubmesh = new IOSubmesh(material);
                    newMesh.Submeshes.Add(material, newSubmesh);

                    bool hasColors  = _settings.UseVertexColor && mesh.VertexColorChannelCount > 0 && mesh.HasVertexColors(0);
                    bool hasNormals = mesh.HasNormals;

                    // Additional integrity checks
                    if ((mesh.VertexCount != mesh.TextureCoordinateChannels[0].Count) ||
                        (hasColors && mesh.VertexCount != mesh.VertexColorChannels[0].Count) ||
                        (hasNormals && mesh.VertexCount != mesh.Normals.Count))
                    {
                        logger.Warn("Mesh \"" + (mesh.Name ?? "") + "\" data structure is inconsistent.");
                        continue;
                    }

                    // Source data
                    var positions = mesh.Vertices;
                    var normals   = mesh.Normals;
                    var texCoords = mesh.TextureCoordinateChannels[0];
                    var colors    = mesh.VertexColorChannels[0];

                    for (int i = 0; i < mesh.VertexCount; i++)
                    {
                        // Create position
                        var position = new Vector3(positions[i].X, positions[i].Y, positions[i].Z);
                        position = ApplyAxesTransforms(position);
                        newMesh.Positions.Add(position);

                        // Create normal
                        if (hasNormals)
                        {
                            var normal = new Vector3(normals[i].X, normals[i].Y, normals[i].Z);
                            normal = ApplyAxesTransforms(normal);
                            newMesh.Normals.Add(normal);
                        }
                        else
                        {
                            newMesh.CalculateNormals();
                        }

                        // Create UV
                        var currentUV = new Vector2(texCoords[i].X, texCoords[i].Y);
                        if (faceTexture != null)
                        {
                            currentUV = ApplyUVTransform(currentUV, faceTexture.Image.Width, faceTexture.Image.Height);
                        }
                        newMesh.UV.Add(currentUV);

                        // Create colors
                        if (hasColors)
                        {
                            var color = ApplyColorTransform(new Vector4(colors[i].R, colors[i].G, colors[i].B, colors[i].A));
                            newMesh.Colors.Add(color);
                        }
                    }

                    // Add polygons
                    foreach (var face in mesh.Faces)
                    {
                        if (face.IndexCount == 3)
                        {
                            var poly = new IOPolygon(IOPolygonShape.Triangle);

                            poly.Indices.Add(lastBaseVertex + face.Indices[0]);
                            poly.Indices.Add(lastBaseVertex + face.Indices[1]);
                            poly.Indices.Add(lastBaseVertex + face.Indices[2]);

                            if (_settings.InvertFaces)
                            {
                                poly.Indices.Reverse();
                            }

                            newSubmesh.Polygons.Add(poly);
                        }
                        else if (face.IndexCount == 4)
                        {
                            var poly = new IOPolygon(IOPolygonShape.Quad);

                            poly.Indices.Add(lastBaseVertex + face.Indices[0]);
                            poly.Indices.Add(lastBaseVertex + face.Indices[1]);
                            poly.Indices.Add(lastBaseVertex + face.Indices[2]);
                            poly.Indices.Add(lastBaseVertex + face.Indices[3]);

                            if (_settings.InvertFaces)
                            {
                                poly.Indices.Reverse();
                            }

                            newSubmesh.Polygons.Add(poly);
                        }
                    }

                    tmpList.Add(newMesh);
                }

                // Sort meshes by name, if specified
                if (_settings.SortByName)
                {
                    tmpList = tmpList.OrderBy(m => m.Name, new CustomComparer <string>(NaturalComparer.Do)).ToList();
                }

                foreach (var mesh in tmpList)
                {
                    newModel.Meshes.Add(mesh);
                }
            }

            if (_settings.ProcessAnimations &&
                scene.HasAnimations && scene.AnimationCount > 0)
            {
                // Find all mesh nodes to count against animation nodes
                var meshNameList = CollectMeshNodeNames(scene.RootNode);

                // Sort animations by name, if specified
                if (_settings.SortByName)
                {
                    meshNameList = meshNameList.OrderBy(s => s, new CustomComparer <string>(NaturalComparer.Do)).ToList();
                }

                // Loop through all animations and add appropriate ones.
                // Integrity check: there should be meshes and mesh count should be equal to unique mesh name count.
                if (scene.MeshCount <= 0 || scene.MeshCount != meshNameList.Count)
                {
                    logger.Warn("Actual number of meshes doesn't correspond to mesh list. Animations won't be imported.");
                }
                else
                {
                    for (int i = 0; i < scene.AnimationCount; i++)
                    {
                        var anim = scene.Animations[i];

                        // Integrity check: support only time-based node animations
                        if (!anim.HasNodeAnimations || anim.DurationInTicks <= 0)
                        {
                            logger.Warn("Anim " + i + " isn't a valid type of animation for TR formats.");
                            continue;
                        }

                        // Guess possible maximum frame and time
                        var    frameCount  = 0;
                        double maximumTime = 0;
                        foreach (var node in anim.NodeAnimationChannels)
                        {
                            if (node.HasPositionKeys)
                            {
                                var maxNodeTime = node.PositionKeys.Max(key => key.Time);
                                maximumTime = maximumTime >= maxNodeTime ? maximumTime : maxNodeTime;
                                frameCount  = frameCount >= node.PositionKeyCount ? frameCount : node.PositionKeyCount;
                            }
                            if (node.HasRotationKeys)
                            {
                                var maxNodeTime = node.RotationKeys.Max(key => key.Time);
                                maximumTime = maximumTime >= maxNodeTime ? maximumTime : maxNodeTime;
                                frameCount  = frameCount >= node.RotationKeyCount ? frameCount : node.RotationKeyCount;
                            }
                        }

                        // Calculate time multiplier
                        var timeMult = (double)(frameCount - 1) / anim.DurationInTicks;

                        // Integrity check: maximum frame time shouldn't excess duration
                        if (timeMult * maximumTime >= frameCount)
                        {
                            logger.Warn("Anim " + i + " has frames outside of time limits and won't be imported.");
                            continue;
                        }

                        IOAnimation ioAnim = new IOAnimation(string.IsNullOrEmpty(anim.Name) ? "Imported animation " + i : anim.Name,
                                                             scene.MeshCount);

                        // Precreate frames and set them to identity
                        for (int j = 0; j < frameCount; j++)
                        {
                            ioAnim.Frames.Add(new IOFrame());
                        }

                        // Precreate rotations and set them to identity
                        // I am using generic foreach here instead of linq foreach because for some reason it
                        // returns wrong amount of angles during enumeration with Enumerable.Repeat.
                        foreach (var frame in ioAnim.Frames)
                        {
                            var angleList = Enumerable.Repeat(Vector3.Zero, scene.MeshCount);
                            frame.Angles.AddRange(angleList);
                        }

                        // Search through all nodes and put data into corresponding frames.
                        // It's not clear what should we do in case if multiple nodes refer to same mesh, but sometimes
                        // it happens, e. g. in case of fbx format. In this case, we'll just add to existing values for now.

                        foreach (var chan in anim.NodeAnimationChannels)
                        {
                            // Look if this channel belongs to any mesh in list.
                            // If so, attribute it to appropriate frame.
                            var chanIndex = meshNameList.IndexOf(item => chan.NodeName.Contains(item));

                            // Integrity check: no appropriate mesh found
                            if (chanIndex < 0)
                            {
                                logger.Warn("Anim " + i + " channel " + chan.NodeName + " has no corresponding mesh in meshtree and will be ignored");
                                continue;
                            }

                            // Apply translation only if found channel belongs to root mesh.
                            if (chanIndex == 0 && chan.HasPositionKeys && chan.PositionKeyCount > 0)
                            {
                                foreach (var key in chan.PositionKeys)
                                {
                                    // Integrity check: frame shouldn't fall out of keyframe array bounds.
                                    var frameIndex = (int)Math.Round(key.Time * timeMult, MidpointRounding.AwayFromZero);
                                    if (frameIndex >= frameCount)
                                    {
                                        logger.Warn("Anim " + i + " channel " + chan.NodeName + " has a key outside of time limits and will be ignored.");
                                        continue;
                                    }

                                    float rX = key.Value.X;
                                    float rY = key.Value.Y;
                                    float rZ = key.Value.Z;

                                    if (_settings.SwapXY)
                                    {
                                        var temp = rX; rX = rY; rY = temp;
                                    }
                                    if (_settings.SwapXZ)
                                    {
                                        var temp = rX; rX = rZ; rZ = temp;
                                    }
                                    if (_settings.SwapYZ)
                                    {
                                        var temp = rY; rY = rZ; rZ = temp;
                                    }

                                    if (_settings.FlipX)
                                    {
                                        rX = -rX;
                                    }
                                    if (_settings.FlipY)
                                    {
                                        rY = -rY;
                                    }
                                    if (_settings.FlipZ)
                                    {
                                        rZ = -rZ;
                                    }

                                    ioAnim.Frames[frameIndex].Offset += new Vector3(rX, rY, rZ);
                                }
                            }

                            if (chan.HasRotationKeys && chan.RotationKeyCount > 0)
                            {
                                foreach (var key in chan.RotationKeys)
                                {
                                    // Integrity check: frame shouldn't fall out of keyframe array bounds.
                                    var frameIndex = (int)Math.Round(key.Time * timeMult, MidpointRounding.AwayFromZero);
                                    if (frameIndex >= frameCount)
                                    {
                                        logger.Warn("Anim " + i + " channel " + chan.NodeName + " has a key outside of time limits and will be ignored.");
                                        continue;
                                    }

                                    // Convert quaternions back to rotations.
                                    // This is similar to TRViewer's conversion routine.

                                    var quatI = System.Numerics.Quaternion.Identity;
                                    var quat  = new System.Numerics.Quaternion(key.Value.X,
                                                                               key.Value.Z,
                                                                               key.Value.Y,
                                                                               -key.Value.W);
                                    quatI *= quat;

                                    var eulers   = MathC.QuaternionToEuler(quatI);
                                    var rotation = new Vector3(eulers.X * 180.0f / (float)Math.PI,
                                                               eulers.Y * 180.0f / (float)Math.PI,
                                                               eulers.Z * 180.0f / (float)Math.PI);

                                    ioAnim.Frames[frameIndex].Angles[chanIndex] += MathC.NormalizeAngle(rotation);
                                }
                            }
                        }

                        newModel.Animations.Add(ioAnim);
                    }
                }
            }

            return(newModel);
        }