//TODO needs to be changed to account for single points /// <summary> /// Turns a bunch of random numbers into valid barycentric coordinates /// </summary> /// <param name="one"></param> /// <param name="two"></param> /// <param name="three"></param> /// <returns></returns> static string[] toBary(Bary b) { double[] bary = { 1, 1, 1, 1, 1, 1, 1, 1, 1 }; //Points /*if (baryArr[index, 0] > 0 && baryArr[index, 4] <= 0 && baryArr[index, 5] <= 0) * { * * bary[1] = 0; * bary[4] = baryArr[index, 0]; * bary[7] = baryArr[index, 0]; * * } * * if (baryArr[index, 1] > 0 && baryArr[index, 3] <= 0 && baryArr[index, 5] <= 0) * { * bary[2] = baryArr[index, 1]; * bary[5] = 0; * bary[8] = baryArr[index, 1]; * } * * if (baryArr[index, 2] > 0 && baryArr[index, 3] <= 0 && baryArr[index, 4] <= 0) * { * bary[0] = baryArr[index, 2]; * bary[3] = baryArr[index, 2]; * bary[6] = 0; * }*/ //Lines if (b.l0 > 0) { bary[0] = b.l0; bary[3] = 0; bary[6] = 0; } if (b.l1 > 0) { bary[1] = 0; bary[4] = b.l1; bary[7] = 0; } if (b.l2 > 0) { bary[2] = 0; bary[5] = 0; bary[8] = b.l2; } string[] baryString = new string[3]; for (int i = 0, c = 0; i < 9; i += 3, c++) { baryString[c] = bary[i] + "," + bary[i + 1] + "," + bary[i + 2] + ","; } return(baryString); }
static int nullBonesC = 0; //TODO remove this counter public static void Main(string[] args) { //Dir if (Directory.Exists("./obj")) { Console.WriteLine("Directory Found"); } else { printError("Creating Dir"); Directory.CreateDirectory("./obj"); } //File Input string fileName = "./obj/" + getUserInput("File name"); if (fileName == "./obj/") { string[] possibleFiles = Directory.GetFiles("./obj"); foreach (string currFileName in possibleFiles) { if (!currFileName.EndsWith(".txt") && !currFileName.EndsWith(".js")) { fileName = currFileName; break; } } } else { string[] possibleFiles = Directory.GetFiles("./obj"); foreach (string currFileName in possibleFiles) { if (!currFileName.Contains("fileName")) { fileName = currFileName; break; } } } Console.WriteLine("Files found, starting to read them"); try { File.Delete("./obj/output.txt"); } catch (Exception e) { printError("No file to delete, ignore this error" + e); } //Create a new importer AssimpContext importer = new AssimpContext(); importer.SetConfig(new IFCUseCustomTriangulationConfig(true)); importer.SetConfig(new SortByPrimitiveTypeConfig(PrimitiveType.Line | PrimitiveType.Point)); importer.SetConfig(new VertexBoneWeightLimitConfig(4)); //This is how we add a configuration (each config is its own class) //NormalSmoothingAngleConfig config = new NormalSmoothingAngleConfig(66.0f); //importer.SetConfig(config); //This is how we add a logging callback LogStream logstream = new LogStream(delegate(String msg, String userData) { Console.WriteLine(msg); }); logstream.Attach(); //Import the model. All configs are set. The model //is imported, loaded into managed memory. Then the unmanaged memory is released, and everything is reset. //Triangulating is already being done //TODO aiProcess_JoinIdenticalVertices (Index buffer objects) scene = importer.ImportFile(fileName, PostProcessPreset.TargetRealTimeMaximumQuality | PostProcessSteps.FlipUVs | PostProcessSteps.OptimizeMeshes | PostProcessSteps.OptimizeGraph | PostProcessSteps.SortByPrimitiveType | PostProcessSteps.LimitBoneWeights); extractBones(scene.RootNode); createBoneTree(scene.RootNode, -1, Matrix4x4.Identity); parseNode(scene.RootNode); //End of example importer.Dispose(); adjVert = (Lookup <Vector3D, triAndVertIndex>)toLookup.ToLookup((item) => item.Key, (item) => item.Value); //First 3 => Point, Second 3 => Line //TODO Make this a bit better //For each triangle, store some bary coords Bary[] bary = new Bary[normals.Count]; //Filled with: default( int ) //Edit #region Bary coords and bones //Lines: for (int j = 0; j < toLookup.Count; j += 3) { Vector3D v0 = toLookup[j + 2].Key - toLookup[j + 1].Key; Vector3D v1 = toLookup[j + 2].Key - toLookup[j].Key; Vector3D v2 = toLookup[j + 1].Key - toLookup[j].Key; double area = Math.Abs(Vector3D.Cross(v1, v2).Length()) / 2; //Determinant of a 2D matrix, used to calculate the area of a parallelogram IEnumerable <triAndVertIndex> matchingVertices0 = adjVert[toLookup[j].Key]; IEnumerable <triAndVertIndex> matchingVertices1 = adjVert[toLookup[j + 1].Key]; IEnumerable <triAndVertIndex> matchingVertices2 = adjVert[toLookup[j + 2].Key]; //2 Matching points //TriIndex = triangle index of the adjacent triangle foreach (triAndVertIndex index in matchingVertices0) { //Oh, yeah! It's working! (Magic!) //TODO turn this into a function as well foreach (triAndVertIndex otherIndex in matchingVertices1) { //If it is part of the same line if (otherIndex.triIndex == index.triIndex) { double angleBetweenTriangles = (Vector3D.Dot(faceNormals[j / 3], faceNormals[otherIndex.triIndex])); if (angleBetweenTriangles < THRESHOLD) { //area = 1/2*base*height //2*area / base = height /* * dist = vec3(area / v0.Length(), 0, 0); * gl_Position = gl_PositionIn[0]; * EmitVertex(); * dist = vec3(0, area / v1.Length(), 0); * gl_Position = gl_PositionIn[1]; * EmitVertex(); * dist = vec3(0, 0, area / v2.Length()); * gl_Position = gl_PositionIn[2]; * EmitVertex();*/ bary[j / 3].l2 = area / v2.Length(); // 1;// angleBetweenTriangles + addTo; } //If we found the adjacent triangle, we can go to the next one break; } } } foreach (triAndVertIndex index in matchingVertices1) { foreach (triAndVertIndex otherIndex in matchingVertices2) { if (otherIndex.triIndex == index.triIndex) { double angleBetweenTriangles = (Vector3D.Dot(faceNormals[j / 3], faceNormals[otherIndex.triIndex])); if (angleBetweenTriangles < THRESHOLD) { bary[j / 3].l0 = area / v0.Length(); // TODO angleBetweenTriangles + addTo; } break; } } } foreach (triAndVertIndex index in matchingVertices2) { foreach (triAndVertIndex otherIndex in matchingVertices0) { if (otherIndex.triIndex == index.triIndex) { double angleBetweenTriangles = (Vector3D.Dot(faceNormals[j / 3], faceNormals[otherIndex.triIndex])); if (angleBetweenTriangles < THRESHOLD) { bary[j / 3].l1 = area / v1.Length(); // TODO angleBetweenTriangles + addTo; } break; } } } } //Draw the points as well for (int j = 0; j < toLookup.Count; j += 3) { Vector3D v0 = toLookup[j + 2].Key - toLookup[j + 1].Key; Vector3D v1 = toLookup[j + 2].Key - toLookup[j].Key; Vector3D v2 = toLookup[j + 1].Key - toLookup[j].Key; double area = Math.Abs(Vector3D.Cross(v1, v2).Length()) / 2; //Determinant of a 2D matrix, used to calculate the area of a parallelogram IEnumerable <triAndVertIndex> matchingVertices0 = adjVert[toLookup[j].Key]; IEnumerable <triAndVertIndex> matchingVertices1 = adjVert[toLookup[j + 1].Key]; IEnumerable <triAndVertIndex> matchingVertices2 = adjVert[toLookup[j + 2].Key]; /*int numberOfAdjBary = 0; * * //Index of the adjacent triangle * foreach (triAndVertIndex index in matchingVertices0) * { * //TODO turn this into a function as well * if ((bary[index.triIndex], ((index.vertIndex + 1) % 3) + 3] > 0 || bary[index.triIndex, ((index.vertIndex + 2) % 3) + 3] > 0) * && index.triIndex != j / 3) * { * numberOfAdjBary++; * } * } * //Every line is actually 2 lines * if (numberOfAdjBary >= 4) * { * //Now, we need to do the point calculations * double dist0 = area / v0.Length(); * //bary[j / 3, 0] = ; * } * numberOfAdjBary = 0; * foreach (triAndVertIndex index in matchingVertices1) * { * if ((bary[index.triIndex, ((index.vertIndex + 1) % 3) + 3] > 0 || bary[index.triIndex, ((index.vertIndex + 2) % 3) + 3] > 0) * && index.triIndex != j / 3) * { * numberOfAdjBary++; * } * } * if (numberOfAdjBary >= 4) * { * bary[j / 3, 1] = area / v1.Length(); * } * numberOfAdjBary = 0; * foreach (triAndVertIndex index in matchingVertices2) * { * if ((bary[index.triIndex, ((index.vertIndex + 1) % 3) + 3] > 0 || bary[index.triIndex, ((index.vertIndex + 2) % 3) + 3] > 0) * && index.triIndex != j / 3) * { * numberOfAdjBary++; * } * } * if (numberOfAdjBary >= 4) * { * bary[j / 3, 2] = area / v2.Length(); * }***/ } #endregion #if true //Create the output file StreamWriter JSONFile = File.CreateText("./obj/output.txt"); //Write to file JSONFile.Write("model = ["); bool firstTime = true; for (int j = 0, texCount = 0; j < vertices.Count; j++) { var index = j - texCount; Vector3D[] currVert = Program.vertices[j]; if (currVert.Length == 1) { if (firstTime) { JSONFile.Write("{"); firstTime = false; } else { JSONFile.Write("]},\n{"); } JSONFile.Write("name:\"" + texNames[(int)currVert[0].X] + "\",model:["); Console.Write(texNames[(int)currVert[0].X] + "---"); texCount++; } else { //Edit string[] baryCoordsOfTri = toBary(bary[index]); //Triangle for (int i = 0; i < 3; i++) { JSONFile.Write(Vec3DToString(currVert[i])); JSONFile.Write(UVToString(uvs[index][i])); JSONFile.Write(Vec3DToString(normals[index][i])); JSONFile.Write(baryCoordsOfTri[i]); bones[index][i].Weights[1] = 0; if (bones[index][i].BoneIDs[1] == -1) { bones[index][i].Weights[0] = 1; } if (bones[index][i].Weights[0] == 0.5) { bones[index][i].Weights[0] = 0.49f; } JSONFile.Write((bones[index][i].BoneIDs[0] + 0.5) + "," + (bones[index][i].BoneIDs[1] + 0.5) + "," + bones[index][i].Weights[0] + ","); if (bones[index][i].Weights[0] > 0.45 && bones[index][i].Weights[0] < 0.55) { //printError("W1: " + string.Join(",.,", bones[index][i].Weights)); } if (bones[index][i].Weights[0] > 0.9) { //printError("W1: " + string.Join(",.,", bones[index][i].Weights)); } } } } JSONFile.Write("]}];"); JSONFile.Close(); #endif StreamWriter bonesFile = File.CreateText("./obj/outputBones.txt"); //You are going to have to reorder the parts manually bonesFile.Write("bones = ["); foreach (BoneInfo boneNode in boneNodesList) { //TODO Number of bones (To nearest power of 2) //TODO Max number of influencing bones per vertex Quaternion rot, offsetRot; Vector3D translation, offsetTranslation; Vector3D scale, offsetScale; boneNode.localMat.Decompose(out scale, out rot, out translation); boneNode.BoneOffsetMatrix.Decompose(out offsetScale, out offsetRot, out offsetTranslation); //Console.WriteLine(QuaternionToString(rot) + "->\n" + MatToString1(rot.GetMatrix())); //Console.WriteLine(QuaternionToString(rot) + "->\n" + Matrix4x4.FromTranslation(translation)); //Don't use .ToString(), use a custom function! bonesFile.WriteLine( "{name:\"" + boneNode.Name + "\",parent:" + boneNode.Parent + ",pos:[" + Vec3DToString(translation, false) + "],qRot:[" + QuaternionToString(rot) + "],offsetPos:[" + Vec3DToString(offsetTranslation, false) + "],offsetRot:[" + QuaternionToString(offsetRot) + "]},"); } bonesFile.Write("];"); bonesFile.WriteLine("\nvar animations = [];"); bonesFile.Close(); try { File.Delete("./obj/output.js"); } catch (Exception) { }; try { File.Delete("./obj/outputBones.js"); } catch (Exception) { }; try { File.Move("./obj/output.txt", Path.ChangeExtension("./obj/output.txt", ".js")); } catch (Exception) { }; try { File.Move("./obj/outputBones.txt", Path.ChangeExtension("./obj/outputBones.txt", ".js")); } catch (Exception) { }; Console.WriteLine("Info: {0} Bones {1} vertices without bones", boneNodesList.Count, nullBonesC); Console.WriteLine("DONE!"); Console.Read(); }