将Unity场景以Wavefront Obj格式导出

来源:互联网 发布:淘宝买人心果树 编辑:程序博客网 时间:2024/06/09 19:57

原文链接

使用方法请参考原文链接。导出的Obj文件可以作为RecastNavigation的RecastDemo.exe程序的输入文件。

脚本修改如下,支持Unity 5.3.5f1。仅修改了原文链接代码的Unity版本兼容性。

EditorObjExporter.cs

using UnityEngine;using UnityEditor;using UnityEditor.SceneManagement;using System.Collections;using System.Collections.Generic;using System.IO;using System.Text;using System;struct ObjMaterial{    public string name;    public string textureName;}public class EditorObjExporter : 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 = "ExportedObj";    private static string MeshToString(MeshFilter mf, Dictionary<string, ObjMaterial> materialList)    {        Mesh m = mf.sharedMesh;        Material[] mats = mf.GetComponent<Renderer>().sharedMaterials;        StringBuilder sb = new StringBuilder();        sb.Append("g ").Append(mf.name).Append("\n");        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}\n", -wv.x, wv.y, wv.z));        }        sb.Append("\n");        foreach (Vector3 lv in m.normals)        {            Vector3 wv = mf.transform.TransformDirection(lv);            sb.Append(string.Format("vn {0} {1} {2}\n", -wv.x, wv.y, wv.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");            //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 = AssetDatabase.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}\n",                triangles[i] + 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("\n");                sw.Write("newmtl {0}\n", kvp.Key);                sw.Write("Ka  0.6 0.6 0.6\n");                sw.Write("Kd  0.6 0.6 0.6\n");                sw.Write("Ks  0.9 0.9 0.9\n");                sw.Write("d  1.0\n");                sw.Write("Ns  0.0\n");                sw.Write("illum 2\n");                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("\n");            }        }    }    private static void MeshToFile(MeshFilter mf, string folder, string filename)    {        Dictionary<string, ObjMaterial> materialList = PrepareFileWrite();        using (StreamWriter sw = new StreamWriter(folder + "/" + filename + ".obj"))        {            sw.Write("mtllib ./" + filename + ".mtl\n");            sw.Write(MeshToString(mf, materialList));        }        MaterialsToFile(materialList, folder, filename);    }    private static void MeshesToFile(MeshFilter[] mf, string folder, string filename)    {        Dictionary<string, ObjMaterial> materialList = PrepareFileWrite();        using (StreamWriter sw = new StreamWriter(folder + "/" + filename + ".obj"))        {            sw.Write("mtllib ./" + filename + ".mtl\n");            for (int i = 0; i < mf.Length; i++)            {                sw.Write(MeshToString(mf[i], 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("Custom/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[i].GetComponentsInChildren(typeof(MeshFilter));            for (int m = 0; m < meshfilter.Length; m++)            {                exportedObjects++;                MeshToFile((MeshFilter)meshfilter[m], targetFolder, selection[i].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("Custom/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[i].GetComponentsInChildren(typeof(MeshFilter));            for (int m = 0; m < meshfilter.Length; m++)            {                exportedObjects++;                mfList.Add(meshfilter[m]);            }        }        if (exportedObjects > 0)        {            MeshFilter[] mf = new MeshFilter[mfList.Count];            for (int i = 0; i < mfList.Count; i++)            {                mf[i] = (MeshFilter)mfList[i];            }            string filename = EditorSceneManager.GetActiveScene().name + "_" + 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!", "");    }    [MenuItem("Custom/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[i].GetComponentsInChildren(typeof(MeshFilter));            MeshFilter[] mf = new MeshFilter[meshfilter.Length];            for (int m = 0; m < meshfilter.Length; m++)            {                exportedObjects++;                mf[m] = (MeshFilter)meshfilter[m];            }            MeshesToFile(mf, targetFolder, selection[i].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!", "");    }}



0 0
原创粉丝点击