ExportOBJ
Author: DaveA, KeliHlodversson, tgraupmann, drobe
Description
Exports a GameObject and its child hierarchy's meshes to a Wavefront .OBJ file. This will export the meshes as you see it.
This is directly derived from the ObjExporter script.
Usage
You must place the script in a folder named Editor in your project's Assets folder for it to work properly.
Select an object in the scene hierarchy or a prefab in your project and then choose File -> Export -> Wavefront OBJ. Follow the save-file dialog to name and locate the intended exported .OBJ file.
A second option, File -> Export -> Wavefront OBJ (No Submeshes), will export the entire GameObject hierarchy as a single mesh. Use this option if you want to combine a prefab or object into a single mesh.
NOTE: This will only process a single GameObject selection at a time. If multiple GameObjects are selected, only the "first" one will be processed.
NOTE: The (No Submeshes) option does not trim faces, generate multi-materials, or even adjust UV coordinates. If you want to optimize or correct the mesh, you are encouraged to refer to a more specialized piece of software to handle that.
NOTE: the Wavefront .OBJ format does not have a concept of submesh offset, scale, or rotation, so every submesh will be rotated, scaled, offset, and then written. All of your meshes will be loaded into Unity with a (0,0,0) rotation, position, and scale.
C# - ObjExporter.cs
using UnityEngine; using UnityEditor; using System.Collections; using System.IO; using System.Text; public class ObjExporterScript { private static int StartIndex = 0; public static void Start() { StartIndex = 0; } public static void End() { StartIndex = 0; } public static string MeshToString(MeshFilter mf, Transform t) { Vector3 s = t.localScale; Vector3 p = t.localPosition; Quaternion r = t.localRotation; int numVertices = 0; Mesh m = mf.sharedMesh; if (!m) { return "####Error####"; } Material[] mats = mf.renderer.sharedMaterials; StringBuilder sb = new StringBuilder(); foreach(Vector3 vv in m.vertices) { Vector3 v = t.TransformPoint(vv); numVertices++; sb.Append(string.Format("v {0} {1} {2}\n",v.x,v.y,-v.z)); } sb.Append("\n"); foreach(Vector3 nn in m.normals) { Vector3 v = r * nn; sb.Append(string.Format("vn {0} {1} {2}\n",-v.x,-v.y,v.z)); } sb.Append("\n"); foreach(Vector3 v in m.uv) { sb.Append(string.Format("vt {0} {1}\n",v.x,v.y)); } for (int material=0; material < m.subMeshCount; material ++) { sb.Append("\n"); sb.Append("usemtl ").Append(mats[material].name).Append("\n"); sb.Append("usemap ").Append(mats[material].name).Append("\n"); int[] triangles = m.GetTriangles(material); for (int i=0;i<triangles.Length;i+=3) { sb.Append(string.Format("f {0}/{0}/{0} {1}/{1}/{1} {2}/{2}/{2}\n", triangles[i]+1+StartIndex, triangles[i+1]+1+StartIndex, triangles[i+2]+1+StartIndex)); } } StartIndex += numVertices; return sb.ToString(); } } public class ObjExporter : ScriptableObject { [MenuItem ("File/Export/Wavefront OBJ")] static void DoExportWSubmeshes() { DoExport(true); } [MenuItem ("File/Export/Wavefront OBJ (No Submeshes)")] static void DoExportWOSubmeshes() { DoExport(false); } static void DoExport(bool makeSubmeshes) { if (Selection.gameObjects.Length == 0) { Debug.Log("Didn't Export Any Meshes; Nothing was selected!"); return; } string meshName = Selection.gameObjects[0].name; string fileName = EditorUtility.SaveFilePanel("Export .obj file", "", meshName, "obj"); ObjExporterScript.Start(); StringBuilder meshString = new StringBuilder(); meshString.Append("#" + meshName + ".obj" + "\n#" + System.DateTime.Now.ToLongDateString() + "\n#" + System.DateTime.Now.ToLongTimeString() + "\n#-------" + "\n\n"); Transform t = Selection.gameObjects[0].transform; Vector3 originalPosition = t.position; t.position = Vector3.zero; if (!makeSubmeshes) { meshString.Append("g ").Append(t.name).Append("\n"); } meshString.Append(processTransform(t, makeSubmeshes)); WriteToFile(meshString.ToString(),fileName); t.position = originalPosition; ObjExporterScript.End(); Debug.Log("Exported Mesh: " + fileName); } static string processTransform(Transform t, bool makeSubmeshes) { StringBuilder meshString = new StringBuilder(); meshString.Append("#" + t.name + "\n#-------" + "\n"); if (makeSubmeshes) { meshString.Append("g ").Append(t.name).Append("\n"); } MeshFilter mf = t.GetComponent<MeshFilter>(); if (mf) { meshString.Append(ObjExporterScript.MeshToString(mf, t)); } for(int i = 0; i < t.childCount; i++) { meshString.Append(processTransform(t.GetChild(i), makeSubmeshes)); } return meshString.ToString(); } static void WriteToFile(string s, string filename) { using (StreamWriter sw = new StreamWriter(filename)) { sw.Write(s); } } }