文章目录

  • OBJ格式解析
  • 一、OBJ格式
  • 二、vtkOBJReader源码解析
    • 1.主要部分
  • 总结

OBJ格式解析

通过解读vtk源码中对OBJ文件的读取代码,讲解如何获取obj模型的顶点(vertex)信息,法线信息,纹理信息以及点(Point)、线、面等主要元素的提取。


一、OBJ格式

1.OBJ文件示例

# 一些注释mtllib cube.mtl
g default
v -0.500000 -0.500000 0.500000
v 0.500000 -0.500000 0.500000
v -0.500000 0.500000 0.500000
v 0.500000 0.500000 0.500000
v -0.500000 0.500000 -0.500000
v 0.500000 0.500000 -0.500000
v -0.500000 -0.500000 -0.500000
v 0.500000 -0.500000 -0.500000
vt 0.001992 0.001992
vt 0.998008 0.001992
vt 0.001992 0.998008
vt 0.998008 0.998008
vt 0.001992 0.001992
vt 0.998008 0.001992
vt 0.001992 0.998008
vt 0.998008 0.998008
vt 0.001992 0.001992
vt 0.998008 0.001992
vt 0.001992 0.998008
vt 0.998008 0.998008
vt 0.001992 0.001992
vt 0.998008 0.001992
vt 0.001992 0.998008
vt 0.998008 0.998008
vt 0.001992 0.001992
vt 0.998008 0.001992
vt 0.001992 0.998008
vt 0.998008 0.998008
vt 0.998008 0.998008
vt 0.001992 0.998008
vt 0.998008 0.001992
vt 0.001992 0.001992
vn 0.000000 0.000000 1.000000
vn 0.000000 0.000000 1.000000
vn 0.000000 0.000000 1.000000
vn 0.000000 0.000000 1.000000
vn 0.000000 1.000000 0.000000
vn 0.000000 1.000000 0.000000
vn 0.000000 1.000000 0.000000
vn 0.000000 1.000000 0.000000
vn 0.000000 0.000000 -1.000000
vn 0.000000 0.000000 -1.000000
vn 0.000000 0.000000 -1.000000
vn 0.000000 0.000000 -1.000000
vn 0.000000 -1.000000 0.000000
vn 0.000000 -1.000000 0.000000
vn 0.000000 -1.000000 0.000000
vn 0.000000 -1.000000 0.000000
vn 1.000000 0.000000 0.000000
vn 1.000000 0.000000 0.000000
vn 1.000000 0.000000 0.000000
vn 1.000000 0.000000 0.000000
vn -1.000000 0.000000 0.000000
vn -1.000000 0.000000 0.000000
vn -1.000000 0.000000 0.000000
vn -1.000000 0.000000 0.000000
s 1
g pCube1
usemtl file1SG
f 1/1/1 2/2/2 3/3/3
f 3/3/3 2/2/2 4/4/4
s 2
f 3/13/5 4/14/6 5/15/7
f 5/15/7 4/14/6 6/16/8
s 3
f 5/21/9 6/22/10 7/23/11
f 7/23/11 6/22/10 8/24/12
s 4
f 7/17/13 8/18/14 1/19/15
f 1/19/15 8/18/14 2/20/16
s 5
f 2/5/17 8/6/18 4/7/19
f 4/7/19 8/6/18 6/8/20
s 6
f 7/9/21 1/10/22 5/11/23
f 5/11/23 1/10/22 3/12/24

2.格式分析

  • 注释以#开头;
  • v表示模型的顶点坐标,表示为: v x y z
  • vn:法线坐标,表示为:vn x y z
  • vt:纹理坐标,一般每个坐标包含两个值,表示为:vt u v w
  • p:Point元素;
  • l:线
  • f:面,可以有多个顶点表示;
    • f v1 v2 v3 … ,仅由三个以上顶点索引组成;
    • f v1/vt1 v2/vt2 v3/vt3 …,由顶点和纹理索引组成;
    • f v1//vn1 v2//vn2 v3//vn3 …,由顶点和法线索引组成;
    • f v1/vt1/vn1 v2/vt2/vn2 v3/vt3/vn3 …,由顶点,纹理和法线索引组成;
      索引的形成是按照顶点、法线,纹理信息在文件中的先后顺序从1开始编号,可以采用负索引,表示倒数第几个顶点,法线,纹理,一般由三个顶点组成一个面,也有多个顶点的情况。

其它更多信息请查看补充部分。

补充:
http://netghost.narod.ru/gff/graphics/summary/waveobj.htm#WAVEOBJ-DMYID.3
https://blog.csdn.net/qq_26900671/article/details/81739977
https://www.cnblogs.com/daofaziran/p/11540517.html

二、vtkOBJReader源码解析

1.主要部分

/*---------------------------------------------------------------------------*\This is only partial support for the OBJ format, which is quite complicated.
To find a full specification, search the net for "OBJ format", eg.:http://en.wikipedia.org/wiki/Objhttp://netghost.narod.ru/gff/graphics/summary/waveobj.htmWe support the following types:v <x> <y> <z>vertexvn <x> <y> <z>vertex normalvt <x> <y>texture coordinatef <v_a> <v_b> <v_c> ...polygonal face linking vertices v_a, v_b, v_c, etc. whichare 1-based indices into the vertex listf <v_a>/<t_a> <v_b>/<t_b> ...polygonal face as above, but with texture coordinates foreach vertex. t_a etc. are 1-based indices into the texturecoordinates list (from the vt lines)f <v_a>/<t_a>/<n_a> <v_b>/<t_b>/<n_b> ...polygonal face as above, with a normal at each vertex, as a1-based index into the normals list (from the vn lines)f <v_a>//<n_a> <v_b>//<n_b> ...polygonal face as above but without texture coordinates.Per-face tcoords and normals are supported by duplicatingthe vertices on each face as necessary.l <v_a> <v_b> ...lines linking vertices v_a, v_b, etc. which are 1-basedindices into the vertex listp <v_a> <v_b> ...points located at the vertices v_a, v_b, etc. which are 1-basedindices into the vertex list\*---------------------------------------------------------------------------*///部分代码float xyz[3];//按行来解析数据...// in the OBJ format the first characters determine how to interpret the line://为定点信息if (strcmp(cmd, "v") == 0){// this is a vertex definition, expect three floats, separated by whitespace://获取坐标值if (sscanf(pLine, "%f %f %f", xyz, xyz + 1, xyz + 2) == 3){points->InsertNextPoint(xyz);}else{vtkErrorMacro(<< "Error reading 'v' at line " << lineNr);everything_ok = false;}}//纹理坐标else if (strcmp(cmd, "vt") == 0){// this is a tcoord, expect two floats, separated by whitespace:// 获取坐标if (sscanf(pLine, "%f %f", xyz, xyz + 1) == 2){tcoords->InsertNextTuple(xyz);}else{vtkErrorMacro(<< "Error reading 'vt' at line " << lineNr);everything_ok = false;}}//法线坐标else if (strcmp(cmd, "vn") == 0){// this is a normal, expect three floats, separated by whitespace://获取坐标if (sscanf(pLine, "%f %f %f", xyz, xyz + 1, xyz + 2) == 3){normals->InsertNextTuple(xyz);hasNormals = true;}else{vtkErrorMacro(<< "Error reading 'vn' at line " << lineNr);everything_ok = false;}}//点元素else if (strcmp(cmd, "p") == 0){// this is a point definition, consisting of 1-based indices separated by whitespace and /pointElems->InsertNextCell(0); // we don't yet know how many points are to comeint nVerts = 0; // keep a count of how many there arewhile (everything_ok && pLine < pEnd){// find next non-whitespace characterwhile (isspace(*pLine) && pLine < pEnd) { pLine++; }if (pLine < pEnd)         // there is still data left on this line{int iVert;if (sscanf(pLine, "%d", &iVert) == 1){pointElems->InsertCellPoint(iVert - 1);nVerts++;}else if (strcmp(pLine, "\\\n") == 0){// handle backslash-newline continuationif (fgets(rawLine, MAX_LINE, in) != NULL){lineNr++;pLine = rawLine;pEnd = rawLine + strlen(rawLine);continue;}else{vtkErrorMacro(<< "Error reading continuation line at line " << lineNr);everything_ok = false;}}else{vtkErrorMacro(<< "Error reading 'p' at line " << lineNr);everything_ok = false;}// skip over what we just sscanf'd// (find the first whitespace character)while (!isspace(*pLine) && pLine < pEnd) { pLine++; }}}if (nVerts < 1){vtkErrorMacro(<< "Error reading file near line " << lineNr<< " while processing the 'p' command");everything_ok = false;}// now we know how many points there were in this cellpointElems->UpdateCellCount(nVerts);}//线元素else if (strcmp(cmd, "l") == 0){// this is a line definition, consisting of 1-based indices separated by whitespace and /lineElems->InsertNextCell(0); // we don't yet know how many points are to comeint nVerts = 0; // keep a count of how many there arewhile (everything_ok && pLine < pEnd){// find next non-whitespace characterwhile (isspace(*pLine) && pLine < pEnd) { pLine++; }if (pLine < pEnd)         // there is still data left on this line{int iVert, dummyInt;if (sscanf(pLine, "%d/%d", &iVert, &dummyInt) == 2){// we simply ignore texture informationlineElems->InsertCellPoint(iVert - 1);nVerts++;}else if (sscanf(pLine, "%d", &iVert) == 1){lineElems->InsertCellPoint(iVert - 1);nVerts++;}else if (strcmp(pLine, "\\\n") == 0){// handle backslash-newline continuationif (fgets(rawLine, MAX_LINE, in) != NULL){lineNr++;pLine = rawLine;pEnd = rawLine + strlen(rawLine);continue;}else{vtkErrorMacro(<< "Error reading continuation line at line " << lineNr);everything_ok = false;}}else{vtkErrorMacro(<< "Error reading 'l' at line " << lineNr);everything_ok = false;}// skip over what we just sscanf'd// (find the first whitespace character)while (!isspace(*pLine) && pLine < pEnd) { pLine++; }}}if (nVerts < 2){vtkErrorMacro(<< "Error reading file near line " << lineNr<< " while processing the 'l' command");everything_ok = false;}// now we know how many points there were in this celllineElems->UpdateCellCount(nVerts);}//面元素else if (strcmp(cmd, "f") == 0){// this is a face definition, consisting of 1-based indices separated by whitespace and /polys->InsertNextCell(0); // we don't yet know how many points are to cometcoord_polys->InsertNextCell(0);normal_polys->InsertNextCell(0);int nVerts = 0, nTCoords = 0, nNormals = 0; // keep a count of how many of each there arewhile (everything_ok && pLine < pEnd){// find the first non-whitespace characterwhile (isspace(*pLine) && pLine < pEnd) { pLine++; }if (pLine < pEnd)         // there is still data left on this line{int iVert, iTCoord, iNormal;//1.获取顶点、纹理、法线索引if (sscanf(pLine, "%d/%d/%d", &iVert, &iTCoord, &iNormal) == 3){polys->InsertCellPoint(iVert - 1); // convert to 0-based indexnVerts++;tcoord_polys->InsertCellPoint(iTCoord - 1);nTCoords++;normal_polys->InsertCellPoint(iNormal - 1);nNormals++;if (iTCoord != iVert)tcoords_same_as_verts = false;if (iNormal != iVert)normals_same_as_verts = false;}//2.获取顶点、法线索引else if (sscanf(pLine, "%d//%d", &iVert, &iNormal) == 2){polys->InsertCellPoint(iVert - 1);nVerts++;normal_polys->InsertCellPoint(iNormal - 1);nNormals++;if (iNormal != iVert)normals_same_as_verts = false;}//3.获取顶点、纹理索引else if (sscanf(pLine, "%d/%d", &iVert, &iTCoord) == 2){polys->InsertCellPoint(iVert - 1);nVerts++;tcoord_polys->InsertCellPoint(iTCoord - 1);nTCoords++;if (iTCoord != iVert)tcoords_same_as_verts = false;}//4.获取顶点索引else if (sscanf(pLine, "%d", &iVert) == 1){polys->InsertCellPoint(iVert - 1);nVerts++;}else if (strcmp(pLine, "\\\n") == 0){// handle backslash-newline continuationif (fgets(rawLine, MAX_LINE, in) != NULL){lineNr++;pLine = rawLine;pEnd = rawLine + strlen(rawLine);continue;}else{vtkErrorMacro(<< "Error reading continuation line at line " << lineNr);everything_ok = false;}}else{vtkErrorMacro(<< "Error reading 'f' at line " << lineNr);everything_ok = false;}// skip over what we just read// (find the first whitespace character)while (!isspace(*pLine) && pLine < pEnd) { pLine++; }}}// count of tcoords and normals must be equal to number of vertices or zeroif (nVerts < 3 ||(nTCoords > 0 && nTCoords != nVerts) ||(nNormals > 0 && nNormals != nVerts)){vtkErrorMacro(<< "Error reading file near line " << lineNr<< " while processing the 'f' command");everything_ok = false;}// now we know how many points there were in this cellpolys->UpdateCellCount(nVerts);tcoord_polys->UpdateCellCount(nTCoords);normal_polys->UpdateCellCount(nNormals);// also make a note of whether any cells have tcoords, and whether any have normalsif (nTCoords > 0) { hasTCoords = true; }if (nNormals > 0) { hasNormals = true; }}else{//vtkDebugMacro(<<"Ignoring line: "<<rawLine);}

总结

熟悉vtk框架,将obj转换为其他模型文件以及提取有效信息。

3D模型格式解析(OBJ)相关推荐

  1. 3d展示网页开发_超实用:一篇文章带你了解市面上主流通用的3D模型格式

    说到格式,相信大家都不陌生. 随着互联网的普及,我们几乎每天都会和不同的格式打交道,文本的TXT.图片的JPG.视频的MP4,就连压缩包也有不同的格式. 通俗来说,你可以把"格式" ...

  2. 【3D】常见的3D模型格式介绍

    OBJ OBJ文件是Alias | Wavefront公司为它的一套基于工作站的3D建模和动画软件"AdvancedVisualizer"开发的一种标准3D模型文件格式. OBJ文 ...

  3. 3D模型格式的一点总结

    通俗来说,你可以把"格式"理解成基于同一规范的技术表征,也可以再简化点把它看成一种分类方式.对于3D模型来说,格式更是种类繁多.不同应用领域的.不同功能属性的,加密的.独有的.通用 ...

  4. osgb转json_超实用:一篇文章带你了解市面上主流通用的3D模型格式

    原标题:超实用:一篇文章带你了解市面上主流通用的3D模型格式 3D模型格式知多少 说到格式,相信大家都不陌生. 随着互联网的普及,我们几乎每天都会和不同的格式打交道,文本的TXT.图片的JPG.视频的 ...

  5. 开源3d模型格式转换_将您的开源业务转换为基于收入的模型时应考虑的因素

    开源3d模型格式转换 是否可以通过一组简单的正式语言转换规则将SQL作为一种语言集成并标准化到Java中? 是的,它可以. 当总部位于瑞士苏黎世的开源公司启动名为jOOQ的新数据库抽象软件项目时, D ...

  6. HOOPS助力AVEVA数字化转型:支持多种3D模型格式转换!

    行业: 电力和公用事业.化工.造船.能源.采矿业 挑战: 创建大规模复杂资产的客户需要汇集多种类型的数据,以支持初始设计和创建强大的数字双胞胎:现有版本的产品只支持半打CAD格式:有限的内部开发资源限 ...

  7. 3D模型文件--STL,OBJ,3DS

    STL格式 全称是Stereolithographic,是3DSystem公司提出的3D模型文件格式,它采用三角形离散地近似表示三维模型,目前已被工业界认为是快速成形领域的标准描述文件格式. STL文 ...

  8. CAD Assistant - 3D模型格式转换利器

    Open Cascade CAD Assistant 是一款功能强大的离线 3D CAD 查看器和转换器,具有简单直观的界面,可免费用于个人和商业用途.该解决方案最初是作为移动平台上 Open CAS ...

  9. 【Unity】模型文件格式、常见3D模型格式

    文章目录 模型文件格式 支持的模型文件格式 标准文件格式 专有文件格式 不支持的模型文件格式 从3ds Max 导入对象 从 Maya 导入对象 限制 常见的3D软件格式 .fbx 格式 .obj 格 ...

最新文章

  1. Python 包管理工具解惑
  2. 获取DataTable前几条数据
  3. C# 公共控件及程序制作流程
  4. CUDA程序优化技巧
  5. git 可视化工具_WEB开发者必备工具集
  6. hp laser103 属性没有配置项_哦?在hp打印机面板上就可以更改打印机ip地址
  7. NPER用计算机怎么算,计算机财务管理第三章详解.doc
  8. gateway sentinel 熔断 不起作用_微服务Gateway新一代网关
  9. android获取位图字节数,Android中获取图片尺寸大小两种方法
  10. npoi 所有列调整为一页_Word节约纸张打印 多页内容一页打印
  11. 用Python3开发简单应用——兽人之袭
  12. 新版盲盒交友小程序源码下载
  13. java gps 纠偏_【实测可用】GPS纠偏算法-Java版
  14. 钢笔墨水能否代替打印机墨水_喷墨打印机该用染料墨水还是颜料墨水?
  15. c语言 修正正弦曲线,[原创]正弦曲线
  16. 漫威十年,好莱坞的转型焦虑
  17. Linux dd 命令 限制文件夹大小
  18. html实现微信公众号,H5在微信公众号的下拉刷新实现
  19. DllPlugin动态链接库插件
  20. Linux下常见错误码

热门文章

  1. LeetCode MySQL 1543. Fix Product Name Format(trim去空格+upper/lower大小写)
  2. LeetCode MySQL 1435. 制作会话柱状图
  3. 程序员面试金典 - 面试题 04.06. 后继者(循环中序遍历)
  4. POJ 2453 贪心应用
  5. 漂亮的html页面源码_爬虫数据分析之html
  6. clob和blob是不是可以进行模糊查询_你知道什么是 MySQL 的模糊查询?
  7. 进程间通信-Queue 消息队列 先进先出
  8. python中pop用法_Python dict pop()用法及代码示例
  9. python网络编程内容_Python网络编程
  10. 做一个好的搜索引擎有多难