OBJ mesh export help

How to fix this?

Just change this line
from:

m = (mf as SkinnedMeshRenderer).sharedMesh;

to:

m = new Mesh();
(mf as SkinnedMeshRenderer).BakeMesh(m);

You can use this modified version of the script which I’ve rewritten so that it will also export meshes from SkinnedMeshRenderers:

/*
Based on ObjExporter.cs, this "wrapper" lets you export to .OBJ directly from the editor menu.
 
This should be put in your "Editor"-folder. Use by selecting the objects you want to export, and select
the appropriate menu item from "Custom->Export". Exported models are put in a folder called
"ExportedObj" in the root of your Unity-project. Textures should also be copied and placed in the
same folder.
N.B. there may be a bug so if the custom option doesn't come up refer to this thread http://answers.unity3d.com/questions/317951/how-to-use-editorobjexporter-obj-saving-script-fro.html */
 
using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System;
using System.Linq;
 
struct ObjMaterial
{
	public string name;
	public string textureName;
}
 
public class EditorObjExporterEx : ScriptableObject
{
	private static int vertexOffset = 0;
	private static int normalOffset = 0;
	private static int uvOffset = 0;
 
 
	//User should probably be able to change this. It is currently left as an excercise for
	//the reader.
	private static string targetFolder = "Assets/ExportedObj";
 
 
    private static string MeshToString(Component mf, Dictionary<string, ObjMaterial> materialList) 
    {
		
		
		
        Mesh m;
        Material[] mats;
		
		if(mf is MeshFilter)
		{
			m = (mf as MeshFilter).mesh;
			mats = mf.renderer.sharedMaterials;
		}
		else if(mf is SkinnedMeshRenderer)
		{
			m = (mf as SkinnedMeshRenderer).sharedMesh;
			mats = (mf as SkinnedMeshRenderer).sharedMaterials;
		}
		else
		{
			return "";
		}
 
        StringBuilder sb = new StringBuilder();
 
        sb.Append("g ").Append(mf.name).Append("

");
foreach(Vector3 lv in m.vertices)
{
Vector3 wv = mf.transform.TransformPoint(lv);

        	//This is sort of ugly - inverting x-component since we're in
        	//a different coordinate system than "everyone" is "used to".
            sb.Append(string.Format("v {0} {1} {2}

“,-wv.x,wv.y,wv.z));
}
sb.Append(”
");

        foreach(Vector3 lv in m.normals) 
        {
        	Vector3 wv = mf.transform.TransformDirection(lv);
 
            sb.Append(string.Format("vn {0} {1} {2}

“,-wv.x,wv.y,wv.z));
}
sb.Append(”
");

        foreach(Vector3 v in m.uv) 
        {
            sb.Append(string.Format("vt {0} {1}

",v.x,v.y));
}

        for (int material=0; material < m.subMeshCount; material ++) {
            sb.Append("

");
sb.Append("usemtl “).Append(mats[material].name).Append(”
");
sb.Append("usemap “).Append(mats[material].name).Append(”
");

            //See if this material is already in the materiallist.
            try
       		{
          		ObjMaterial objMaterial = new ObjMaterial();
 
          		objMaterial.name = mats[material].name;
 
          		if (mats[material].mainTexture)
          			objMaterial.textureName = EditorUtility.GetAssetPath(mats[material].mainTexture);
          		else 
          			objMaterial.textureName = null;
 
          		materialList.Add(objMaterial.name, objMaterial);
        	}
        	catch (ArgumentException)
        	{
            	//Already in the dictionary
        	}
 
 
            int[] triangles = m.GetTriangles(material);
            for (int i=0;i<triangles.Length;i+=3) 
            {
            	//Because we inverted the x-component, we also needed to alter the triangle winding.
                sb.Append(string.Format("f {1}/{1}/{1} {0}/{0}/{0} {2}/{2}/{2}

",
triangles*+1 + vertexOffset, triangles[i+1]+1 + normalOffset, triangles[i+2]+1 + uvOffset));*
}
}

vertexOffset += m.vertices.Length;
normalOffset += m.normals.Length;
uvOffset += m.uv.Length;

return sb.ToString();
}

private static void Clear()
{

  • vertexOffset = 0;*

  • normalOffset = 0;*

  • uvOffset = 0;*
    }

  • private static Dictionary<string, ObjMaterial> PrepareFileWrite()*

  • {*

  •  Clear();*
    
  • return new Dictionary<string, ObjMaterial>();*

  • }*

  • private static void MaterialsToFile(Dictionary<string, ObjMaterial> materialList, string folder, string filename)*

  • {*

  •  using (StreamWriter sw = new StreamWriter(folder + "/" + filename + ".mtl"))* 
    

{

  • foreach( KeyValuePair<string, ObjMaterial> kvp in materialList )*
  • {*
  •  sw.Write("
    

");*

  •  sw.Write("newmtl {0}
    

", kvp.Key);*

  •  sw.Write("Ka  0.6 0.6 0.6
    

");*

  •  		sw.Write("Kd  0.6 0.6 0.6
    

");*

  •  		sw.Write("Ks  0.9 0.9 0.9
    

");*

  •  		sw.Write("d  1.0
    

");*

  •  		sw.Write("Ns  0.0
    

");*

  •  		sw.Write("illum 2
    

");*

  •  		if (kvp.Value.textureName != null)*
    
  •  		{*
    
  •  			string destinationFile = kvp.Value.textureName;*
    
  •  			int stripIndex = destinationFile.LastIndexOf('/');//FIXME: Should be Path.PathSeparator;*
    
  •  		if (stripIndex >= 0)*
    
  •  	destinationFile = destinationFile.Substring(stripIndex + 1).Trim();*
    
  •  string relativeFile = destinationFile;*
    
  •  destinationFile = folder + "/" + destinationFile;*
    
  •  			Debug.Log("Copying texture from " + kvp.Value.textureName + " to " + destinationFile);*
    
  •  			try*
    
  •  			{*
    
  •  				//Copy the source file*
    
  •  				File.Copy(kvp.Value.textureName, destinationFile);*
    
  •  			}*
    
  •  			catch*
    
  •  			{*
    
  •  			}	*
    
  •  			sw.Write("map_Kd {0}", relativeFile);*
    
  •  		}*
    
  •  		sw.Write("
    

");*

  • }*
    }
  • }*

private static void MeshToFile(Component mf, string folder, string filename)
{

  • Dictionary<string, ObjMaterial> materialList = PrepareFileWrite();*

  •  Directory.CreateDirectory(folder);*
    

using (StreamWriter sw = new StreamWriter(folder +“/” + filename + “.obj”))
{

  • sw.Write(“mtllib ./” + filename + ".mtl
    ");*

sw.Write(MeshToString(mf, materialList));
}

MaterialsToFile(materialList, folder, filename);
}

private static void MeshesToFile(Component[] mf, string folder, string filename)
{

  • Dictionary<string, ObjMaterial> materialList = PrepareFileWrite();*

  •  Directory.CreateDirectory(folder);*
    

using (StreamWriter sw = new StreamWriter(folder +“/” + filename + “.obj”))
{

  • sw.Write(“mtllib ./” + filename + ".mtl
    ");*

  • for (int i = 0; i < mf.Length; i++)*

  • {*
    _ sw.Write(MeshToString(mf*, materialList));_
    _
    }_
    _
    }*_

MaterialsToFile(materialList, folder, filename);
}

private static bool CreateTargetFolder()
{
* try*
* {*
* System.IO.Directory.CreateDirectory(targetFolder);*
* }*
* catch*
* {*
* EditorUtility.DisplayDialog(“Error!”, “Failed to create target folder!”, “”);*
* return false;*
* }*

* return true;*
}

[MenuItem (“Window/Export/Export all MeshFilters in selection to separate OBJs”)]
static void ExportSelectionToSeparate()
{
* if (!CreateTargetFolder())*
* return;*

Transform[] selection = Selection.GetTransforms(SelectionMode.Editable | SelectionMode.ExcludePrefab);

if (selection.Length == 0)
{
* EditorUtility.DisplayDialog(“No source object selected!”, “Please select one or more target objects”, “”);*
* return;*
}

int exportedObjects = 0;

* for (int i = 0; i < selection.Length; i++)*
* {*
Component meshfilter = selection_.GetComponentsInChildren(typeof(MeshFilter)).Concat(selection*.GetComponentsInChildren(typeof(SkinnedMeshRenderer))).ToArray();*_

* for (int m = 0; m < meshfilter.Length; m++)*
* {*
* exportedObjects++;*
MeshToFile(meshfilter[m], targetFolder, selection*.name + “" + i + "” + m);
_ }
}*_

* if (exportedObjects > 0)*
* EditorUtility.DisplayDialog(“Objects exported”, “Exported " + exportedObjects + " objects”, “”);*
* else*
* EditorUtility.DisplayDialog(“Objects not exported”, “Make sure at least some of your selected objects have mesh filters!”, “”);*
}

[MenuItem (“Window/Export/Export whole selection to single OBJ”)]
static void ExportWholeSelectionToSingle()
{
* if (!CreateTargetFolder())*
* return;*

Transform[] selection = Selection.GetTransforms(SelectionMode.Editable | SelectionMode.ExcludePrefab);

if (selection.Length == 0)
{
* EditorUtility.DisplayDialog(“No source object selected!”, “Please select one or more target objects”, “”);*
* return;*
}

int exportedObjects = 0;

ArrayList mfList = new ArrayList();

* for (int i = 0; i < selection.Length; i++)*
* {*
Component meshfilter = selection_.GetComponentsInChildren(typeof(MeshFilter)).Concat(selection*.GetComponentsInChildren(typeof(SkinnedMeshRenderer))).ToArray();*_

* for (int m = 0; m < meshfilter.Length; m++)*
* {*
* exportedObjects++;*
* mfList.Add(meshfilter[m]);*
* }*
* }*

* if (exportedObjects > 0)*
* {*
* Component[] mf = new Component[mfList.Count];*

* for (int i = 0; i < mfList.Count; i++)*
* {*
mf = (Component)mfList*;*
* }*

* string filename = EditorApplication.currentScene + “_” + exportedObjects;*

* int stripIndex = filename.LastIndexOf(‘/’);//FIXME: Should be Path.PathSeparator*

* if (stripIndex >= 0)*
* filename = filename.Substring(stripIndex + 1).Trim();*

* MeshesToFile(mf, targetFolder, filename);*

* EditorUtility.DisplayDialog(“Objects exported”, "Exported " + exportedObjects + " objects to " + filename, “”);*
* }*
* else*
* EditorUtility.DisplayDialog(“Objects not exported”, “Make sure at least some of your selected objects have mesh filters or skinned mesh renderers!”, “”);*
}

[MenuItem (“Window/Export/Export each selected to single OBJ”)]
static void ExportEachSelectionToSingle()
{
* if (!CreateTargetFolder())*
* return;*

Transform[] selection = Selection.GetTransforms(SelectionMode.Editable | SelectionMode.ExcludePrefab);

if (selection.Length == 0)
{
* EditorUtility.DisplayDialog(“No source object selected!”, “Please select one or more target objects”, “”);*
* return;*
}

int exportedObjects = 0;

* for (int i = 0; i < selection.Length; i++)*
* {*
Component meshfilter = selection_.GetComponentsInChildren(typeof(MeshFilter)).Concat(selection*.GetComponentsInChildren(typeof(SkinnedMeshRenderer))).ToArray();_
MeshesToFile(meshfilter, targetFolder, selection.name + "" + i);*
* }*_

* if (exportedObjects > 0)*
* {*
* EditorUtility.DisplayDialog(“Objects exported”, “Exported " + exportedObjects + " objects”, “”);*
* }*
* else*
* EditorUtility.DisplayDialog(“Objects not exported”, “Make sure at least some of your selected objects have mesh filters or skinned mesh renderers!”, “”);*
}

}
_*

EXPORT DEFORMED SKINNED MESH TO OBJ : UNITY

Dont edit the file in notepad -
Do this :

  • import the package in unity
    • click on the script (EditorObjExporterEx.cs) in your edit
      folder
    • let the built in script editor launch
    • edit the indicated text and save
    • allow unity to recompile
    • select your game object
    • use the custom menu-> export whole selection to obj menu item.
      look for your .obj in the root of your project in the new folder : ExportedObj

Ive exported two deformed meshes into single .objs - this works like a charm!

You can even set the exact frame of the pose you want with the animation window and pick the animation if your model is rigged with an animator.

Just change this line from:

m = (mf as SkinnedMeshRenderer).sharedMesh;

to:

mesh m = new Mesh(); 
(mf as SkinnedMeshRenderer).BakeMesh(m);