找回密码
 注册帐号

扫一扫,访问微社区

MemoryC MemoryC杂记(三)【obj模型的加载和解析】

55
回复
1590
查看
[ 复制链接 ]
排名
1348
昨日变化

29

主题

273

帖子

2740

积分

Rank: 9Rank: 9Rank: 9

UID
175038
好友
47
蛮牛币
3299
威望
0
注册时间
2016-10-12
在线时间
619 小时
最后登录
2019-4-24

专栏作家活力之星

2018-10-15 20:14:02 显示全部楼层 阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

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

x
Unity动态加载和解析obj模型


最近在做的项目中有这个模块觉得可能大家有人需要,就分享出来。当然,你也可能找到其他人写的解析模块,我这篇文章虽有重复部分,但是也包含一些针对Unity平台的特殊处理。

1、Unity平台的Mesh一般都是三角网格,而实际上obj模型不仅可能是三角网格,还有可能是四边形网格。为了让obj解析之后更好地兼容Unity,这里对四边形网格进行了三角化操作;

2、在Unity中,Mesh.uv是一个Vector2类型数组,第i个元素表示第i个顶点对应的UV贴图的二维坐标。不同的是,Unity中Mesh.uv每个元素的顺序是与Mesh.vertices相对应的,而实际上obj 文件并没有这个约束。obj文件中v(顶点)的顺序和vt(UV坐标)的顺序不需要保持一致,甚至个数都可以不相同,只是在表示每个f时,标注每个顶点对应的vt的序号。本期MemoryC杂记中,我们将在解析obj中的uv的时候,将vt的数目和顺序按照Unity的规范来调整。

3、在Unity中,Mesh.normals(法线)也是与顶点顺序相对应的,类似的,我也做了相应的处理使之保持一致。

4、obj模型中表示面的行有以下几种方式 :[f va vb vc]、[f va/vta/vna vb/vtb/vnb vc/vtc/vnc]、[f va//vna vb//vnb vc//vnc]、[f va/vta vb/vtb vc/vtc]等。本文所给的方法均进行了适配。

5、返回Mesh前,重新计算了模型的切线和边界等信息。

6、出处http://www.manew.com/forum-47-453-1.html,如果转载请注 游戏蛮牛、MemoryC字样,否则皆为侵权行为。


【代码】

[C#] 纯文本查看 复制代码
using System.Collections;

using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// author:MemoryC
/// date:2018.09.16
/// description:ObjReader by MemoryC
/// support:load .obj file from external storage and convert it to mesh file with uvCoord and vertice normals
/// </summary>
public class ObjReader{
    /// <summary>
    /// 通过文件路径读取obj文件
    /// </summary>
    /// <param name="filename">最好用绝对路径</param>
    /// <param name="scale">比例,默认1</param>
    /// <a href="http://www.manew.com/forum-47-453-1.html"></a>
    /// <returns></returns>
    public static Mesh ReadMeshByObj(string filename,float scale=1f) {

        Mesh mesh = new Mesh();
        mesh.name = filename.Substring((int)Mathf.Max(filename.LastIndexOf("/"), filename.LastIndexOf("\\"))+1);

        List<Vector3> verticies = new List<Vector3>();
        List<Vector2> uvs = new List<Vector2>();
        List<Vector3> normals = new List<Vector3>();
        List<int> triangles = new List<int>();
        Vector2[] uUV=null;
        Vector3[] uNorm = null;

        System.IO.StreamReader sr = new System.IO.StreamReader(filename);
        string line;
        int lineNum = 0;
        while ((line = sr.ReadLine()) != null) {
            lineNum++;
            if (line.StartsWith("v ")) {//顶点
                line = line.Substring(2).Trim();
                string[] pos = line.Split(' ');
                if (pos.Length == 3) {
                    verticies.Add(new Vector3(float.Parse(pos[0]) / scale, float.Parse(pos[1]) / scale, float.Parse(pos[2]) / scale));
                } else {
                    Debug.Log("第" + lineNum + "行数据故障:" + line);
                }
            } else if (line.StartsWith("vt ")) {//纹理坐标
                line = line.Substring(3).Trim();
                string[] pos = line.Split(' '); 
                if (pos.Length == 2) {
                    uvs.Add(new Vector2(float.Parse(pos[0]), float.Parse(pos[1])));
                    
                } else {
                    Debug.Log("第" + lineNum + "行数据故障:" + line);
                }
            } else if(line .StartsWith("vn ")) {
                line = line.Substring(3).Trim();
                string[] pos = line.Split(' ');
                if (pos.Length == 3) {
                    normals.Add(new Vector3(float.Parse(pos[0]), float.Parse(pos[1]), float.Parse(pos[2])));
                } else {
                    Debug.Log("第" + lineNum + "行数据故障:" + line);
                }
            } else if (line.StartsWith("f ")){
                line = line.Substring(2).Trim();
                string[] pos = line.Split(' ');
                if (uUV == null) {
                    uUV = new Vector2[verticies.Count];
                }
                if (uNorm == null) {
                    uNorm = new Vector3[verticies.Count];
                }
                if (pos.Length == 3|| pos.Length == 4) {
                    if (pos[0].Contains("/")) {
                        //预处理
                        for (int i = 0; i < pos.Length; i++) {
                            pos.Replace("//", "/-/");
                            if (pos.EndsWith("/")) {
                                pos = pos + "-";
                            }
                        }
                        int[] vIndexes = new int[pos.Length];
                        
                        //解析
                        for (int i = 0; i < pos.Length; i++) {
                            string[] v_vt_vn = pos.Split('/');
                            int vIndex = int.Parse(v_vt_vn[0]);
                            if (!v_vt_vn[1].Equals("-")) {
                                int vtIndex = int.Parse(v_vt_vn[1]);
                                if(uUV[vIndex - 1].magnitude==0) {
                                    uUV[vIndex - 1] = uvs[vtIndex - 1];
                                }
                                
                            }
                            if (!v_vt_vn[2].Equals("-")) {
                                int vnIndex = int.Parse(v_vt_vn[2]);
                                if ( uNorm[vIndex - 1].magnitude == 0) {
                                    uNorm[vIndex - 1] = normals[vnIndex - 1];
                                }
                            }
                            vIndexes = vIndex;
                          
                        }
                        //加入三角形
                        for (int i = 0; i < 3; i++) {
                            triangles.Add(vIndexes - 1);
                        }
                        if (vIndexes.Length == 4) {
                            triangles.Add(vIndexes[0] - 1);
                            triangles.Add(vIndexes[2] - 1);
                            triangles.Add(vIndexes[3] - 1);
                        } 

                    } else {
                        triangles.Add(int.Parse(pos[0]) - 1);
                        triangles.Add(int.Parse(pos[1]) - 1);
                        triangles.Add(int.Parse(pos[2]) - 1);
                        if (pos.Length == 4) {
                            triangles.Add(int.Parse(pos[0]) - 1);
                            triangles.Add(int.Parse(pos[2]) - 1);
                            triangles.Add(int.Parse(pos[3]) - 1);
                        }
                    }
                } else {
                    Debug.Log("第" + lineNum + "行数据故障:" + line);
                }
            }
        }
        mesh.vertices = verticies.ToArray();
        mesh.normals = uNorm;
        mesh.triangles = triangles.ToArray();
        mesh.uv = uUV;//uvs.ToArray();
        mesh.RecalculateNormals();
        mesh.RecalculateTangents();
        mesh.RecalculateBounds();
        Debug.Log(string.Format("模型加载完成,面数:{0}点数:{1}",triangles.Count/3,verticies.Count))
        return mesh;
    }
}

展示效果

游客,如果您要查看本帖隐藏内容请回复


如果本文感动了您,别忘了点文章下方的"支持""评分"哦~

评分所用鲜花为系统赠送,不用就浪费了~

参与人数 1鲜花 +2 收起 理由
2542397398 + 2 很给力!

查看全部评分总评分 : 鲜花 +2

回复

使用道具 举报

2初来乍到
122/150
排名
15584
昨日变化

0

主题

20

帖子

122

积分

Rank: 2Rank: 2

UID
224263
好友
0
蛮牛币
24
威望
0
注册时间
2017-5-30
在线时间
56 小时
最后登录
2019-4-12
2018-10-15 21:30:17 显示全部楼层

感谢分享
回复

使用道具 举报

3偶尔光临
279/300
排名
14228
昨日变化

9

主题

103

帖子

279

积分

Rank: 3Rank: 3Rank: 3

UID
288527
好友
0
蛮牛币
3046
威望
0
注册时间
2018-7-4
在线时间
95 小时
最后登录
2019-3-22
2018-10-15 21:45:37 显示全部楼层
66666666666666666666666666666
回复 支持 反对

使用道具 举报

排名
625
昨日变化

3

主题

473

帖子

3139

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
16063
好友
0
蛮牛币
997
威望
0
注册时间
2014-3-1
在线时间
1301 小时
最后登录
2019-4-26
QQ
2018-10-15 23:08:31 显示全部楼层
感谢分享感谢分享感谢分享
回复 支持 反对

使用道具 举报

5熟悉之中
971/1000
排名
5174
昨日变化

32

主题

276

帖子

971

积分

Rank: 5Rank: 5

UID
254245
好友
3
蛮牛币
9634
威望
0
注册时间
2017-11-14
在线时间
407 小时
最后登录
2019-4-18
2018-10-16 09:07:08 显示全部楼层
感谢楼主分享
回复

使用道具 举报

7日久生情
1878/5000
排名
2201
昨日变化

12

主题

878

帖子

1878

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
218409
好友
3
蛮牛币
5135
威望
0
注册时间
2017-4-19
在线时间
364 小时
最后登录
2019-3-27
2018-10-16 09:11:54 显示全部楼层
6666666666666666
回复 支持 反对

使用道具 举报

7日久生情
2006/5000
排名
1897
昨日变化

41

主题

737

帖子

2006

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
214924
好友
4
蛮牛币
17463
威望
0
注册时间
2017-3-28
在线时间
512 小时
最后登录
2019-4-25
2018-10-16 09:20:56 显示全部楼层
大神就是大神
回复

使用道具 举报

5熟悉之中
649/1000
排名
5083
昨日变化

2

主题

55

帖子

649

积分

Rank: 5Rank: 5

UID
234627
好友
0
蛮牛币
780
威望
0
注册时间
2017-7-27
在线时间
308 小时
最后登录
2019-4-25
2018-10-16 09:25:28 显示全部楼层
谢谢分享。。。。。。。。。。。。。。。。
回复

使用道具 举报

7日久生情
1582/5000
排名
1199
昨日变化

0

主题

216

帖子

1582

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
137070
好友
0
蛮牛币
3211
威望
0
注册时间
2016-2-20
在线时间
390 小时
最后登录
2019-4-26
2018-10-16 09:50:44 显示全部楼层
感谢大佬百忙之中抽空进行的无私分享!
回复 支持 反对

使用道具 举报

6蛮牛粉丝
1354/1500
排名
1480
昨日变化

1

主题

238

帖子

1354

积分

Rank: 6Rank: 6Rank: 6

UID
2627
好友
0
蛮牛币
1032
威望
0
注册时间
2013-8-26
在线时间
259 小时
最后登录
2019-4-21
2018-10-16 09:53:23 显示全部楼层
感谢分享
回复

使用道具 举报

5熟悉之中
867/1000
排名
4473
昨日变化

3

主题

138

帖子

867

积分

Rank: 5Rank: 5

UID
168522
好友
0
蛮牛币
615
威望
0
注册时间
2016-9-14
在线时间
398 小时
最后登录
2019-4-23
2018-10-16 10:41:09 显示全部楼层
感谢分享感谢分享感谢分享666
回复 支持 反对

使用道具 举报

7日久生情
3487/5000
排名
173
昨日变化

0

主题

73

帖子

3487

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
3194
好友
0
蛮牛币
5626
威望
0
注册时间
2013-9-4
在线时间
1157 小时
最后登录
2019-4-26
2018-10-16 10:46:18 显示全部楼层
感谢分享感谢分享感谢分享感谢分享感谢分享
回复 支持 反对

使用道具 举报

7日久生情
1705/5000
排名
19946
昨日变化

12

主题

777

帖子

1705

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
158776
好友
2
蛮牛币
99
威望
0
注册时间
2016-7-26
在线时间
883 小时
最后登录
2019-3-12
2018-10-16 11:38:42 显示全部楼层
6666666666666666666666
回复 支持 反对

使用道具 举报

3偶尔光临
287/300
排名
18290
昨日变化

1

主题

42

帖子

287

积分

Rank: 3Rank: 3Rank: 3

UID
180232
好友
0
蛮牛币
168
威望
0
注册时间
2016-11-2
在线时间
210 小时
最后登录
2019-3-29
2018-10-16 11:53:55 显示全部楼层
,,,,,,,,,,,,,,,,,,,,,,,
回复

使用道具 举报

4四处流浪
371/500
排名
11658
昨日变化

3

主题

83

帖子

371

积分

Rank: 4

UID
130020
好友
0
蛮牛币
112
威望
0
注册时间
2015-11-26
在线时间
201 小时
最后登录
2018-11-12
2018-10-16 12:30:14 显示全部楼层
展示效果
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册帐号

本版积分规则