Unity功能实现——解析OBJ模型文件

Unity功能实现——解析OBJ模型文件

1、OBJFile类
用于存储读取obj文件的g、v、f
g对应gameobject.name
v对应mesh.vertices
f对应mesh.triangles 注意unity对于mesh点索引的起始点是0不是1

using System.Collections.Generic;
using UnityEngine;

public class OBJFile
{
    public string GroupName { get; set; } = "";                         //g
    public List<Vector3> PointList { get; set; } = new List<Vector3>(); //v
    public List<int> FaceList { get; set; } = new List<int>();          //f
}

2、AnalyseFile函数
用于读取obj文件的文本内容并取出其中的g、v、f存入OBJFile
fileText对应obj文件的文本内容

    internal static OBJFile AnalyseFile(string fileText)
    {
        //创建obj类
        OBJFile objFile = new OBJFile();
        //按行切割obj文本
        string[] fileLines = fileText.Split('\n');
        foreach (string fileLine in fileLines)
        {
            //组
            if (fileLine.Contains("g "))
            {
                string[] groupLine = fileLine.Split(' ');
                objFile.GroupName = groupLine[1];
            }
            //点
            else if (fileLine.Contains("v "))
            {
                string[] vertexLine = fileLine.Split(' ');
                Vector3 vertex = new Vector3(float.Parse(vertexLine[1]), float.Parse(vertexLine[2]), float.Parse(vertexLine[3]));
                objFile.PointList.Add(vertex);
            }
            //面
            else if (fileLine.Contains("f "))
            {
                string[] faceLine = fileLine.Split(' ');
                objFile.FaceList.Add(int.Parse(faceLine[1]) - 1);//-1是因为unity里顶点索引是从0开始,不是1开始
                objFile.FaceList.Add(int.Parse(faceLine[2]) - 1);//文本f 1 2 3 转化到unity要成为f [0] [1] [2]
                objFile.FaceList.Add(int.Parse(faceLine[3]) - 1);
            }
        }
        return objFile;
    }

3、LoadOBJModel函数
用于读取制定路径的obj文件并在unity场景中生成对应物体
path对应obj文件路径

    public static void LoadOBJModel(string path)
    {
        //obj文件路径
        //string filePath = @"C:\Users\username\Desktop\测试用.obj";
        string filePath = path;
        //获取obj文件文本
        string fileText = ReadFile(filePath);
        //解析obj字符串
        OBJFile objFile = AnalyseFile(fileText);
        //创建网格
        Mesh mesh = new Mesh();
        mesh.name = objFile.GroupName;
        mesh.vertices = objFile.PointList.ToArray();
        mesh.triangles = objFile.FaceList.ToArray();
        mesh.RecalculateNormals();//从三角形和顶点重新计算网格的法线。
        //创建游戏物体
        GameObject gameObject = new GameObject(objFile.GroupName);
        MeshFilter meshFilter = gameObject.AddComponent<MeshFilter>();
        MeshRenderer meshRenderer = gameObject.AddComponent<MeshRenderer>();
        meshFilter.mesh = mesh;
        meshRenderer.material = new Material(Shader.Find("Standard"));
    }

=========================================================================================================
4、OpenFileName类
用于声明windows资源管理器dll

public class OpenFileName
{
    public int structSize = 0;
    public IntPtr dlgOwner = IntPtr.Zero;
    public IntPtr instance = IntPtr.Zero;
    public String filter = null;
    public String customFilter = null;
    public int maxCustFilter = 0;
    public int filterIndex = 0;
    public String file = null;
    public int maxFile = 0;
    public String fileTitle = null;
    public int maxFileTitle = 0;
    public String initialDir = null;
    public String title = null;
    public int flags = 0;
    public short fileOffset = 0;
    public short fileExtension = 0;
    public String defExt = null;
    public IntPtr custData = IntPtr.Zero;
    public IntPtr hook = IntPtr.Zero;
    public String templateName = null;
    public IntPtr reservedPtr = IntPtr.Zero;
    public int reservedInt = 0;
    public int flagsEx = 0;
}

public class WindowDLL
{
    [DllImport("Comdlg32.dll", SetLastError = true, ThrowOnUnmappableChar = true, CharSet = CharSet.Auto)]
    public static extern bool GetOpenFileName([In, Out] OpenFileName ofn);//外部dll的方法
    public static bool GetOpenFileName1([In, Out] OpenFileName ofn)//调用外部dll方法
    {
        return GetOpenFileName(ofn);
    }
}

5、添加按钮事件调用资源管理器

    public void Button_OnClick()
    {
        OpenFileName ofn = new OpenFileName();//实例化一个文件对象
        ofn.structSize = Marshal.SizeOf(ofn);//结构大小
        ofn.filter = "All Files\0*.*\0\0";//文件类型过滤器
        ofn.file = new string(new char[512]);//文件路径
        ofn.maxFile = ofn.file.Length;//文件路径长度
        ofn.fileTitle = new string(new char[128]);//文件标题
        ofn.maxFileTitle = ofn.fileTitle.Length;//文件标题长度
        ofn.initialDir = Application.dataPath;//默认路径
        ofn.title = "Open OBJ Model";//对象标题
        ofn.defExt = "OBJ";//显示文件的类型
        //注意 下面这个字段不一定要全选 但是 0x00000008 项不要缺少
        ofn.flags = 0x00080000 | 0x00001000 | 0x00000800 | 0x00000200 | 0x00000008;
        //OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST| OFN_ALLOWMULTISELECT|OFN_NOCHANGEDIR
        //如果调用外部WindowDLL能访问到该文件
        if (WindowDLL.GetOpenFileName(ofn))
        {
            //加载OBJ文件
            ImportOBJUtil.LoadOBJModel(ofn.file);
            Debug.Log("所选文件路径为:" + ofn.file);
        }
        else
        {
            Debug.Log("无法访问到文件:" + ofn.file);
        }
    }

6、效果
该方法只针对博主另一篇博客的Revit插件生成的OBJ模型格式
https://blog.csdn.net/qq_28907595/article/details/84838419

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_28907595/article/details/85243683