/// <summary> /// Return the f line string (i.e. 1/1/1 2/2/2 3/3/3) /// </summary> /// <param name="vertIndexes"></param> /// <param name="indexesObj"></param> /// <returns></returns> private static string GetDataF(VertIndexesObj vertIndexes, LocalIndexesObj indexesObj) { const string strSpace = " "; string[] strIndexesF = new string[vertIndexes.VertIndexList.Count]; int i = 0; foreach (VertIndexObj vertIndex in vertIndexes.VertIndexList) { int?V = vertIndex.V; int?Vt = vertIndex.Vt; int?Vn = vertIndex.Vn; if (V != null) { V = V + 1 + indexesObj.vIndex; } if (Vt != null) { Vt = Vt + 1 + indexesObj.vtIndex; } if (Vn != null) { Vn = Vn + 1 + indexesObj.vnIndex; } strIndexesF[i] = GetIndexesF(V, Vt, Vn); // Add the 1/1/1 i++; } return(string.Join(strSpace, strIndexesF)); }
/// <summary> /// Return one object from the obj file /// </summary> /// <param name="listKeysValues"></param> /// <param name="allVertices"></param> /// <param name="startIndex"></param> /// <param name="endIndex"></param> /// <returns></returns> private static ObjectObj ObjectData(List <Tuple <string, string> > listKeysValues, AllVerticesDataObj allVertices, int startIndex, int endIndex) { LocalIndexesObj indexesObj = new LocalIndexesObj(); ObjectObj objectObj = new ObjectObj(); int i = startIndex; while (i < endIndex) { Tuple <string, string> keyValue = listKeysValues[i]; if (keyValue != null) { string key = keyValue.Item1; string value = keyValue.Item2.TrimEnd('\0').Trim(); // Remove the null character and any blank space if (ObjUtils.IsVertData(key)) // f { VerticeData(value, objectObj, allVertices, indexesObj); } else // Other key (o, g, s, usemtl) { switch (key) { case "usemtl": objectObj.MaterialName = value; break; case "o": objectObj.ObjectName = value; break; case "g": objectObj.GroupName = value; break; case "s": if (value != "off") { if (Int32.TryParse(value, out int s)) { objectObj.Smooth = s; } } break; default: break; } } } i++; } return(objectObj); }
/// <summary> /// Create the obj and mtl files with the given data /// </summary> /// <param name="objData">Data parsed from the obj file</param> /// <param name="mtlData">Data parsed from the mtl file</param> /// <param name="objFilename">Output path</param> /// <param name="makeMtl">Create a mtl file</param> /// <param name="useExistingMtl">Use the mtlData to create the mtl file</param> /// <returns></returns> public static bool WriteObj(ObjData objData, MtlData mtlData, string objFilename, bool makeMtl, bool useExistingMtl) { // objFilename has the .obj extension string directory = System.IO.Path.GetDirectoryName(objFilename); string noExtension = System.IO.Path.GetFileNameWithoutExtension(objFilename); string mtlRelative = string.Format("{0}.mtl", noExtension); string mtlFilename = System.IO.Path.Combine(directory, mtlRelative); List <string> mtlLines = new List <string>(); // To store the lines to append to the mtl file try { using (StreamWriter obj = new StreamWriter(objFilename)) { // mtllib, o, v, vt, g, usemtl, s, f obj.WriteLine(GenericUtils.GetCreditsFile()); if (makeMtl) { obj.WriteLine(ObjUtils.GetNewMtlLib(mtlRelative)); } LocalIndexesObj indexesObj = new LocalIndexesObj(); foreach (ObjectObj objectObj in objData.ObjectsList) { if (objectObj.ObjectName != null) { obj.WriteLine(ObjUtils.GetNewObject(objectObj.ObjectName)); // o } foreach (Point p in objectObj.VerticesList) { obj.WriteLine(ObjUtils.GetNewCoord(p.ToString())); // v } foreach (UVCoordinates uv in objectObj.UVsList) { obj.WriteLine(ObjUtils.GetNewTexCoord(uv.ToString())); // vt } foreach (Vector v in objectObj.NormalsList) { obj.WriteLine(ObjUtils.GetNewVertNormal(v.ToString())); // vn } if (objectObj.GroupName != null) { obj.WriteLine(ObjUtils.GetNewGroup(objectObj.GroupName)); // g } if (objectObj.MaterialName != null) { obj.WriteLine(ObjUtils.GetNewUseMtl(objectObj.MaterialName)); // usemtl // Store lines in the mtl array to append to the file later mtlLines.Add(MtlUtils.GetMtlData(objectObj.MaterialName, objectObj.TextureName)); } if (objectObj.Smooth == -1) { obj.WriteLine(ObjUtils.GetNewSmoothGroup()); // s } else { obj.WriteLine(ObjUtils.GetNewSmoothGroup(objectObj.Smooth)); // s } foreach (VertIndexesObj vertIndexes in objectObj.VertIndexesList) { obj.WriteLine(ObjUtils.GetNewF(GetDataF(vertIndexes, indexesObj))); // f } indexesObj.vIndex += objectObj.VerticesList.Count; indexesObj.vtIndex += objectObj.UVsList.Count; indexesObj.vnIndex += objectObj.NormalsList.Count; } } } catch { return(false); } if (makeMtl) // If we dont delete materials { if (useExistingMtl && mtlData != null) // Use the parsed mtl { return(MtlExporter.WriteMtl(mtlData, mtlFilename)); } else // Create a mtl from the data obtained in the obj { return(MtlExporter.WriteMtl(mtlLines, mtlFilename)); } } return(true); }
/// <summary> /// Store the f, v, vt and vn lines into the object /// </summary> /// <param name="value"></param> /// <param name="objectObj"></param> /// <param name="allVertices"></param> /// <param name="indexesObj"></param> private static void VerticeData(string value, ObjectObj objectObj, AllVerticesDataObj allVertices, LocalIndexesObj indexesObj) { VertIndexesObj vertIndexes = new VertIndexesObj(); foreach (string indexes in ObjUtils.SplitVertData(value)) { VertIndexObj vertIndex = new VertIndexObj(); string[] indexList = ObjUtils.SplitIndexes(indexes); int length = indexList.Length; for (int i = 0; i < length; i++) { int index = 0; if (indexList[i] != "") // the vt line can be empty { if (Int32.TryParse(indexList[i], out int tmpIndex)) // Get the index { index = tmpIndex; } } if (i == 0) // v { if (index != 0) { vertIndex.V = indexesObj.vIndex; string vLine = allVertices.GetVIndex(index - 1); // Obj index start at 1 if (vLine != null) { objectObj.VerticesList.Add(new Point(vLine)); indexesObj.vIndex++; } } } else if (i == 1) // vt { if (index != 0) { vertIndex.Vt = indexesObj.vtIndex; string vtLine = allVertices.GetVtIndex(index - 1); // Obj index start at 1 if (vtLine != null) { objectObj.UVsList.Add(new UVCoordinates(vtLine)); indexesObj.vtIndex++; } } } else if (i == 2) // vn { if (index != 0) { vertIndex.Vn = indexesObj.vnIndex; string vnLine = allVertices.GetVnIndex(index - 1); // Obj index start at 1 if (vnLine != null) { objectObj.NormalsList.Add(new Vector(vnLine)); indexesObj.vnIndex++; } } } } vertIndexes.VertIndexList.Add(vertIndex); } objectObj.VertIndexesList.Add(vertIndexes); }
/// <summary> /// Merge together every group in the array /// </summary> /// <param name="objData">Data parsed from the obj file</param> /// <param name="textureName">Path to the texture file</param> /// <param name="groups">List of groups index</param> /// <returns></returns> private static ObjectObj MergeObjects(ObjData objData, string textureName, List <int> groups) { int length = groups.Count; if (length >= 1) // Should always be the case { // If the texture name is a relative/absolute path to the file, we only keep the name string relativeTexture = System.IO.Path.GetFileName(textureName); ObjectObj objectObj = new ObjectObj(objData.ObjectsList[groups[0]]) { MaterialName = relativeTexture, // Materialname will be the same as the texture file GroupName = relativeTexture, ObjectName = relativeTexture, TextureName = textureName }; if (length == 1) // Only one group { return(objectObj); } else // More group to merge with the first one { LocalIndexesObj localIndexes = new LocalIndexesObj { vIndex = objectObj.VerticesList.Count, vtIndex = objectObj.UVsList.Count, vnIndex = objectObj.NormalsList.Count }; for (int i = 1; i < length; i++) { ObjectObj nextObjectObj = objData.ObjectsList[groups[i]]; foreach (Point p in nextObjectObj.VerticesList) { objectObj.VerticesList.Add(p); } foreach (UVCoordinates uv in nextObjectObj.UVsList) { objectObj.UVsList.Add(uv); } foreach (Vector v in nextObjectObj.NormalsList) { objectObj.NormalsList.Add(v); } foreach (VertIndexesObj vertIndexes in nextObjectObj.VertIndexesList) { foreach (VertIndexObj vertIndex in vertIndexes.VertIndexList) { if (vertIndex.V != null) { vertIndex.V += localIndexes.vIndex; } if (vertIndex.Vt != null) { vertIndex.Vt += localIndexes.vtIndex; } if (vertIndex.Vn != null) { vertIndex.Vn += localIndexes.vnIndex; } } objectObj.VertIndexesList.Add(vertIndexes); } localIndexes.vIndex += nextObjectObj.VerticesList.Count; localIndexes.vtIndex += nextObjectObj.UVsList.Count; localIndexes.vnIndex += nextObjectObj.NormalsList.Count; } return(objectObj); } } return(null); }
/// <summary> /// Calculate the normal vector for each triangle /// </summary> /// <param name="objData">Data parsed from the obj file</param> public static void CalculateNormal(ObjData objData) { foreach (ObjectObj objectObj in objData.ObjectsList) { // A triangle is made from 3 points LocalIndexesObj localIndexes = new LocalIndexesObj(); List <Vector> normalsList = objectObj.NormalsList; localIndexes.vnIndex = normalsList.Count; // Set the current max vnIndex List <Point> verticesList = objectObj.VerticesList; int verticesLength = verticesList.Count; foreach (VertIndexesObj vertIndexes in objectObj.VertIndexesList) { if (vertIndexes.VertIndexList.Count >= 3) // Should always be the case { VertIndexObj vertIndex1 = vertIndexes.VertIndexList[0]; VertIndexObj vertIndex2 = vertIndexes.VertIndexList[1]; VertIndexObj vertIndex3 = vertIndexes.VertIndexList[2]; // If a normal needs to be calculated if (vertIndex1.Vn == null || vertIndex2.Vn == null || vertIndex3.Vn == null) { // If all points indexes are correctly defined if (vertIndex1.V != null && vertIndex2.V != null && vertIndex3.V != null) { Point p1 = (vertIndex1.V < verticesLength) ? verticesList[(int)vertIndex1.V] : null; Point p2 = (vertIndex2.V < verticesLength) ? verticesList[(int)vertIndex2.V] : null; Point p3 = (vertIndex3.V < verticesLength) ? verticesList[(int)vertIndex3.V] : null; // If all indexes lead to existing points if (p1 != null && p2 != null && p3 != null) { Vector vector1 = new Vector(p1, p2); Vector vector2 = new Vector(p2, p3); Vector vectorNormal = Vector.GetNormalVector(vector1, vector2); normalsList.Add(vectorNormal.GetUnitVector()); // Add to the list the unit vector // We assign the index of the normal vector to if (vertIndex1.Vn == null) { vertIndex1.Vn = localIndexes.vnIndex; } if (vertIndex2.Vn == null) { vertIndex2.Vn = localIndexes.vnIndex; } if (vertIndex3.Vn == null) { vertIndex3.Vn = localIndexes.vnIndex; } // Increment the index for the next normal vector localIndexes.vnIndex++; } } } } } } }