Exporting multiple Meshes in a single Wavefront OBJ file

I have a working script where I export multiple meshes that are created during runtime into a OBJ file, but each mesh creates a separate file.

Code that is working

 private static void ExportToObjImpl(GameObject obj, string writePath)
    {
        if (obj == null)
        {
            Debug.Log("No object selected.");
            return;
        }

        if (!obj.TryGetComponent(out MeshFilter meshFilter))
        {
            Debug.Log("No MeshFilter is found in selected GameObject.", obj);
            return;
        }

        if (meshFilter.sharedMesh == null)
        {
            Debug.Log("No mesh is found in selected GameObject.", obj);
            return;
        }

        CultureInfo previousCurrentCulture = Thread.CurrentThread.CurrentCulture;

        try
        {
            using StreamWriter writer = new StreamWriter(writePath);

            // Set the culture to always being invariant/standard
            // this is why the OBJ's were messed up, my CultureInfo formats floats with ',' instead of '.' which is what OBJ uses.
            Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
            writer.Write(GetMeshOBJ(obj.name, meshFilter.sharedMesh, ApplyObjTransformations ? obj.transform.localToWorldMatrix : Matrix4x4.identity));
        }
        catch (System.Exception e)
        {
            Debug.LogWarning($"[ExportToObjImpl] An exception occured while exporting selected GameObject : {e.Message}\n{e.StackTrace}", obj);
        }

        Thread.CurrentThread.CurrentCulture = previousCurrentCulture;
    }
    public static string GetMeshOBJ(string name, Mesh mesh, Matrix4x4 objTransform)
    {
        StringBuilder sb = new StringBuilder();

        foreach (Vector3 v in mesh.vertices)
        {
            Vector3 writeV = (objTransform != Matrix4x4.identity && objTransform != default) ? objTransform.MultiplyPoint(v) : v;
            sb.Append(string.Format("v {0} {1} {2}\n", writeV.x, writeV.y, writeV.z));
        }

        // Also export UV's
        foreach (Vector3 v in mesh.uv)
        {
            sb.Append(string.Format("vt {0} {1} {2}\n", v.x, v.y, v.z));
        }

        foreach (Vector3 v in mesh.normals)
        {
            sb.Append(string.Format("vn {0} {1} {2}\n", v.x, v.y, v.z));
        }

        for (int material = 0; material < mesh.subMeshCount; material++)
        {
            sb.Append(string.Format("\ng {0}\n", name));
            int[] triangles = mesh.GetTriangles(material);
            for (int i = 0; i < triangles.Length; i += 3)
            {
                sb.Append(string.Format("f {0}/{0} {1}/{1} {2}/{2}\n",
                triangles[i] + 1,
                triangles[i + 1] + 1,
                triangles[i + 2] + 1));
            }
        }

        return sb.ToString();
    }


I wanted to export all the meshes into one file only, but the meshes seem to break

Code that is not working

private static void ExportToObjImpl2(GameObject[] objs, string writePath)
    {
        if (objs == null)
        {
            Debug.Log("No object selected.");
            return;
        }


        List<Mesh> meshfilter = new List<Mesh>();
        foreach (GameObject obj in objs)
        {
            meshfilter.Add(obj.GetComponent<MeshFilter>().sharedMesh);
        }

        Mesh[] meshesArray = meshfilter.ToArray();



        CultureInfo previousCurrentCulture = Thread.CurrentThread.CurrentCulture;

        try
        {
            using StreamWriter writer = new StreamWriter(writePath);

            Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
            writer.Write(GetMeshOBJ2(objs, meshesArray, Matrix4x4.identity));
        }
        catch (System.Exception e)
        {
            Debug.LogWarning($"[ExportToObjImpl] An exception occured while exporting selected GameObject : {e.Message}\n{e.StackTrace}", objs[0]);
        }

        Thread.CurrentThread.CurrentCulture = previousCurrentCulture;
    }
    public static string GetMeshOBJ2(Object[] lines, Mesh[] meshes, Matrix4x4 objTransform)
    {
        StringBuilder sb = new StringBuilder();
        int l = 0;
        foreach (Object obj in lines)
        {
            sb.Append(string.Format("o {0}\n", "Line" + l.ToString()));

            foreach (Vector3 v in meshes[l].vertices)
            {
                Vector3 writeV = (objTransform != Matrix4x4.identity && objTransform != default) ? objTransform.MultiplyPoint(v) : v;
                sb.Append(string.Format("v {0} {1} {2}\n", writeV.x, writeV.y, writeV.z));
            }

            // Also export UV's
            foreach (Vector3 v in meshes[l].uv)
            {
                sb.Append(string.Format("vt {0} {1} {2}\n", v.x, v.y, v.z));
            }

            foreach (Vector3 v in meshes[l].normals)
            {
                sb.Append(string.Format("vn {0} {1} {2}\n", v.x, v.y, v.z));
            }

            for (int material = 0; material < meshes[l].subMeshCount; material++)
            {

                int[] triangles = meshes[l].GetTriangles(material);
                for (int i = 0; i < triangles.Length; i += 3)
                {
                    sb.Append(string.Format("f {0}/{0} {1}/{1} {2}/{2}\n",
                    triangles[i] + 1,
                    triangles[i + 1] + 1,
                    triangles[i + 2] + 1));
                }
            }

            l++;
        }



        return sb.ToString();
    }

The left image is from the first script and the right one from the second


Could anyone help point me in the right direction? Is it a formatting error?

Are you aware that:
a) there’s the FBX Exporter package and it’s only an additional step to convert the FBX to OBJ with any tool?
b) there are OBJ exporters available, both free and paid?

:wink:

Didn’t read the code but combining two meshes into one isn’t done by writing more data to the file, but rather you’d have to use something like Mesh.Combine in order to weld the meshes together. But then these won’t be individual objects anymore.

You’d have to read through the OBJ format specs in order to get this right … or: see above.