三维模型obj文件的格式解析与读取-程序员宅基地

技术标签: python  运维  c/c++  

请先看这两个中文博客中对于obj的介绍:

读取Obj格式的模型文件(Dx10)

C++读入obj格式模型文件

更为详细的英文资料(用google或者aol搜索 "obj format"即可得到):

http://en.wikipedia.org/wiki/Wavefront_.obj_file

Wavefront OBJ File Format Summary

最详细的资料 obj spec: http://www.martinreddy.net/gfx/3d/OBJ.spec

http://people.cs.clemson.edu/~dhouse/courses/405/docs/brief-obj-file-format.html

http://www.scratchapixel.com/lessons/3d-advanced-lessons/obj-file-format/obj-file-format/

 

看完以上随便一个内容,obj的格式可以说了解了。下面实现对obj文件的读取。

 

 .obj文件中,每一行都有表明该行意义的标志符。对obj的读取中,处理以下标志符

"v"--点的坐标,三维模型为x, y, z的顺序;程序中以

1 typedef struct ObjVector3
2 {
3     ObjFloat x;
4     ObjFloat y;
5     ObjFloat z;
6 } ObjVector3;

结构存储。

"vt"--纹理坐标,程序中以

1 typedef struct ObjVector2
2 {
3     ObjFloat x;
4     ObjFloat y;
5 } ObjVector2;

结构存储

"vn"--法向量坐标,程序中与“v”的存储结构相同

"f"--面所用到的点坐标/纹理坐标/法向量坐标的索引,

"mtllib"--.obj文件用到的material库文件,“usemtl”标志符用到的material都是从material库文件中取出的

"g"--组group的名称,group里面的"f"可以使用0-N个"usemtl"对面的显示渲染进行控制,当使用了大于1个“usemtl”标志符,程序处理时对于已经读取的"f"很难控制;同时查看obj读取的源码,有的用到了这个标志符,有的没有使用该标志,有的使用了"usemtl"标志符对所读取的"f"面进行分割,本文的处理是使用"usemtl"标志符将"f"面分割为mesh,但是考虑到不同的group可以使用相同的"usemtl”标志(即不同的group都使用了 usemtl AAA),因此将"g"与"usemtl"结合起来,二者的名称作为mesh的名称

"usemtl"--参见"mtllib","g"。一旦使用了该标志符,则在该标志符后面的"f"全部受影响,直到遇到下一个"usemtl"

mesh结构,解析已经读取的“f”存储所面的点坐标/纹理坐标/法向量坐标,其结构为

 1 struct Mesh
 2 {
 3     string name;        // name
 4     ObjIntd mtl_idx;    // the index of material used by mesh 
 5 
 6     vector<ObjVector3> positions;    // "v" flag
 7     vector<ObjVector2> texcoords;    // "vt" flag
 8     vector<ObjVector3> normals;        // "vn" flag
 9     vector<ObjDword> indices;    // the indices of points of face in positions
10 
11     void reset()
12     { 
13         mtl_idx = -1;
14 
15         name.clear();
16         positions.clear();
17         texcoords.clear();
18         normals.clear();
19         indices.clear();
20     }
21 };
View Code

结构中出现的

ObjFloat ObjIntd

是一组typedef,具体为

 1 typedef int32_t ObjBool;
 2 typedef uint8_t ObjByte;
 3 typedef uint16_t ObjWord;
 4 typedef uint32_t ObjDword;
 5 typedef int8_t ObjIntb;
 6 typedef int16_t ObjIntw;
 7 typedef int32_t ObjIntd;
 8 
 9 typedef float ObjFloat;
10 typedef double ObjDouble;
View Code

 对obj文件读取的主体程序如下

 1     ObjBool obj_file_load(const string& objname)
 2     {
 3         if (objname.empty())
 4             return LIBOBJ_FALSE;
 5 
 6         int mesh_count = 0;
 7         Mesh mesh_;
 8         string groupname;
 9         string usemtl;
10         vector<ObjVector3> positions;
11         vector<ObjVector3> normals;
12         vector<ObjVector2> texcoords;
13         vector<vector<ObjVertexIndex> > faces;
14         map<string, ObjIntd> mtlMap;
15 
16         fstream obj_stream;    
17         obj_stream.open(objname.c_str(), std::ios_base::in);
18         if (!obj_stream.is_open())
19             return LIBOBJ_FALSE;
20 
21         string obj_flag;
22         while (obj_stream.good())
23         {
24             obj_stream >> obj_flag;
25 
26             if (obj_flag.empty() || (obj_flag[0] == '#'))
27             {
28                 obj_stream.ignore(1024, '\n');            // skip line
29                 continue;
30             }
31 
32             if (obj_flag == "v")            // position flag
33                 if (!obj_parse_vector3(obj_stream, positions))
34                     return LIBOBJ_FALSE;
35             else if (obj_flag == "vt")    // texture coordinate flag
36                 if (!obj_parse_vector2(obj_stream, texcoords))
37                     return LIBOBJ_FALSE;
38             else if (obj_flag == "vn")    // normal flag
39                 if (!obj_parse_vector3(obj_stream, normals))
40                     return LIBOBJ_FALSE;
41             else if (obj_flag == "g")        //group name
42                 if (!obj_parse_group(obj_stream, groupname))
43                     return LIBOBJ_FALSE;
44             else if (obj_flag == "f")        // face    flag
45             {
46                 vector<ObjVertexIndex> face;
47 
48                 obj_parse_face(obj_stream, face, positions, texcoords, normals);
49 
50                 faces.push_back(face);
51             }
52             else if (obj_flag == "mtllib")    // Material library
53             {
54                 vector<string> materialnames;
55 
56                 obj_parse_mtllib(obj_stream, materialnames);
57 
58                 for (unsigned i = 0; i < materialnames.size(); i++)
59                     if (!mtl_file_load(get_file_path(objname) + '/' + materialnames[i]))
60                         return LIBOBJ_FALSE;
61             }
62             else if (obj_flag == "usemtl")
63             {
64                 if (obj_save_mesh(positions, texcoords, normals, faces, groupname+usemtl, mesh_))
65                 {
66                     m_meshes.back().mtl_idx = mtl_index(usemtl);
67                     
68                     faces.clear();
69                     mesh_.reset();
70                 }
71 
72                 obj_parse_group(obj_stream, usemtl);
73             }
74             else
75             {
76                 obj_stream.ignore(1024, '\n');            // skip line
77             }
78         }  
79 
80         if (!obj_stream.eof())
81             return LIBOBJ_FALSE;
82 
83         //save mesh data
84         if (obj_save_mesh(positions, texcoords, normals, faces, groupname+usemtl, mesh_))
85         {
86             m_meshes.back().mtl_idx = mtl_index(usemtl);
87 
88             faces.clear();
89             mesh_.reset();
90         }
91 
92         obj_stream.close();
93 
94         return LIBOBJ_TRUE;
95     }
View Code

 

obj文件用到了.mtl格式的material,在对“mtllib”标志符解析时开始读取该.mtl文件,

对于.mtl文件的介绍,请阅读

obj + mtl 格式

mtl文件格式

MTL文件格式分析

mtl文件的简要说明

更为详细的英文资料:

http://www.fileformat.info/format/material/

http://people.cs.clemson.edu/~dhouse/courses/405/docs/brief-mtl-file-format.html

本程序中存储mtl文件的结构较为简单,只使用了mtl文件中的几个结构而没有全部处理

 1 struct ObjMaterial
 2 {
 3     string name;
 4     
 5     ObjRgb ambient;
 6     ObjRgb diffuse;
 7     ObjRgb specular;
 8 
 9     ObjWord shininess;
10     ObjByte illumination_model;
11     ObjFloat transparency;
12 
13     string ambient_texture;
14     string diffuse_texture;
15     string specular_texture;
16 };
View Code

对mtl文件的解析代码:

 1     ObjBool mtl_file_load(const string& mtlname)
 2     {
 3         if (mtlname.empty())        // if obj has no material
 4             return LIBOBJ_FALSE;
 5 
 6         ObjMaterial* pmaterial = NULL;
 7 
 8         fstream mtlstream;
 9         mtlstream.open(mtlname.c_str(), std::ios_base::in);    //open strFileName file
10         if (!mtlstream.is_open())
11             return LIBOBJ_FALSE;
12         
13         string mtlflag;
14         while (mtlstream.good())
15         {
16             mtlstream >> mtlflag;
17 
18             if (mtlflag == "newmtl")
19             {
20                 string materialname;
21                 mtlstream >> materialname;
22                 if (mtl_index(materialname) != -1)
23                     continue;
24 
25                 pmaterial = new ObjMaterial;
26                 pmaterial->name = materialname;
27                 m_materials.push_back(pmaterial);
28             }
29             else if (mtlflag == "Ka")        //Ambient color
30                 if (!mtl_parse_color(mtlstream, pmaterial->ambient))
31                     return LIBOBJ_FALSE;
32             else if (mtlflag == "Kd")        //Diffuse color
33                 if (!mtl_parse_color(mtlstream, pmaterial->diffuse))
34                     return LIBOBJ_FALSE;
35             else if (mtlflag == "Ks")        //Specular color
36                 if (!mtl_parse_color(mtlstream, pmaterial->specular))
37                     return LIBOBJ_FALSE;
38             else if (mtlflag == "Tr"/*"d"*/)        // Alpha, that is transparent
39                 if (!mtl_parse_light(mtlstream, pmaterial->transparency))
40                     return LIBOBJ_FALSE;
41             else if (mtlflag == "Ns")        //Shininess
42                 if (!mtl_parse_light(mtlstream, pmaterial->shininess))
43                     return LIBOBJ_FALSE;
44             else if (mtlflag == "illum")        //Illumination type
45                 if (!mtl_parse_light(mtlstream, pmaterial->illumination_model))
46                     return LIBOBJ_FALSE;
47             else if (mtlflag == "map_Ka")    //ambient Texture
48                 if (!mtl_parse_texture(mtlstream, pmaterial->ambient_texture))
49                     return LIBOBJ_FALSE;
50             else if (mtlflag == "map_Kd")    //diffuse Texture
51                 if (!mtl_parse_texture(mtlstream, pmaterial->diffuse_texture))
52                     return LIBOBJ_FALSE;
53             else if (mtlflag == "map_Ks")    //specular Texture
54                 if (!mtl_parse_texture(mtlstream, pmaterial->specular_texture))
55                     return LIBOBJ_FALSE;
56             else
57                 mtlstream.ignore(1024, '\n');    // ignore this line, on the assumption that the max characters at this line is 1024.                
58         }
59 
60         if (!mtlstream.eof())
61             return LIBOBJ_FALSE;
62 
63         mtlstream.close();
64         return LIBOBJ_TRUE;
65     }
View Code

完整的代码放在了https://github.com/priseup/obj_load

ps: 手上没有数据,还没有进行测试

转载于:https://www.cnblogs.com/Taiwantomzhang/p/3993703.html

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_34335458/article/details/93371984

智能推荐

分布式光纤传感器的全球与中国市场2022-2028年:技术、参与者、趋势、市场规模及占有率研究报告_预计2026年中国分布式传感器市场规模有多大-程序员宅基地

文章浏览阅读3.2k次。本文研究全球与中国市场分布式光纤传感器的发展现状及未来发展趋势,分别从生产和消费的角度分析分布式光纤传感器的主要生产地区、主要消费地区以及主要的生产商。重点分析全球与中国市场的主要厂商产品特点、产品规格、不同规格产品的价格、产量、产值及全球和中国市场主要生产商的市场份额。主要生产商包括:FISO TechnologiesBrugg KabelSensor HighwayOmnisensAFL GlobalQinetiQ GroupLockheed MartinOSENSA Innovati_预计2026年中国分布式传感器市场规模有多大

07_08 常用组合逻辑电路结构——为IC设计的延时估计铺垫_基4布斯算法代码-程序员宅基地

文章浏览阅读1.1k次,点赞2次,收藏12次。常用组合逻辑电路结构——为IC设计的延时估计铺垫学习目的:估计模块间的delay,确保写的代码的timing 综合能给到多少HZ,以满足需求!_基4布斯算法代码

OpenAI Manager助手(基于SpringBoot和Vue)_chatgpt网页版-程序员宅基地

文章浏览阅读3.3k次,点赞3次,收藏5次。OpenAI Manager助手(基于SpringBoot和Vue)_chatgpt网页版

关于美国计算机奥赛USACO,你想知道的都在这_usaco可以多次提交吗-程序员宅基地

文章浏览阅读2.2k次。USACO自1992年举办,到目前为止已经举办了27届,目的是为了帮助美国信息学国家队选拔IOI的队员,目前逐渐发展为全球热门的线上赛事,成为美国大学申请条件下,含金量相当高的官方竞赛。USACO的比赛成绩可以助力计算机专业留学,越来越多的学生进入了康奈尔,麻省理工,普林斯顿,哈佛和耶鲁等大学,这些同学的共同点是他们都参加了美国计算机科学竞赛(USACO),并且取得过非常好的成绩。适合参赛人群USACO适合国内在读学生有意向申请美国大学的或者想锻炼自己编程能力的同学,高三学生也可以参加12月的第_usaco可以多次提交吗

MySQL存储过程和自定义函数_mysql自定义函数和存储过程-程序员宅基地

文章浏览阅读394次。1.1 存储程序1.2 创建存储过程1.3 创建自定义函数1.3.1 示例1.4 自定义函数和存储过程的区别1.5 变量的使用1.6 定义条件和处理程序1.6.1 定义条件1.6.1.1 示例1.6.2 定义处理程序1.6.2.1 示例1.7 光标的使用1.7.1 声明光标1.7.2 打开光标1.7.3 使用光标1.7.4 关闭光标1.8 流程控制的使用1.8.1 IF语句1.8.2 CASE语句1.8.3 LOOP语句1.8.4 LEAVE语句1.8.5 ITERATE语句1.8.6 REPEAT语句。_mysql自定义函数和存储过程

半导体基础知识与PN结_本征半导体电流为0-程序员宅基地

文章浏览阅读188次。半导体二极管——集成电路最小组成单元。_本征半导体电流为0

随便推点

【Unity3d Shader】水面和岩浆效果_unity 岩浆shader-程序员宅基地

文章浏览阅读2.8k次,点赞3次,收藏18次。游戏水面特效实现方式太多。咱们这边介绍的是一最简单的UV动画(无顶点位移),整个mesh由4个顶点构成。实现了水面效果(左图),不动代码稍微修改下参数和贴图可以实现岩浆效果(右图)。有要思路是1,uv按时间去做正弦波移动2,在1的基础上加个凹凸图混合uv3,在1、2的基础上加个水流方向4,加上对雾效的支持,如没必要请自行删除雾效代码(把包含fog的几行代码删除)S..._unity 岩浆shader

广义线性模型——Logistic回归模型(1)_广义线性回归模型-程序员宅基地

文章浏览阅读5k次。广义线性模型是线性模型的扩展,它通过连接函数建立响应变量的数学期望值与线性组合的预测变量之间的关系。广义线性模型拟合的形式为:其中g(μY)是条件均值的函数(称为连接函数)。另外,你可放松Y为正态分布的假设,改为Y 服从指数分布族中的一种分布即可。设定好连接函数和概率分布后,便可以通过最大似然估计的多次迭代推导出各参数值。在大部分情况下,线性模型就可以通过一系列连续型或类别型预测变量来预测正态分布的响应变量的工作。但是,有时候我们要进行非正态因变量的分析,例如:(1)类别型.._广义线性回归模型

HTML+CSS大作业 环境网页设计与实现(垃圾分类) web前端开发技术 web课程设计 网页规划与设计_垃圾分类网页设计目标怎么写-程序员宅基地

文章浏览阅读69次。环境保护、 保护地球、 校园环保、垃圾分类、绿色家园、等网站的设计与制作。 总结了一些学生网页制作的经验:一般的网页需要融入以下知识点:div+css布局、浮动、定位、高级css、表格、表单及验证、js轮播图、音频 视频 Flash的应用、ul li、下拉导航栏、鼠标划过效果等知识点,网页的风格主题也很全面:如爱好、风景、校园、美食、动漫、游戏、咖啡、音乐、家乡、电影、名人、商城以及个人主页等主题,学生、新手可参考下方页面的布局和设计和HTML源码(有用点赞△) 一套A+的网_垃圾分类网页设计目标怎么写

C# .Net 发布后,把dll全部放在一个文件夹中,让软件目录更整洁_.net dll 全局目录-程序员宅基地

文章浏览阅读614次,点赞7次,收藏11次。之前找到一个修改 exe 中 DLL地址 的方法, 不太好使,虽然能正确启动, 但无法改变 exe 的工作目录,这就影响了.Net 中很多获取 exe 执行目录来拼接的地址 ( 相对路径 ),比如 wwwroot 和 代码中相对目录还有一些复制到目录的普通文件 等等,它们的地址都会指向原来 exe 的目录, 而不是自定义的 “lib” 目录,根本原因就是没有修改 exe 的工作目录这次来搞一个启动程序,把 .net 的所有东西都放在一个文件夹,在文件夹同级的目录制作一个 exe._.net dll 全局目录

BRIEF特征点描述算法_breif description calculation 特征点-程序员宅基地

文章浏览阅读1.5k次。本文为转载,原博客地址:http://blog.csdn.net/hujingshuang/article/details/46910259简介 BRIEF是2010年的一篇名为《BRIEF:Binary Robust Independent Elementary Features》的文章中提出,BRIEF是对已检测到的特征点进行描述,它是一种二进制编码的描述子,摈弃了利用区域灰度..._breif description calculation 特征点

房屋租赁管理系统的设计和实现,SpringBoot计算机毕业设计论文_基于spring boot的房屋租赁系统论文-程序员宅基地

文章浏览阅读4.1k次,点赞21次,收藏79次。本文是《基于SpringBoot的房屋租赁管理系统》的配套原创说明文档,可以给应届毕业生提供格式撰写参考,也可以给开发类似系统的朋友们提供功能业务设计思路。_基于spring boot的房屋租赁系统论文