Search Unity

Export Unity mesh to OBJ or FBX format

Discussion in 'Asset Importing & Exporting' started by JVed, Jan 15, 2014.

  1. JVed

    JVed

    Joined:
    Jan 15, 2014
    Posts:
    1
    Hi,

    I would like to export an Unity object (viewed in the scene) to an OBJ or FBX file format object.
    Could I do that easily ?

    Is there an Asset for that ?

    Thanks a lot.
    Joe.
     
  2. Deleted User

    Deleted User

    Guest

  3. justincrab

    justincrab

    Joined:
    Mar 18, 2018
    Posts:
    1
    Deprected
     
    mindq likes this.
  4. jeromeWork

    jeromeWork

    Joined:
    Sep 1, 2015
    Posts:
    429
  5. mgear

    mgear

    Joined:
    Aug 3, 2010
    Posts:
    9,406
  6. jeromeWork

    jeromeWork

    Joined:
    Sep 1, 2015
    Posts:
    429
  7. Edy

    Edy

    Joined:
    Jun 3, 2010
    Posts:
    2,508
    Last edited: May 15, 2020
    Maeslezo likes this.
  8. sxa

    sxa

    Joined:
    Aug 8, 2014
    Posts:
    741
    Edy likes this.
  9. hugogfadams

    hugogfadams

    Joined:
    Jul 27, 2020
    Posts:
    6
    I just used ObjExporter.cs and it works fine with changing one line. It will tell you it's deprecated but all you have to change is
    Code (CSharp):
    1. Material[] mats = mf.renderer.sharedMaterials;
    to
    Code (CSharp):
    1. Material[] mats = mf.GetComponent<Renderer>().sharedMaterials;
     
    Ony, Aurigan and gearedgeek like this.
  10. gearedgeek

    gearedgeek

    Joined:
    Jun 19, 2015
    Posts:
    236
  11. xofreshxo

    xofreshxo

    Joined:
    Apr 12, 2017
    Posts:
    79
    Edy likes this.
  12. triangle4studios

    triangle4studios

    Joined:
    Jun 28, 2020
    Posts:
    33
    Something really beneficial for you all to know.
    You can make your own obj. Its just a text file. No need for 3rd party applications and this gives you full control over your export.
    • v is your vertices(1 line per vert)
    • vn is your normals (1 face per line)
    • vt is your uvs (1 uv per line)
    • f is your faces, and is split into a triplet of numbers, the first being the vertex index, the second being the uv (vt) index and the third your normal index.
    https://en.wikipedia.org/wiki/Wavefront_.obj_file

    An example of a properly formatted .obj file:
    Code (CSharp):
    1. # Creator Name
    2. # Creator Website
    3. o NameOfObject
    4. v -1.000000 0.000000 1.000000
    5. v 1.000000 0.000000 1.000000
    6. v -1.000000 0.000000 -1.000000
    7. v 1.000000 0.000000 -1.000000
    8. vn -0.0000 1.0000 -0.0000
    9. vt 0.000000 0.000000
    10. vt 1.000000 0.000000
    11. vt 0.000000 1.000000
    12. vt 1.000000 1.000000
    13. s 0
    14. f 1/1/1 2/2/1 4/4/1 3/3/1
    Cheers
     
    Ony likes this.
  13. SteenPetersen

    SteenPetersen

    Joined:
    Mar 13, 2016
    Posts:
    103
    In case anyone needs it, I wrote a script that export as OBJ.


    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3. using System.Collections;
    4. using System.IO;
    5. using System.Text;
    6.  
    7. public class ExportMeshToOBJ : ScriptableObject
    8. {
    9.     [MenuItem("GameObject/Export to OBJ")]
    10.     static void ExportToOBJ()
    11.     {
    12.         GameObject obj = Selection.activeObject as GameObject;
    13.         if (obj == null)
    14.         {
    15.             Debug.Log("No object selected.");
    16.             return;
    17.         }
    18.  
    19.         MeshFilter meshFilter = obj.GetComponent<MeshFilter>();
    20.         if (meshFilter == null)
    21.         {
    22.             Debug.Log("No mesh found in selected GameObject.");
    23.             return;
    24.         }
    25.  
    26.         string path = EditorUtility.SaveFilePanel("Export OBJ", "", obj.name, "obj");
    27.         Mesh mesh = meshFilter.sharedMesh;
    28.         StringBuilder sb = new StringBuilder();
    29.  
    30.         foreach(Vector3 v in mesh.vertices)
    31.         {
    32.             sb.Append(string.Format("v {0} {1} {2}\n", v.x, v.y, v.z));
    33.         }
    34.         foreach(Vector3 v in mesh.normals)
    35.         {
    36.             sb.Append(string.Format("vn {0} {1} {2}\n", v.x, v.y, v.z));
    37.         }
    38.         for (int material=0; material < mesh.subMeshCount; material++)
    39.         {
    40.             sb.Append(string.Format("\ng {0}\n", obj.name));
    41.             int[] triangles = mesh.GetTriangles(material);
    42.             for (int i = 0; i < triangles.Length; i += 3)
    43.             {
    44.                 sb.Append(string.Format("f {0}/{0} {1}/{1} {2}/{2}\n",
    45.                 triangles[i] + 1,
    46.                 triangles[i + 1] + 1,
    47.                 triangles[i + 2] + 1));
    48.             }
    49.         }
    50.         StreamWriter writer = new StreamWriter(path);
    51.         writer.Write(sb.ToString());
    52.         writer.Close();
    53.     }
    54. }
    55.  
     
    Ony, GDevTeam, Tigrou777 and 2 others like this.
  14. ReDarkTechnology

    ReDarkTechnology

    Joined:
    Mar 30, 2020
    Posts:
    7
    Here's the modified version of the code that supports multiple selection if anyone need it
    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3. using System.IO;
    4. using System.Text;
    5.  
    6. public class ExportMeshToOBJ : ScriptableObject
    7. {
    8.     [MenuItem("GameObject/Export to OBJ")]
    9.     static void ExportToOBJ()
    10.     {
    11.         GameObject obj = Selection.activeObject as GameObject;
    12.         if (obj == null)
    13.         {
    14.             Debug.Log("No object selected.");
    15.             return;
    16.         }
    17.  
    18.         MeshFilter meshFilter = obj.GetComponent<MeshFilter>();
    19.         if (meshFilter == null)
    20.         {
    21.             Debug.Log("No MeshFilter is found in selected GameObject.", obj);
    22.             return;
    23.         }
    24.  
    25.         if (meshFilter.sharedMesh == null)
    26.         {
    27.             Debug.Log("No mesh is found in selected GameObject.", obj);
    28.             return;
    29.         }
    30.  
    31.         string path = EditorUtility.SaveFilePanel("Export OBJ", "", obj.name, "obj");
    32.         StreamWriter writer = new StreamWriter(path);
    33.         writer.Write(GetMeshOBJ(obj.name, meshFilter.sharedMesh));
    34.         writer.Close();
    35.     }
    36.  
    37.     [MenuItem("GameObject/Export to OBJs")]
    38.     static void ExportToOBJs()
    39.     {
    40.         var objs = Selection.gameObjects;
    41.         if (objs.Length < 1)
    42.         {
    43.             Debug.Log("No object selected.");
    44.             return;
    45.         }
    46.         var directory = EditorUtility.SaveFolderPanel("Export OBJs to", "", "OBJFiles");
    47.         foreach (var obj in objs)
    48.         {
    49.             MeshFilter meshFilter = obj.GetComponent<MeshFilter>();
    50.             if (meshFilter == null)
    51.             {
    52.                 Debug.LogWarning($"No MeshFilter is found in selected GameObject: {obj.name}", obj);
    53.                 continue;
    54.             }
    55.  
    56.             if(meshFilter.sharedMesh == null)
    57.             {
    58.                 Debug.LogWarning($"No mesh is found in selected GameObject: {obj.name}", obj);
    59.                 continue;
    60.             }
    61.  
    62.             string path = Path.Combine(directory, obj.name + ".obj");
    63.             StreamWriter writer = new StreamWriter(path);
    64.             writer.Write(GetMeshOBJ(obj.name, meshFilter.sharedMesh));
    65.             writer.Close();
    66.         }
    67.     }
    68.  
    69.     public static string GetMeshOBJ(string name, Mesh mesh)
    70.     {
    71.         StringBuilder sb = new StringBuilder();
    72.  
    73.         foreach (Vector3 v in mesh.vertices)
    74.             sb.Append(string.Format("v {0} {1} {2}\n", v.x, v.y, v.z));
    75.  
    76.         foreach (Vector3 v in mesh.normals)
    77.             sb.Append(string.Format("vn {0} {1} {2}\n", v.x, v.y, v.z));
    78.  
    79.         for (int material = 0; material < mesh.subMeshCount; material++)
    80.         {
    81.             sb.Append(string.Format("\ng {0}\n", name));
    82.             int[] triangles = mesh.GetTriangles(material);
    83.             for (int i = 0; i < triangles.Length; i += 3)
    84.             {
    85.                 sb.Append(string.Format("f {0}/{0} {1}/{1} {2}/{2}\n",
    86.                 triangles[i] + 1,
    87.                 triangles[i + 1] + 1,
    88.                 triangles[i + 2] + 1));
    89.             }
    90.         }
    91.  
    92.         return sb.ToString();
    93.     }
    94. }
     

    Attached Files:

    Ony likes this.
  15. b3x2088

    b3x2088

    Joined:
    Sep 11, 2019
    Posts:
    1
    If you were wondering why the OBJ's didn't import or you always got a messed up model that is useless this may happen due to your system locale (mine is set to Turkish, which formats floats with ',' character, OBJ format expects '.').
    I modified the multi export script so that it always exports correctly independent of system locale (sets the current threads locale as Invariant and resets it back to previous one after exporting, i also added a feature where you can apply Transform Matrix transformations to the meshes, useful if you are exporting a prefab)

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3. using System.IO;
    4. using System.Text;
    5. using System.Threading;
    6. using System.Globalization;
    7.  
    8. public static class ExportMeshToOBJ
    9. {
    10.     /// <summary>
    11.     /// Whether to apply matrix transformations while exporting a GameObject to OBJ.
    12.     /// </summary>
    13.     public static bool ApplyObjTransformations = true;
    14.  
    15.     private static void ExportToObjImpl(GameObject obj, string writePath)
    16.     {
    17.         if (obj == null)
    18.         {
    19.             Debug.Log("No object selected.");
    20.             return;
    21.         }
    22.  
    23.         if (!obj.TryGetComponent(out MeshFilter meshFilter))
    24.         {
    25.             Debug.Log("No MeshFilter is found in selected GameObject.", obj);
    26.             return;
    27.         }
    28.  
    29.         if (meshFilter.sharedMesh == null)
    30.         {
    31.             Debug.Log("No mesh is found in selected GameObject.", obj);
    32.             return;
    33.         }
    34.  
    35.         CultureInfo previousCurrentCulture = Thread.CurrentThread.CurrentCulture;
    36.  
    37.         try
    38.         {
    39.             using StreamWriter writer = new StreamWriter(writePath);
    40.  
    41.             // Set the culture to always being invariant/standard
    42.             // this is why the OBJ's were messed up, my CultureInfo formats floats with ',' instead of '.' which is what OBJ uses.
    43.             Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
    44.             writer.Write(GetMeshOBJ(obj.name, meshFilter.sharedMesh, ApplyObjTransformations ? obj.transform.localToWorldMatrix : Matrix4x4.identity));
    45.         }
    46.         catch (System.Exception e)
    47.         {
    48.             Debug.LogWarning($"[ExportToObjImpl] An exception occured while exporting selected GameObject : {e.Message}\n{e.StackTrace}", obj);
    49.         }
    50.  
    51.         Thread.CurrentThread.CurrentCulture = previousCurrentCulture;
    52.     }
    53.     public static string GetMeshOBJ(string name, Mesh mesh, Matrix4x4 objTransform)
    54.     {
    55.         StringBuilder sb = new StringBuilder();
    56.  
    57.         foreach (Vector3 v in mesh.vertices)
    58.         {
    59.             Vector3 writeV = (objTransform != Matrix4x4.identity && objTransform != default) ? objTransform.MultiplyPoint(v) : v;
    60.             sb.Append(string.Format("v {0} {1} {2}\n", writeV.x, writeV.y, writeV.z));
    61.         }
    62.  
    63.         // Also export UV's
    64.         foreach (Vector3 v in mesh.uv)
    65.         {
    66.             sb.Append(string.Format("vt {0} {1} {2}\n", v.x, v.y, v.z));
    67.         }
    68.  
    69.         foreach (Vector3 v in mesh.normals)
    70.         {
    71.             sb.Append(string.Format("vn {0} {1} {2}\n", v.x, v.y, v.z));
    72.         }
    73.  
    74.         for (int material = 0; material < mesh.subMeshCount; material++)
    75.         {
    76.             sb.Append(string.Format("\ng {0}\n", name));
    77.             int[] triangles = mesh.GetTriangles(material);
    78.             for (int i = 0; i < triangles.Length; i += 3)
    79.             {
    80.                 sb.Append(string.Format("f {0}/{0} {1}/{1} {2}/{2}\n",
    81.                 triangles[i] + 1,
    82.                 triangles[i + 1] + 1,
    83.                 triangles[i + 2] + 1));
    84.             }
    85.         }
    86.  
    87.         return sb.ToString();
    88.     }
    89.  
    90.     private static string PreviousSelectedDirectory = "";
    91.  
    92.     [MenuItem("GameObject/Export to OBJ")]
    93.     static void ExportToOBJ()
    94.     {
    95.         ApplyObjTransformations = false;
    96.  
    97.         GameObject obj = Selection.activeObject as GameObject;
    98.         string path = EditorUtility.SaveFilePanel("Export OBJ", PreviousSelectedDirectory, obj.name, "obj");
    99.  
    100.         ExportToObjImpl(obj, path);
    101.     }
    102.     [MenuItem("GameObject/Export to OBJs")]
    103.     static void ExportToOBJs()
    104.     {
    105.         ApplyObjTransformations = false;
    106.  
    107.         GameObject[] objs = Selection.gameObjects;
    108.         if (objs.Length < 1)
    109.         {
    110.             Debug.Log("No object selected.");
    111.             return;
    112.         }
    113.         string directory = EditorUtility.SaveFolderPanel("Export OBJs to", PreviousSelectedDirectory, "OBJFiles");
    114.         PreviousSelectedDirectory = directory;
    115.  
    116.         foreach (GameObject obj in objs)
    117.         {
    118.             ExportToObjImpl(obj, Path.Combine(directory, obj.name + ".obj"));
    119.         }
    120.     }
    121.  
    122.     [MenuItem("GameObject/Export to OBJ (Apply GameObject Transform)")]
    123.     static void ExportToOBJWithTransformations()
    124.     {
    125.         ApplyObjTransformations = true;
    126.  
    127.         GameObject obj = Selection.activeObject as GameObject;
    128.         string path = EditorUtility.SaveFilePanel("Export OBJ", PreviousSelectedDirectory, obj.name, "obj");
    129.  
    130.         ExportToObjImpl(obj, path);
    131.     }
    132.     [MenuItem("GameObject/Export to OBJs (Apply GameObject Transform)")]
    133.     static void ExportToOBJsWithTransformations()
    134.     {
    135.         ApplyObjTransformations = true;
    136.  
    137.         GameObject[] objs = Selection.gameObjects;
    138.         if (objs.Length < 1)
    139.         {
    140.             Debug.Log("No object selected.");
    141.             return;
    142.         }
    143.         string directory = EditorUtility.SaveFolderPanel("Export OBJs to", PreviousSelectedDirectory, "OBJFiles");
    144.         PreviousSelectedDirectory = directory;
    145.  
    146.         foreach (GameObject obj in objs)
    147.         {
    148.             ExportToObjImpl(obj, Path.Combine(directory, obj.name + ".obj"));
    149.         }
    150.     }
    151. }
    152.  
     

    Attached Files: