查看: 2030|回复: 3
打印 上一主题 下一主题

Unity网格资源导出为*.Obj格式模型脚本

[复制链接]

315

主题

0

听众

1万

积分

资深设计师

Rank: 7Rank: 7Rank: 7

纳金币
10878
精华
0

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

跳转到指定楼层
楼主
发表于 2012-3-16 21:50:22 |只看该作者 |倒序浏览
这个脚本由 CocoaChina 版主“四角钱” 分享,可以导出 Unity 的网格资源为模型文件。原理是利用 bjExporter.MeshToString() 创建一个文本字符串构成的 Obj 文件,或者用 ObjExporter.MeshToFile() 直接保存为一个文件。
    将下面2个脚本保存在 Editor 文件夹中,然后选择一个网格对象,在 Custom 菜单中根据需要选择导出为 Obj 文件,文件将被保存在项目目录的 ExportedObj 文件夹中。
    文件名: ObjExporter.cs
    cs 代码
using UnityEngine;

using System.Collections;

using System.IO;

using System.Text;



public class ObjExporter {



    public static string MeshToString(MeshFilter mf) {

        Mesh m = mf.mesh;

        Material[] mats = mf.renderer.sharedMaterials;

        

        StringBuilder sb = new StringBuilder();

        

        sb.Append("g ").Append(mf.name).Append("
");

        foreach(Vector3 v in m.vertices) {

            sb.Append(string.Format("v {0} {1} {2}
",v.x,v.y,v.z));

        }

        sb.Append("
");

        foreach(Vector3 v in m.normals) {

            sb.Append(string.Format("vn {0} {1} {2}
",v.x,v.y,v.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("
");

               

            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}
",

                    triangles+1, triangles[i+1]+1, triangles[i+2]+1));

            }

        }

        return sb.ToString();

    }

   

    public static void MeshToFile(MeshFilter mf, string filename) {

        using (StreamWriter sw = new StreamWriter(filename))

        {

            sw.Write(MeshToString(mf));

        }

    }

}
    文件名: EditorObjExporter.cs
    cs 代码
/*

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. */



using UnityEngine;

using UnityEditor;

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.renderer.sharedMaterials;

        

        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(MeshFilter mf, string folder, string filename)

    {

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

   

        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(MeshFilter[] mf, string folder, string filename)

    {

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

   

        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 ("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!", "lease select one or more target objects", "");

            return;

        }

        

        int exportedObjects = 0;

        

        for (int i = 0; i < selection.Length; i++)

        {

         Component[] meshfilter = selection.GetComponentsInChildren(typeof(MeshFilter));

         

         for (int m = 0; m < meshfilter.Length; m++)

         {

          exportedObjects++;

          MeshToFile((MeshFilter)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 ("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!", "lease 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));

         

         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 = (MeshFilter)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!", "");

    }

   

   

   

    [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!", "lease select one or more target objects", "");

            return;

        }

        

        int exportedObjects = 0;

        

        

        for (int i = 0; i < selection.Length; i++)

        {

         Component[] meshfilter = selection.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.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!", "");

    }

   

}
分享到: QQ好友和群QQ好友和群 腾讯微博腾讯微博 腾讯朋友腾讯朋友 微信微信
转播转播0 分享淘帖0 收藏收藏0 支持支持0 反对反对0
回复

使用道具 举报

315

主题

0

听众

1万

积分

资深设计师

Rank: 7Rank: 7Rank: 7

纳金币
10878
精华
0

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

沙发
发表于 2012-3-16 22:18:54 |只看该作者
赞!
回复

使用道具 举报

2508

主题

2

听众

3万

积分

资深设计师

Rank: 7Rank: 7Rank: 7

纳金币
32806
精华
12

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

板凳
发表于 2012-11-7 09:19:17 |只看该作者
不错的  谢谢楼主分享
回复

使用道具 举报

2317

主题

54

听众

2万

积分

资深设计师

Rank: 7Rank: 7Rank: 7

纳金币
20645
精华
62

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

地板
发表于 2012-11-11 17:42:58 |只看该作者
这个不错。可以试试看效果
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

手机版|纳金网 ( 闽ICP备2021016425号-2/3

GMT+8, 2025-7-20 10:08 , Processed in 0.096081 second(s), 29 queries .

Powered by Discuz!-创意设计 X2.5

© 2008-2019 Narkii Inc.

回顶部