public H3D ToH3D(string TextureAndMtlSearchPath = null) { H3D Output = new H3D(); Dictionary <string, OBJMaterial> Materials = new Dictionary <string, OBJMaterial>(); if (TextureAndMtlSearchPath != null) { string MaterialFile = Path.Combine(TextureAndMtlSearchPath, MtlFile); if (File.Exists(MaterialFile)) { string MaterialName = null; OBJMaterial Material = default(OBJMaterial); TextReader Reader = new StreamReader(MaterialFile); for (string Line; (Line = Reader.ReadLine()) != null;) { string[] Params = Line.Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries); if (Params.Length == 0) { continue; } switch (Params[0]) { case "newmtl": if (Params.Length > 1) { if (MaterialName != null && Material.DiffuseTexture != null) { Materials.Add(MaterialName, Material); } Material = new OBJMaterial(); MaterialName = Line.Substring(Line.IndexOf(" ")).Trim(); } break; case "map_Kd": if (Params.Length > 1) { string Name = Line.Substring(Line.IndexOf(Params[1])); string TextureFile = Path.Combine(TextureAndMtlSearchPath, Name); string TextureName = Path.GetFileNameWithoutExtension(TextureFile); if (File.Exists(TextureFile) && !Output.Textures.Contains(TextureName)) { Output.Textures.Add(new H3DTexture(TextureFile)); } Material.DiffuseTexture = Path.GetFileNameWithoutExtension(TextureName); } break; case "Ka": case "Kd": case "Ks": if (Params.Length >= 4) { Vector4 Color = new Vector4( float.Parse(Params[1], CultureInfo.InvariantCulture), float.Parse(Params[2], CultureInfo.InvariantCulture), float.Parse(Params[3], CultureInfo.InvariantCulture), 1); switch (Params[0]) { case "Ka": Material.Ambient = Color; break; case "Kd": Material.Diffuse = Color; break; case "Ks": Material.Specular = Color; break; } } break; } } Reader.Dispose(); if (MaterialName != null && Material.DiffuseTexture != null) { Materials.Add(MaterialName, Material); } } } H3DModel Model = new H3DModel(); Model.Name = "Model"; ushort MaterialIndex = 0; Model.Flags = H3DModelFlags.HasSkeleton; Model.BoneScaling = H3DBoneScaling.Maya; Model.MeshNodesVisibility.Add(true); float Height = 0; foreach (OBJMesh Mesh in Meshes) { Vector3 MinVector = new Vector3(); Vector3 MaxVector = new Vector3(); Dictionary <PICAVertex, int> Vertices = new Dictionary <PICAVertex, int>(); List <H3DSubMesh> SubMeshes = new List <H3DSubMesh>(); Queue <PICAVertex> VerticesQueue = new Queue <PICAVertex>(); foreach (PICAVertex Vertex in Mesh.Vertices) { VerticesQueue.Enqueue(Vertex); } while (VerticesQueue.Count > 2) { List <ushort> Indices = new List <ushort>(); while (VerticesQueue.Count > 0) { for (int Tri = 0; Tri < 3; Tri++) { PICAVertex Vertex = VerticesQueue.Dequeue(); if (Vertices.ContainsKey(Vertex)) { Indices.Add((ushort)Vertices[Vertex]); } else { Indices.Add((ushort)Vertices.Count); if (Vertex.Position.X < MinVector.X) { MinVector.X = Vertex.Position.X; } if (Vertex.Position.Y < MinVector.Y) { MinVector.Y = Vertex.Position.Y; } if (Vertex.Position.Z < MinVector.Z) { MinVector.Z = Vertex.Position.Z; } if (Vertex.Position.X > MaxVector.X) { MaxVector.X = Vertex.Position.X; } if (Vertex.Position.Y > MaxVector.Y) { MaxVector.Y = Vertex.Position.Y; } if (Vertex.Position.Z > MaxVector.Z) { MaxVector.Z = Vertex.Position.Z; } Vertices.Add(Vertex, Vertices.Count); } } } H3DSubMesh SM = new H3DSubMesh(); SM.BoneIndices = new ushort[] { 0 }; SM.Skinning = H3DSubMeshSkinning.Smooth; SM.Indices = Indices.ToArray(); SubMeshes.Add(SM); } //Mesh List <PICAAttribute> Attributes = PICAAttribute.GetAttributes( PICAAttributeName.Position, PICAAttributeName.Normal, PICAAttributeName.TexCoord0, PICAAttributeName.Color, PICAAttributeName.BoneIndex, PICAAttributeName.BoneWeight); H3DMesh M = new H3DMesh(Vertices.Keys, Attributes, SubMeshes) { Skinning = H3DMeshSkinning.Smooth, MeshCenter = (MinVector + MaxVector) * 0.5f, MaterialIndex = MaterialIndex }; if (Height < MaxVector.Y) { Height = MaxVector.Y; } //Material string MatName = $"Mat{MaterialIndex++.ToString("D5")}_{Mesh.MaterialName}"; H3DMaterial Material = H3DMaterial.GetSimpleMaterial(Model.Name, MatName, null); if (Materials.ContainsKey(Mesh.MaterialName)) { Material.Texture0Name = Materials[Mesh.MaterialName].DiffuseTexture; } else { Material.Texture0Name = "NoTexture"; } Model.Materials.Add(Material); M.UpdateBoolUniforms(Material); Model.AddMesh(M); } /* * On Pokémon, the root bone (on the animaiton file) is used by the game to move * characters around, and all rigged bones are parented to this bone. * It's usually the Waist bone, that points upward and is half the character height. */ Model.Skeleton.Add(new H3DBone( new Vector3(0, Height * 0.5f, 0), new Vector3(0, 0, (float)(Math.PI * 0.5)), Vector3.One, "Waist", -1)); Model.Skeleton[0].CalculateTransform(Model.Skeleton); Output.Models.Add(Model); Output.CopyMaterials(); return(Output); }