public ObjFace(ObjFace face, ushort value) { Vertices = face.Vertices; Material = face.Material; CollisionAttribute = value; }
// ---- METHODS (PUBLIC) ------------------------------------------------------------------------------------- /// <summary> /// Creates a generic model which can be exported into a .obj file format. /// </summary> /// <returns></returns> public ObjModel CreateGenericModel() { ObjModel objModel = new ObjModel(); Dictionary <string, ObjMesh> meshes = new Dictionary <string, ObjMesh>(); bool spltByMaterial = true; foreach (KCLModel model in Models) { //Distinct check. Some cases prisims have a unique ID //Only split when they don't each have their own. var distinctPrisms = model.Prisms .GroupBy(p => p.CollisionFlags) .Select(g => g.First()) .ToList().Count; if (distinctPrisms == model.Prisms.Length) { spltByMaterial = false; } } var mesh = new ObjMesh($"Mesh"); if (!spltByMaterial) { objModel.Meshes.Add(mesh); } foreach (KCLModel model in Models) { foreach (var face in model.Prisms) { var triangle = model.GetTriangle(face); var normal = triangle.Normal; if (triangle.HasNan()) { continue; } ObjFace objFace = new ObjFace(); objFace.Material = $"COL_{face.CollisionFlags.ToString("X")}"; objFace.Vertices = new ObjVertex[3]; for (int i = 0; i < 3; i++) { objFace.Vertices[i] = new ObjVertex() { Position = triangle.Vertices[i], Normal = normal, }; } if (spltByMaterial) { if (!meshes.ContainsKey(objFace.Material)) { meshes.Add(objFace.Material, new ObjMesh(objFace.Material)); objModel.Meshes.Add(meshes[objFace.Material]); } meshes[objFace.Material].Faces.Add(objFace); } else { mesh.Faces.Add(objFace); } } } return(objModel); }
/// <summary> /// Loads the object file data from the given <paramref name="stream"/>. /// </summary> /// <param name="stream">The <see cref="Stream"/> to load the data from.</param> /// <param name="leaveOpen"><c>true</c> to leave <paramref name="stream"/> open after loading the instance. /// </param> public void Load(Stream stream) { DebugLogger.WriteLine($"Loading obj file...."); Meshes = new List <ObjMesh>(); Materials = new List <ObjMaterial>(); ObjMesh currentMesh = new ObjMesh("Mesh"); HashSet <string> faceHashes = new HashSet <string>(); Dictionary <ObjFace, int> faceDupes = new Dictionary <ObjFace, int>(); using (StreamReader reader = new StreamReader(stream, Encoding.UTF8)) { List <Vector3> Positions = new List <Vector3>(); List <Vector2> TexCoords = new List <Vector2>(); List <Vector3> Normals = new List <Vector3>(); var enusculture = new CultureInfo("en-US"); string currentMaterial = null; while (!reader.EndOfStream) { string line = reader.ReadLine(); line = line.Replace(",", "."); // Ignore empty lines and comments. if (String.IsNullOrWhiteSpace(line) || line.StartsWith("#")) { continue; } string[] args = line.Split(_argSeparators, StringSplitOptions.RemoveEmptyEntries); if (args.Length == 1) { continue; } switch (args[0]) { case "o": case "g": currentMesh = new ObjMesh(args.Length > 1 ? args[1] : $"Mesh{Meshes.Count}"); Meshes.Add(currentMesh); continue; case "v": Positions.Add(new Vector3( Single.Parse(args[1], enusculture), Single.Parse(args[2], enusculture), Single.Parse(args[3], enusculture))); continue; case "vt": TexCoords.Add(new Vector2( Single.Parse(args[1], enusculture), Single.Parse(args[2], enusculture))); continue; case "vn": Normals.Add(new Vector3( Single.Parse(args[1], enusculture), Single.Parse(args[2], enusculture), Single.Parse(args[3], enusculture))); continue; case "f": if (args.Length != 4) { throw new Exception("Obj must be trianglulated!"); } int[] indices = new int[3 * 2]; //3 faces, position and normal indices // Only support triangles for now. ObjFace face = new ObjFace() { Vertices = new ObjVertex[3] }; face.Material = currentMaterial; for (int i = 0; i < face.Vertices.Length; i++) { string[] vertexArgs = args[i + 1].Split(_vertexSeparators, StringSplitOptions.None); int positionIndex = Int32.Parse(vertexArgs[0]) - 1; face.Vertices[i].Position = Positions[positionIndex]; if (float.IsNaN(face.Vertices[i].Position.X) || float.IsNaN(face.Vertices[i].Position.Y) || float.IsNaN(face.Vertices[i].Position.Z)) { face.Vertices = null; break; } if (vertexArgs.Length > 1 && vertexArgs[1] != String.Empty) { face.Vertices[i].TexCoord = TexCoords[Int32.Parse(vertexArgs[1]) - 1]; } if (vertexArgs.Length > 2 && vertexArgs[2] != String.Empty) { face.Vertices[i].Normal = Normals[Int32.Parse(vertexArgs[2]) - 1]; } } string faceStr = face.ToString(); if (faceHashes.Contains(faceStr)) { continue; } faceHashes.Add(faceStr); if (face.Vertices != null) { currentMesh.Faces.Add(face); } continue; case "usemtl": { if (args.Length < 2) { continue; } currentMaterial = args[1]; continue; } } } } Console.WriteLine($"FACE COUNT {currentMesh.Faces.Count}"); faceDupes.Clear(); if (Meshes.Count == 0) //No object or groups present, use one single mesh { Meshes.Add(currentMesh); } }