Skip to content

Instantly share code, notes, and snippets.

@MattRix
Last active June 21, 2024 06:31
Show Gist options
  • Save MattRix/0522c27ee44c0fbbdf76d65de123eeff to your computer and use it in GitHub Desktop.
Save MattRix/0522c27ee44c0fbbdf76d65de123eeff to your computer and use it in GitHub Desktop.
Exports Unity meshes to an obj file
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.GetComponent<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 != null)
{
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);
}
}
}
@radiatoryang
Copy link

radiatoryang commented Jun 20, 2022

for anyone who gets here via Google -- just fyi, Unity won't import OBJ submeshes separately unless there's a .MTL file, among other possible problems... see https://forum.unity.com/threads/importing-obj-file-with-submeshes.724640/#post-8220573

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment