/// <summary> /// Gets all the meshes and outputs to a string (even grabbing the child of each gameObject if includeChildren is true /// </summary> /// <returns>The mesh to string.</returns> /// <param name="gameObj">GameObject Parent.</param> /// <param name="materials">Every Material in the parent that can be accessed.</param> /// <param name="objects">The StringBuidler to create objects for the FBX file.</param> /// <param name="connections">The StringBuidler to create connections for the FBX file.</param> /// <param name="parentObject">Parent object, if left null this is the top parent.</param> /// <param name="parentModelId">Parent model id, 0 if top parent.</param> public static long GetMeshToString(GameObject gameObj, Material[] materials, ref StringBuilder objects, ref StringBuilder connections, GameObject parentObject = null, long parentModelId = 0, bool includeChildren = true, bool disableRotationAndScale = false) { StringBuilder tempObjectSb = new StringBuilder(); StringBuilder tempConnectionsSb = new StringBuilder(); long geometryId = GetRandomFBXId(); long modelId = GetRandomFBXId(); // Sees if there is a skinned mesh renderer or regular mesh. Skinned meshes are baked into whatever pose they have and are exported MeshFilter filter = gameObj.GetComponent <MeshFilter>(); SkinnedMeshRenderer skinnedMesh = gameObj.GetComponent <SkinnedMeshRenderer>(); Mesh meshToExport = new Mesh(); if (filter != null) { meshToExport = filter.sharedMesh; } else if (skinnedMesh != null) { meshToExport = new Mesh(); skinnedMesh.BakeMesh(meshToExport); } if (meshToExport == null) { Debug.LogError("Couldn't find a filter name"); } string meshName = gameObj.name; // A NULL parent means that the gameObject is at the top string isMesh = "Null"; if (meshToExport != null) { meshName = meshToExport.name; isMesh = "Mesh"; } if (meshName == "") { meshName = "Skinned Mesh " + Random.Range(0, 1000000); } if (parentModelId == 0) { tempConnectionsSb.AppendLine("\t;Model::" + meshName + ", Model::RootNode"); } else { tempConnectionsSb.AppendLine("\t;Model::" + meshName + ", Model::USING PARENT"); } tempConnectionsSb.AppendLine("\tC: \"OO\"," + modelId + "," + parentModelId); tempConnectionsSb.AppendLine(); tempObjectSb.AppendLine("\tModel: " + modelId + ", \"Model::" + gameObj.name + "\", \"" + isMesh + "\" {"); tempObjectSb.AppendLine("\t\tVersion: 232"); tempObjectSb.AppendLine("\t\tProperties70: {"); tempObjectSb.AppendLine("\t\t\tP: \"RotationOrder\", \"enum\", \"\", \"\",4"); tempObjectSb.AppendLine("\t\t\tP: \"RotationActive\", \"bool\", \"\", \"\",1"); tempObjectSb.AppendLine("\t\t\tP: \"InheritType\", \"enum\", \"\", \"\",1"); tempObjectSb.AppendLine("\t\t\tP: \"ScalingMax\", \"Vector3D\", \"Vector\", \"\",0,0,0"); tempObjectSb.AppendLine("\t\t\tP: \"DefaultAttributeIndex\", \"int\", \"Integer\", \"\",0"); // ===== Local Translation Offset ========= Vector3 position = gameObj.transform.localPosition; tempObjectSb.Append("\t\t\tP: \"Lcl Translation\", \"Lcl Translation\", \"\", \"A+\","); // Append the X Y Z coords to the system tempObjectSb.AppendFormat("{0},{1},{2}", position.x * -1, position.y, position.z); tempObjectSb.AppendLine(); // Rotates the object correctly from Unity space if (disableRotationAndScale == false) { Vector3 localRotation = gameObj.transform.localEulerAngles; tempObjectSb.AppendFormat("\t\t\tP: \"Lcl Rotation\", \"Lcl Rotation\", \"\", \"A+\",{0},{1},{2}", localRotation.x, localRotation.y * -1, -1 * localRotation.z); } else { tempObjectSb.AppendFormat("\t\t\tP: \"Lcl Rotation\", \"Lcl Rotation\", \"\", \"A+\",{0},{1},{2}", 0, 0, 0); } tempObjectSb.AppendLine(); // Adds the local scale of this object if (disableRotationAndScale == false) { Vector3 localScale = gameObj.transform.localScale; tempObjectSb.AppendFormat("\t\t\tP: \"Lcl Scaling\", \"Lcl Scaling\", \"\", \"A\",{0},{1},{2}", localScale.x, localScale.y, localScale.z); } else { tempObjectSb.AppendFormat("\t\t\tP: \"Lcl Scaling\", \"Lcl Scaling\", \"\", \"A\",{0},{1},{2}", 1, 1, 1); } tempObjectSb.AppendLine(); tempObjectSb.AppendLine("\t\t\tP: \"currentUVSet\", \"KString\", \"\", \"U\", \"map1\""); tempObjectSb.AppendLine("\t\t}"); tempObjectSb.AppendLine("\t\tShading: T"); tempObjectSb.AppendLine("\t\tCulling: \"CullingOff\""); tempObjectSb.AppendLine("\t}"); // Adds in geometry if it exists, if it it does not exist, this is a empty gameObject file and skips over this if (meshToExport != null) { Mesh mesh = meshToExport; // ================================= // General Geometry Info // ================================= // Generate the geometry information for the mesh created tempObjectSb.AppendLine("\tGeometry: " + geometryId + ", \"Geometry::\", \"Mesh\" {"); // ===== WRITE THE VERTICIES ===== Vector3[] verticies = mesh.vertices; int vertCount = mesh.vertexCount * 3; // <= because the list of points is just a list of comma seperated values, we need to multiply by three tempObjectSb.AppendLine("\t\tVertices: *" + vertCount + " {"); tempObjectSb.Append("\t\t\ta: "); for (int i = 0; i < verticies.Length; i++) { if (i > 0) { tempObjectSb.Append(","); } // Points in the verticies. We also reverse the x value because Unity has a reverse X coordinate tempObjectSb.AppendFormat("{0},{1},{2}", verticies[i].x * -1, verticies[i].y, verticies[i].z); } tempObjectSb.AppendLine(); tempObjectSb.AppendLine("\t\t} "); // ======= WRITE THE TRIANGLES ======== int triangleCount = mesh.triangles.Length; int[] triangles = mesh.triangles; tempObjectSb.AppendLine("\t\tPolygonVertexIndex: *" + triangleCount + " {"); // Write triangle indexes tempObjectSb.Append("\t\t\ta: "); for (int i = 0; i < triangleCount; i += 3) { if (i > 0) { tempObjectSb.Append(","); } // To get the correct normals, must rewind the triangles since we flipped the x direction tempObjectSb.AppendFormat("{0},{1},{2}", triangles[i], triangles[i + 2], (triangles[i + 1] * -1) - 1); // <= Tells the poly is ended } tempObjectSb.AppendLine(); tempObjectSb.AppendLine("\t\t} "); tempObjectSb.AppendLine("\t\tGeometryVersion: 124"); tempObjectSb.AppendLine("\t\tLayerElementNormal: 0 {"); tempObjectSb.AppendLine("\t\t\tVersion: 101"); tempObjectSb.AppendLine("\t\t\tName: \"\""); tempObjectSb.AppendLine("\t\t\tMappingInformationType: \"ByPolygonVertex\""); tempObjectSb.AppendLine("\t\t\tReferenceInformationType: \"Direct\""); // ===== WRITE THE NORMALS ========== Vector3[] normals = mesh.normals; tempObjectSb.AppendLine("\t\t\tNormals: *" + (triangleCount * 3) + " {"); tempObjectSb.Append("\t\t\t\ta: "); for (int i = 0; i < triangleCount; i += 3) { if (i > 0) { tempObjectSb.Append(","); } // To get the correct normals, must rewind the normal triangles like the triangles above since x was flipped Vector3 newNormal = normals[triangles[i]]; tempObjectSb.AppendFormat("{0},{1},{2},", newNormal.x * -1, // Switch normal as is tradition newNormal.y, newNormal.z); newNormal = normals[triangles[i + 2]]; tempObjectSb.AppendFormat("{0},{1},{2},", newNormal.x * -1, // Switch normal as is tradition newNormal.y, newNormal.z); newNormal = normals[triangles[i + 1]]; tempObjectSb.AppendFormat("{0},{1},{2}", newNormal.x * -1, // Switch normal as is tradition newNormal.y, newNormal.z); } tempObjectSb.AppendLine(); tempObjectSb.AppendLine("\t\t\t}"); tempObjectSb.AppendLine("\t\t}"); // ===== WRITE THE COLORS ===== bool containsColors = mesh.colors.Length == verticies.Length; if (containsColors) { Color[] colors = mesh.colors; Dictionary <Color, int> colorTable = new Dictionary <Color, int>(); // reducing amount of data by only keeping unique colors. int idx = 0; // build index table of all the different colors present in the mesh for (int i = 0; i < colors.Length; i++) { if (!colorTable.ContainsKey(colors[i])) { colorTable[colors[i]] = idx; idx++; } } tempObjectSb.AppendLine("\t\tLayerElementColor: 0 {"); tempObjectSb.AppendLine("\t\t\tVersion: 101"); tempObjectSb.AppendLine("\t\t\tName: \"Col\""); tempObjectSb.AppendLine("\t\t\tMappingInformationType: \"ByPolygonVertex\""); tempObjectSb.AppendLine("\t\t\tReferenceInformationType: \"IndexToDirect\""); tempObjectSb.AppendLine("\t\t\tColors: *" + colorTable.Count * 4 + " {"); tempObjectSb.Append("\t\t\t\ta: "); bool first = true; foreach (KeyValuePair <Color, int> color in colorTable) { if (!first) { tempObjectSb.Append(","); } tempObjectSb.AppendFormat("{0},{1},{2},{3}", color.Key.r, color.Key.g, color.Key.b, color.Key.a); first = false; } tempObjectSb.AppendLine(); tempObjectSb.AppendLine("\t\t\t\t}"); // Color index tempObjectSb.AppendLine("\t\t\tColorIndex: *" + triangles.Length + " {"); tempObjectSb.Append("\t\t\t\ta: "); for (int i = 0; i < triangles.Length; i += 3) { if (i > 0) { tempObjectSb.Append(","); } // Triangles need to be fliped for the x flip int index1 = triangles[i]; int index2 = triangles[i + 2]; int index3 = triangles[i + 1]; // Find the color index related to that vertice index index1 = colorTable[colors[index1]]; index2 = colorTable[colors[index2]]; index3 = colorTable[colors[index3]]; tempObjectSb.AppendFormat("{0},{1},{2}", index1, index2, index3); } tempObjectSb.AppendLine(); tempObjectSb.AppendLine("\t\t\t}"); tempObjectSb.AppendLine("\t\t}"); } else { Debug.LogWarning("Mesh contains " + mesh.vertices.Length + " vertices for " + mesh.colors.Length + " colors. Skip color export"); } // ================ UV CREATION ========================= // -- UV 1 Creation int uvLength = mesh.uv.Length; Vector2[] uvs = mesh.uv; tempObjectSb.AppendLine("\t\tLayerElementUV: 0 {"); // the Zero here is for the first UV map tempObjectSb.AppendLine("\t\t\tVersion: 101"); tempObjectSb.AppendLine("\t\t\tName: \"map1\""); tempObjectSb.AppendLine("\t\t\tMappingInformationType: \"ByPolygonVertex\""); tempObjectSb.AppendLine("\t\t\tReferenceInformationType: \"IndexToDirect\""); tempObjectSb.AppendLine("\t\t\tUV: *" + uvLength * 2 + " {"); tempObjectSb.Append("\t\t\t\ta: "); for (int i = 0; i < uvLength; i++) { if (i > 0) { tempObjectSb.Append(","); } tempObjectSb.AppendFormat("{0},{1}", uvs[i].x, uvs[i].y); } tempObjectSb.AppendLine(); tempObjectSb.AppendLine("\t\t\t\t}"); // UV tile index coords tempObjectSb.AppendLine("\t\t\tUVIndex: *" + triangleCount + " {"); tempObjectSb.Append("\t\t\t\ta: "); for (int i = 0; i < triangleCount; i += 3) { if (i > 0) { tempObjectSb.Append(","); } // Triangles need to be fliped for the x flip int index1 = triangles[i]; int index2 = triangles[i + 2]; int index3 = triangles[i + 1]; tempObjectSb.AppendFormat("{0},{1},{2}", index1, index2, index3); } tempObjectSb.AppendLine(); tempObjectSb.AppendLine("\t\t\t}"); tempObjectSb.AppendLine("\t\t}"); // -- UV 2 Creation // TODO: Add UV2 Creation here // -- Smoothing // TODO: Smoothing doesn't seem to do anything when importing. This maybe should be added. -KBH // ============ MATERIALS ============= tempObjectSb.AppendLine("\t\tLayerElementMaterial: 0 {"); tempObjectSb.AppendLine("\t\t\tVersion: 101"); tempObjectSb.AppendLine("\t\t\tName: \"\""); tempObjectSb.AppendLine("\t\t\tMappingInformationType: \"ByPolygon\""); tempObjectSb.AppendLine("\t\t\tReferenceInformationType: \"IndexToDirect\""); int totalFaceCount = 0; // So by polygon means that we need 1/3rd of how many indicies we wrote. int numberOfSubmeshes = mesh.subMeshCount; StringBuilder submeshesSb = new StringBuilder(); // For just one submesh, we set them all to zero if (numberOfSubmeshes == 1) { int numFaces = triangles.Length / 3; for (int i = 0; i < numFaces; i++) { submeshesSb.Append("0,"); totalFaceCount++; } } else { List <int[]> allSubmeshes = new List <int[]>(); // Load all submeshes into a space for (int i = 0; i < numberOfSubmeshes; i++) { allSubmeshes.Add(mesh.GetIndices(i)); } // TODO: Optimize this search pattern for (int i = 0; i < triangles.Length; i += 3) { for (int subMeshIndex = 0; subMeshIndex < allSubmeshes.Count; subMeshIndex++) { bool breaker = false; for (int n = 0; n < allSubmeshes[subMeshIndex].Length; n += 3) { if (triangles[i] == allSubmeshes[subMeshIndex][n] && triangles[i + 1] == allSubmeshes[subMeshIndex][n + 1] && triangles[i + 2] == allSubmeshes[subMeshIndex][n + 2]) { submeshesSb.Append(subMeshIndex.ToString()); submeshesSb.Append(","); totalFaceCount++; break; } if (breaker) { break; } } } } } tempObjectSb.AppendLine("\t\t\tMaterials: *" + totalFaceCount + " {"); tempObjectSb.Append("\t\t\t\ta: "); tempObjectSb.AppendLine(submeshesSb.ToString()); tempObjectSb.AppendLine("\t\t\t} "); tempObjectSb.AppendLine("\t\t}"); // ============= INFORMS WHAT TYPE OF LATER ELEMENTS ARE IN THIS GEOMETRY ================= tempObjectSb.AppendLine("\t\tLayer: 0 {"); tempObjectSb.AppendLine("\t\t\tVersion: 100"); tempObjectSb.AppendLine("\t\t\tLayerElement: {"); tempObjectSb.AppendLine("\t\t\t\tType: \"LayerElementNormal\""); tempObjectSb.AppendLine("\t\t\t\tTypedIndex: 0"); tempObjectSb.AppendLine("\t\t\t}"); tempObjectSb.AppendLine("\t\t\tLayerElement: {"); tempObjectSb.AppendLine("\t\t\t\tType: \"LayerElementMaterial\""); tempObjectSb.AppendLine("\t\t\t\tTypedIndex: 0"); tempObjectSb.AppendLine("\t\t\t}"); tempObjectSb.AppendLine("\t\t\tLayerElement: {"); tempObjectSb.AppendLine("\t\t\t\tType: \"LayerElementTexture\""); tempObjectSb.AppendLine("\t\t\t\tTypedIndex: 0"); tempObjectSb.AppendLine("\t\t\t}"); if (containsColors) { tempObjectSb.AppendLine("\t\t\tLayerElement: {"); tempObjectSb.AppendLine("\t\t\t\tType: \"LayerElementColor\""); tempObjectSb.AppendLine("\t\t\t\tTypedIndex: 0"); tempObjectSb.AppendLine("\t\t\t}"); } tempObjectSb.AppendLine("\t\t\tLayerElement: {"); tempObjectSb.AppendLine("\t\t\t\tType: \"LayerElementUV\""); tempObjectSb.AppendLine("\t\t\t\tTypedIndex: 0"); tempObjectSb.AppendLine("\t\t\t}"); // TODO: Here we would add UV layer 1 for ambient occlusion UV file // tempObjectSb.AppendLine("\t\t\tLayerElement: {"); // tempObjectSb.AppendLine("\t\t\t\tType: \"LayerElementUV\""); // tempObjectSb.AppendLine("\t\t\t\tTypedIndex: 1"); // tempObjectSb.AppendLine("\t\t\t}"); tempObjectSb.AppendLine("\t\t}"); tempObjectSb.AppendLine("\t}"); // Add the connection for the model to the geometry so it is attached the right mesh tempConnectionsSb.AppendLine("\t;Geometry::, Model::" + mesh.name); tempConnectionsSb.AppendLine("\tC: \"OO\"," + geometryId + "," + modelId); tempConnectionsSb.AppendLine(); // Add the connection of all the materials in order of submesh MeshRenderer meshRenderer = gameObj.GetComponent <MeshRenderer>(); if (meshRenderer != null) { Material[] allMaterialsInThisMesh = meshRenderer.sharedMaterials; for (int i = 0; i < allMaterialsInThisMesh.Length; i++) { Material mat = allMaterialsInThisMesh[i]; int referenceId = Mathf.Abs(mat.GetInstanceID()); if (mat == null) { Debug.LogError("ERROR: the game object " + gameObj.name + " has an empty material on it. This will export problematic files. Please fix and reexport"); continue; } tempConnectionsSb.AppendLine("\t;Material::" + mat.name + ", Model::" + mesh.name); tempConnectionsSb.AppendLine("\tC: \"OO\"," + referenceId + "," + modelId); tempConnectionsSb.AppendLine(); } } } if (includeChildren == true) { // Recursively add all the other objects to the string that has been built. for (int i = 0; i < gameObj.transform.childCount; i++) { GameObject childObject = gameObj.transform.GetChild(i).gameObject; HiFiFBXUnityMeshGetter.GetMeshToString(childObject, materials, ref tempObjectSb, ref tempConnectionsSb, gameObj, modelId); } } objects.Append(tempObjectSb.ToString()); connections.Append(tempConnectionsSb.ToString()); return(modelId); }
/// <summary> /// Creates the FBX file from the GameObject given, and returns the string /// </summary> public static string MeshToString(GameObject gameObj, string newPath, bool exportRotationAndScale = true, bool doNotExportChildren = false, bool copyMaterials = false, bool copyTextures = false) { StringBuilder sb = new StringBuilder(); StringBuilder objectProps = new StringBuilder(); objectProps.AppendLine("; Object properties"); objectProps.AppendLine(";------------------------------------------------------------------"); objectProps.AppendLine(""); objectProps.AppendLine("Objects: {"); StringBuilder objectConnections = new StringBuilder(); objectConnections.AppendLine("; Object connections"); objectConnections.AppendLine(";------------------------------------------------------------------"); objectConnections.AppendLine(""); objectConnections.AppendLine("Connections: {"); objectConnections.AppendLine("\t"); Material[] materials = new Material[0]; // First finds all unique materials and compiles them (and writes to the object connections) for funzies string materialsObjectSerialized = ""; string materialConnectionsSerialized = ""; HiFiMatExporter.GetAllTopMaterialsToString(gameObj, newPath, copyTextures, out materials, out materialsObjectSerialized, out materialConnectionsSerialized); // Run recursive FBX Mesh grab over the entire gameobject HiFiFBXUnityMeshGetter.GetMeshToString(gameObj, materials, ref objectProps, ref objectConnections, null, 0, !doNotExportChildren, !exportRotationAndScale); // write the materials to the objectProps here. Should not do it in the above as it recursive. objectProps.Append(materialsObjectSerialized); objectConnections.Append(materialConnectionsSerialized); // Close up both builders; objectProps.AppendLine("}"); objectConnections.AppendLine("}"); // ========= Create header ======== // Intro sb.AppendLine("; FBX 7.3.0 project file"); sb.AppendLine("; Copyright (C) 1997-2010 Autodesk Inc. and/or its licensors."); sb.AppendLine("; All rights reserved."); sb.AppendLine("; ----------------------------------------------------"); sb.AppendLine(); // The header sb.AppendLine("FBXHeaderExtension: {"); sb.AppendLine("\tFBXHeaderVersion: 1003"); sb.AppendLine("\tFBXVersion: 7300"); // Creationg Date Stamp System.DateTime currentDate = System.DateTime.Now; sb.AppendLine("\tCreationTimeStamp: {"); sb.AppendLine("\t\tVersion: 1000"); sb.AppendLine("\t\tYear: " + currentDate.Year); sb.AppendLine("\t\tMonth: " + currentDate.Month); sb.AppendLine("\t\tDay: " + currentDate.Day); sb.AppendLine("\t\tHour: " + currentDate.Hour); sb.AppendLine("\t\tMinute: " + currentDate.Minute); sb.AppendLine("\t\tSecond: " + currentDate.Second); sb.AppendLine("\t\tMillisecond: " + currentDate.Millisecond); sb.AppendLine("\t}"); // Info on the Creator sb.AppendLine("\tCreator: \"" + VersionInformation + "\""); sb.AppendLine("\tSceneInfo: \"SceneInfo::GlobalInfo\", \"UserData\" {"); sb.AppendLine("\t\tType: \"UserData\""); sb.AppendLine("\t\tVersion: 100"); sb.AppendLine("\t\tMetaData: {"); sb.AppendLine("\t\t\tVersion: 100"); sb.AppendLine("\t\t\tTitle: \"\""); sb.AppendLine("\t\t\tSubject: \"\""); sb.AppendLine("\t\t\tAuthor: \"\""); sb.AppendLine("\t\t\tKeywords: \"\""); sb.AppendLine("\t\t\tRevision: \"\""); sb.AppendLine("\t\t\tComment: \"\""); sb.AppendLine("\t\t}"); sb.AppendLine("\t\tProperties70: {"); // Information on how this item was originally generated string documentInfoPaths = newPath; sb.AppendLine("\t\t\tP: \"DocumentUrl\", \"KString\", \"Url\", \"\", \"" + documentInfoPaths + "\""); sb.AppendLine("\t\t\tP: \"SrcDocumentUrl\", \"KString\", \"Url\", \"\", \"" + documentInfoPaths + "\""); sb.AppendLine("\t\t\tP: \"Original\", \"Compound\", \"\", \"\""); sb.AppendLine("\t\t\tP: \"Original|ApplicationVendor\", \"KString\", \"\", \"\", \"\""); sb.AppendLine("\t\t\tP: \"Original|ApplicationName\", \"KString\", \"\", \"\", \"\""); sb.AppendLine("\t\t\tP: \"Original|ApplicationVersion\", \"KString\", \"\", \"\", \"\""); sb.AppendLine("\t\t\tP: \"Original|DateTime_GMT\", \"DateTime\", \"\", \"\", \"\""); sb.AppendLine("\t\t\tP: \"Original|FileName\", \"KString\", \"\", \"\", \"\""); sb.AppendLine("\t\t\tP: \"LastSaved\", \"Compound\", \"\", \"\""); sb.AppendLine("\t\t\tP: \"LastSaved|ApplicationVendor\", \"KString\", \"\", \"\", \"\""); sb.AppendLine("\t\t\tP: \"LastSaved|ApplicationName\", \"KString\", \"\", \"\", \"\""); sb.AppendLine("\t\t\tP: \"LastSaved|ApplicationVersion\", \"KString\", \"\", \"\", \"\""); sb.AppendLine("\t\t\tP: \"LastSaved|DateTime_GMT\", \"DateTime\", \"\", \"\", \"\""); sb.AppendLine("\t\t}"); sb.AppendLine("\t}"); sb.AppendLine("}"); // The Global information sb.AppendLine("GlobalSettings: {"); sb.AppendLine("\tVersion: 1000"); sb.AppendLine("\tProperties70: {"); sb.AppendLine("\t\tP: \"UpAxis\", \"int\", \"Integer\", \"\",1"); sb.AppendLine("\t\tP: \"UpAxisSign\", \"int\", \"Integer\", \"\",1"); sb.AppendLine("\t\tP: \"FrontAxis\", \"int\", \"Integer\", \"\",2"); sb.AppendLine("\t\tP: \"FrontAxisSign\", \"int\", \"Integer\", \"\",1"); sb.AppendLine("\t\tP: \"CoordAxis\", \"int\", \"Integer\", \"\",0"); sb.AppendLine("\t\tP: \"CoordAxisSign\", \"int\", \"Integer\", \"\",1"); sb.AppendLine("\t\tP: \"OriginalUpAxis\", \"int\", \"Integer\", \"\",-1"); sb.AppendLine("\t\tP: \"OriginalUpAxisSign\", \"int\", \"Integer\", \"\",1"); sb.AppendLine("\t\tP: \"UnitScaleFactor\", \"double\", \"Number\", \"\",100"); // NOTE: This sets the resize scale upon import sb.AppendLine("\t\tP: \"OriginalUnitScaleFactor\", \"double\", \"Number\", \"\",100"); sb.AppendLine("\t\tP: \"AmbientColor\", \"ColorRGB\", \"Color\", \"\",0,0,0"); sb.AppendLine("\t\tP: \"DefaultCamera\", \"KString\", \"\", \"\", \"Producer Perspective\""); sb.AppendLine("\t\tP: \"TimeMode\", \"enum\", \"\", \"\",11"); sb.AppendLine("\t\tP: \"TimeSpanStart\", \"KTime\", \"Time\", \"\",0"); sb.AppendLine("\t\tP: \"TimeSpanStop\", \"KTime\", \"Time\", \"\",479181389250"); sb.AppendLine("\t\tP: \"CustomFrameRate\", \"double\", \"Number\", \"\",-1"); sb.AppendLine("\t}"); sb.AppendLine("}"); // The Object definations sb.AppendLine("; Object definitions"); sb.AppendLine(";------------------------------------------------------------------"); sb.AppendLine(""); sb.AppendLine("Definitions: {"); sb.AppendLine("\tVersion: 100"); sb.AppendLine("\tCount: 4"); sb.AppendLine("\tObjectType: \"GlobalSettings\" {"); sb.AppendLine("\t\tCount: 1"); sb.AppendLine("\t}"); sb.AppendLine("\tObjectType: \"Model\" {"); sb.AppendLine("\t\tCount: 1"); // TODO figure out if this count matters sb.AppendLine("\t\tPropertyTemplate: \"FbxNode\" {"); sb.AppendLine("\t\t\tProperties70: {"); sb.AppendLine("\t\t\t\tP: \"QuaternionInterpolate\", \"enum\", \"\", \"\",0"); sb.AppendLine("\t\t\t\tP: \"RotationOffset\", \"Vector3D\", \"Vector\", \"\",0,0,0"); sb.AppendLine("\t\t\t\tP: \"RotationPivot\", \"Vector3D\", \"Vector\", \"\",0,0,0"); sb.AppendLine("\t\t\t\tP: \"ScalingOffset\", \"Vector3D\", \"Vector\", \"\",0,0,0"); sb.AppendLine("\t\t\t\tP: \"ScalingPivot\", \"Vector3D\", \"Vector\", \"\",0,0,0"); sb.AppendLine("\t\t\t\tP: \"TranslationActive\", \"bool\", \"\", \"\",0"); sb.AppendLine("\t\t\t\tP: \"TranslationMin\", \"Vector3D\", \"Vector\", \"\",0,0,0"); sb.AppendLine("\t\t\t\tP: \"TranslationMax\", \"Vector3D\", \"Vector\", \"\",0,0,0"); sb.AppendLine("\t\t\t\tP: \"TranslationMinX\", \"bool\", \"\", \"\",0"); sb.AppendLine("\t\t\t\tP: \"TranslationMinY\", \"bool\", \"\", \"\",0"); sb.AppendLine("\t\t\t\tP: \"TranslationMinZ\", \"bool\", \"\", \"\",0"); sb.AppendLine("\t\t\t\tP: \"TranslationMaxX\", \"bool\", \"\", \"\",0"); sb.AppendLine("\t\t\t\tP: \"TranslationMaxY\", \"bool\", \"\", \"\",0"); sb.AppendLine("\t\t\t\tP: \"TranslationMaxZ\", \"bool\", \"\", \"\",0"); sb.AppendLine("\t\t\t\tP: \"RotationOrder\", \"enum\", \"\", \"\",0"); sb.AppendLine("\t\t\t\tP: \"RotationSpaceForLimitOnly\", \"bool\", \"\", \"\",0"); sb.AppendLine("\t\t\t\tP: \"RotationStiffnessX\", \"double\", \"Number\", \"\",0"); sb.AppendLine("\t\t\t\tP: \"RotationStiffnessY\", \"double\", \"Number\", \"\",0"); sb.AppendLine("\t\t\t\tP: \"RotationStiffnessZ\", \"double\", \"Number\", \"\",0"); sb.AppendLine("\t\t\t\tP: \"AxisLen\", \"double\", \"Number\", \"\",10"); sb.AppendLine("\t\t\t\tP: \"PreRotation\", \"Vector3D\", \"Vector\", \"\",0,0,0"); sb.AppendLine("\t\t\t\tP: \"PostRotation\", \"Vector3D\", \"Vector\", \"\",0,0,0"); sb.AppendLine("\t\t\t\tP: \"RotationActive\", \"bool\", \"\", \"\",0"); sb.AppendLine("\t\t\t\tP: \"RotationMin\", \"Vector3D\", \"Vector\", \"\",0,0,0"); sb.AppendLine("\t\t\t\tP: \"RotationMax\", \"Vector3D\", \"Vector\", \"\",0,0,0"); sb.AppendLine("\t\t\t\tP: \"RotationMinX\", \"bool\", \"\", \"\",0"); sb.AppendLine("\t\t\t\tP: \"RotationMinY\", \"bool\", \"\", \"\",0"); sb.AppendLine("\t\t\t\tP: \"RotationMinZ\", \"bool\", \"\", \"\",0"); sb.AppendLine("\t\t\t\tP: \"RotationMaxX\", \"bool\", \"\", \"\",0"); sb.AppendLine("\t\t\t\tP: \"RotationMaxY\", \"bool\", \"\", \"\",0"); sb.AppendLine("\t\t\t\tP: \"RotationMaxZ\", \"bool\", \"\", \"\",0"); sb.AppendLine("\t\t\t\tP: \"InheritType\", \"enum\", \"\", \"\",0"); sb.AppendLine("\t\t\t\tP: \"ScalingActive\", \"bool\", \"\", \"\",0"); sb.AppendLine("\t\t\t\tP: \"ScalingMin\", \"Vector3D\", \"Vector\", \"\",0,0,0"); sb.AppendLine("\t\t\t\tP: \"ScalingMax\", \"Vector3D\", \"Vector\", \"\",1,1,1"); sb.AppendLine("\t\t\t\tP: \"ScalingMinX\", \"bool\", \"\", \"\",0"); sb.AppendLine("\t\t\t\tP: \"ScalingMinY\", \"bool\", \"\", \"\",0"); sb.AppendLine("\t\t\t\tP: \"ScalingMinZ\", \"bool\", \"\", \"\",0"); sb.AppendLine("\t\t\t\tP: \"ScalingMaxX\", \"bool\", \"\", \"\",0"); sb.AppendLine("\t\t\t\tP: \"ScalingMaxY\", \"bool\", \"\", \"\",0"); sb.AppendLine("\t\t\t\tP: \"ScalingMaxZ\", \"bool\", \"\", \"\",0"); sb.AppendLine("\t\t\t\tP: \"GeometricTranslation\", \"Vector3D\", \"Vector\", \"\",0,0,0"); sb.AppendLine("\t\t\t\tP: \"GeometricRotation\", \"Vector3D\", \"Vector\", \"\",0,0,0"); sb.AppendLine("\t\t\t\tP: \"GeometricScaling\", \"Vector3D\", \"Vector\", \"\",1,1,1"); sb.AppendLine("\t\t\t\tP: \"MinDampRangeX\", \"double\", \"Number\", \"\",0"); sb.AppendLine("\t\t\t\tP: \"MinDampRangeY\", \"double\", \"Number\", \"\",0"); sb.AppendLine("\t\t\t\tP: \"MinDampRangeZ\", \"double\", \"Number\", \"\",0"); sb.AppendLine("\t\t\t\tP: \"MaxDampRangeX\", \"double\", \"Number\", \"\",0"); sb.AppendLine("\t\t\t\tP: \"MaxDampRangeY\", \"double\", \"Number\", \"\",0"); sb.AppendLine("\t\t\t\tP: \"MaxDampRangeZ\", \"double\", \"Number\", \"\",0"); sb.AppendLine("\t\t\t\tP: \"MinDampStrengthX\", \"double\", \"Number\", \"\",0"); sb.AppendLine("\t\t\t\tP: \"MinDampStrengthY\", \"double\", \"Number\", \"\",0"); sb.AppendLine("\t\t\t\tP: \"MinDampStrengthZ\", \"double\", \"Number\", \"\",0"); sb.AppendLine("\t\t\t\tP: \"MaxDampStrengthX\", \"double\", \"Number\", \"\",0"); sb.AppendLine("\t\t\t\tP: \"MaxDampStrengthY\", \"double\", \"Number\", \"\",0"); sb.AppendLine("\t\t\t\tP: \"MaxDampStrengthZ\", \"double\", \"Number\", \"\",0"); sb.AppendLine("\t\t\t\tP: \"PreferedAngleX\", \"double\", \"Number\", \"\",0"); sb.AppendLine("\t\t\t\tP: \"PreferedAngleY\", \"double\", \"Number\", \"\",0"); sb.AppendLine("\t\t\t\tP: \"PreferedAngleZ\", \"double\", \"Number\", \"\",0"); sb.AppendLine("\t\t\t\tP: \"LookAtProperty\", \"object\", \"\", \"\""); sb.AppendLine("\t\t\t\tP: \"UpVectorProperty\", \"object\", \"\", \"\""); sb.AppendLine("\t\t\t\tP: \"Show\", \"bool\", \"\", \"\",1"); sb.AppendLine("\t\t\t\tP: \"NegativePercentShapeSupport\", \"bool\", \"\", \"\",1"); sb.AppendLine("\t\t\t\tP: \"DefaultAttributeIndex\", \"int\", \"Integer\", \"\",-1"); sb.AppendLine("\t\t\t\tP: \"Freeze\", \"bool\", \"\", \"\",0"); sb.AppendLine("\t\t\t\tP: \"LODBox\", \"bool\", \"\", \"\",0"); sb.AppendLine("\t\t\t\tP: \"Lcl Translation\", \"Lcl Translation\", \"\", \"A\",0,0,0"); sb.AppendLine("\t\t\t\tP: \"Lcl Rotation\", \"Lcl Rotation\", \"\", \"A\",0,0,0"); sb.AppendLine("\t\t\t\tP: \"Lcl Scaling\", \"Lcl Scaling\", \"\", \"A\",1,1,1"); sb.AppendLine("\t\t\t\tP: \"Visibility\", \"Visibility\", \"\", \"A\",1"); sb.AppendLine("\t\t\t\tP: \"Visibility Inheritance\", \"Visibility Inheritance\", \"\", \"\",1"); sb.AppendLine("\t\t\t}"); sb.AppendLine("\t\t}"); sb.AppendLine("\t}"); // The geometry, this is IMPORTANT sb.AppendLine("\tObjectType: \"Geometry\" {"); sb.AppendLine("\t\tCount: 1"); // TODO - this must be set by the number of items being placed. sb.AppendLine("\t\tPropertyTemplate: \"FbxMesh\" {"); sb.AppendLine("\t\t\tProperties70: {"); sb.AppendLine("\t\t\t\tP: \"Color\", \"ColorRGB\", \"Color\", \"\",0.8,0.8,0.8"); sb.AppendLine("\t\t\t\tP: \"BBoxMin\", \"Vector3D\", \"Vector\", \"\",0,0,0"); sb.AppendLine("\t\t\t\tP: \"BBoxMax\", \"Vector3D\", \"Vector\", \"\",0,0,0"); sb.AppendLine("\t\t\t\tP: \"Primary Visibility\", \"bool\", \"\", \"\",1"); sb.AppendLine("\t\t\t\tP: \"Casts Shadows\", \"bool\", \"\", \"\",1"); sb.AppendLine("\t\t\t\tP: \"Receive Shadows\", \"bool\", \"\", \"\",1"); sb.AppendLine("\t\t\t}"); sb.AppendLine("\t\t}"); sb.AppendLine("\t}"); // The materials that are being placed. Has to be simple I think sb.AppendLine("\tObjectType: \"Material\" {"); sb.AppendLine("\t\tCount: 1"); sb.AppendLine("\t\tPropertyTemplate: \"FbxSurfacePhong\" {"); sb.AppendLine("\t\t\tProperties70: {"); sb.AppendLine("\t\t\t\tP: \"ShadingModel\", \"KString\", \"\", \"\", \"Phong\""); sb.AppendLine("\t\t\t\tP: \"MultiLayer\", \"bool\", \"\", \"\",0"); sb.AppendLine("\t\t\t\tP: \"EmissiveColor\", \"Color\", \"\", \"A\",0,0,0"); sb.AppendLine("\t\t\t\tP: \"EmissiveFactor\", \"Number\", \"\", \"A\",1"); sb.AppendLine("\t\t\t\tP: \"AmbientColor\", \"Color\", \"\", \"A\",0.2,0.2,0.2"); sb.AppendLine("\t\t\t\tP: \"AmbientFactor\", \"Number\", \"\", \"A\",1"); sb.AppendLine("\t\t\t\tP: \"DiffuseColor\", \"Color\", \"\", \"A\",0.8,0.8,0.8"); sb.AppendLine("\t\t\t\tP: \"DiffuseFactor\", \"Number\", \"\", \"A\",1"); sb.AppendLine("\t\t\t\tP: \"Bump\", \"Vector3D\", \"Vector\", \"\",0,0,0"); sb.AppendLine("\t\t\t\tP: \"NormalMap\", \"Vector3D\", \"Vector\", \"\",0,0,0"); sb.AppendLine("\t\t\t\tP: \"BumpFactor\", \"double\", \"Number\", \"\",1"); sb.AppendLine("\t\t\t\tP: \"TransparentColor\", \"Color\", \"\", \"A\",0,0,0"); sb.AppendLine("\t\t\t\tP: \"TransparencyFactor\", \"Number\", \"\", \"A\",0"); sb.AppendLine("\t\t\t\tP: \"DisplacementColor\", \"ColorRGB\", \"Color\", \"\",0,0,0"); sb.AppendLine("\t\t\t\tP: \"DisplacementFactor\", \"double\", \"Number\", \"\",1"); sb.AppendLine("\t\t\t\tP: \"VectorDisplacementColor\", \"ColorRGB\", \"Color\", \"\",0,0,0"); sb.AppendLine("\t\t\t\tP: \"VectorDisplacementFactor\", \"double\", \"Number\", \"\",1"); sb.AppendLine("\t\t\t\tP: \"SpecularColor\", \"Color\", \"\", \"A\",0.2,0.2,0.2"); sb.AppendLine("\t\t\t\tP: \"SpecularFactor\", \"Number\", \"\", \"A\",1"); sb.AppendLine("\t\t\t\tP: \"ShininessExponent\", \"Number\", \"\", \"A\",20"); sb.AppendLine("\t\t\t\tP: \"ReflectionColor\", \"Color\", \"\", \"A\",0,0,0"); sb.AppendLine("\t\t\t\tP: \"ReflectionFactor\", \"Number\", \"\", \"A\",1"); sb.AppendLine("\t\t\t}"); sb.AppendLine("\t\t}"); sb.AppendLine("\t}"); // Explanation of how textures work sb.AppendLine("\tObjectType: \"Texture\" {"); sb.AppendLine("\t\tCount: 2"); // TODO - figure out if this texture number is important sb.AppendLine("\t\tPropertyTemplate: \"FbxFileTexture\" {"); sb.AppendLine("\t\t\tProperties70: {"); sb.AppendLine("\t\t\t\tP: \"TextureTypeUse\", \"enum\", \"\", \"\",0"); sb.AppendLine("\t\t\t\tP: \"Texture alpha\", \"Number\", \"\", \"A\",1"); sb.AppendLine("\t\t\t\tP: \"CurrentMappingType\", \"enum\", \"\", \"\",0"); sb.AppendLine("\t\t\t\tP: \"WrapModeU\", \"enum\", \"\", \"\",0"); sb.AppendLine("\t\t\t\tP: \"WrapModeV\", \"enum\", \"\", \"\",0"); sb.AppendLine("\t\t\t\tP: \"UVSwap\", \"bool\", \"\", \"\",0"); sb.AppendLine("\t\t\t\tP: \"PremultiplyAlpha\", \"bool\", \"\", \"\",1"); sb.AppendLine("\t\t\t\tP: \"Translation\", \"Vector\", \"\", \"A\",0,0,0"); sb.AppendLine("\t\t\t\tP: \"Rotation\", \"Vector\", \"\", \"A\",0,0,0"); sb.AppendLine("\t\t\t\tP: \"Scaling\", \"Vector\", \"\", \"A\",1,1,1"); sb.AppendLine("\t\t\t\tP: \"TextureRotationPivot\", \"Vector3D\", \"Vector\", \"\",0,0,0"); sb.AppendLine("\t\t\t\tP: \"TextureScalingPivot\", \"Vector3D\", \"Vector\", \"\",0,0,0"); sb.AppendLine("\t\t\t\tP: \"CurrentTextureBlendMode\", \"enum\", \"\", \"\",1"); sb.AppendLine("\t\t\t\tP: \"UVSet\", \"KString\", \"\", \"\", \"default\""); sb.AppendLine("\t\t\t\tP: \"UseMaterial\", \"bool\", \"\", \"\",0"); sb.AppendLine("\t\t\t\tP: \"UseMipMap\", \"bool\", \"\", \"\",0"); sb.AppendLine("\t\t\t}"); sb.AppendLine("\t\t}"); sb.AppendLine("\t}"); sb.AppendLine("}"); sb.AppendLine(""); sb.Append(objectProps.ToString()); sb.Append(objectConnections.ToString()); return(sb.ToString()); }