[Unity] Unity导出任意模型为obj模型

查看:18044 |回复:2 | 2021-11-16 16:07:10

您需要 登录 才可以下载或查看,没有账号?注册

x
本帖最后由 Pharmacist 于 2022-4-29 11:14 编辑

Maya或者3dMax导模型到unity比较常见,但是unity导出模型到maya或者3dMax也偶尔会用到。有时候就是需要定位这些场景数据到maya中作为参考,甚至作为基础模型。
那么unity怎么导出模型成obj呢?
unity商店一抓一大把,可能需要花点$。这里我给出一个脚本,直接就可以导出obj模型了。
1.首先写引用
image.png
2.定义材质球结构
image.png
3.基础方法,mesh、material转数据。
5.unity菜单命令
怎么用呢?选择要导出的模型,或者模型的组,然后点一下这个命令就好了。
代码:
using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System;


struct ObjMat
{
    public string name;
    public string textureName;
}

public class ObjExporter : ScriptableObject
{
    private static int vertexOffset = 0;
    private static int normalOffset = 0;
    private static int uvOffset = 0;

    //导出地址
    private static string targetFolder = "Assets/ExportedObj";

    private static string MeshToString(MeshFilter mf, Dictionary<string, ObjMat> 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
            {
                ObjMat objMaterial = new ObjMat();

                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}\n",
                    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, ObjMat> PrepareFileWrite()
    {
        Clear();

        return new Dictionary<string, ObjMat>();
    }


    private static void MaterialsToFile(Dictionary<string, ObjMat> materialList, string folder, string filename)
    {
        using (StreamWriter sw = new StreamWriter(folder + "/" + filename + ".mtl"))
        {
            foreach (KeyValuePair<string, ObjMat> 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\n\n");
            }
        }
    }


    private static void MeshToFile(MeshFilter mf, string folder, string filename)
    {
        Dictionary<string, ObjMat> 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, ObjMat> 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, 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("Tools/Export/将每个被选中资源成分离的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));
            MeshFilter[] mf = new MeshFilter[0];
            if (meshfilter != null && meshfilter.Length > 0)
            {
                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!", "");
    }
}

2021-11-16 16:07:10  
 赞 赞 0

使用道具 登录

2个回答,把该问题分享到群,邀请大神一起回答。
2#
想要成大触,天天上元素!
回复 收起回复
2021-11-19 16:00:20   回复
 赞 赞 0

使用道具 登录

3#
回复 收起回复
2023-2-26 12:51:03   回复
 赞 赞 0

使用道具 登录

CG 游戏行业专业问题

unityobj导出手机游戏引擎手游引擎Unity3D技术
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表