zoukankan      html  css  js  c++  java
  • 三维模型obj文件的格式解析与读取

    请先看这两个中文博客中对于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: 手上没有数据,还没有进行测试

  • 相关阅读:
    SpringMvc 大概流程分析
    HandlerMethodArgumentResolver 参数解析器
    linux 技巧:使用 screen 管理你的远程会话
    CentOS Linux解决Device eth0 does not seem to be present
    php连接oracle oracle开启扩展
    关于linux一些备份、还原,压缩,归档的命令
    Sphinx学习之sphinx的安装篇
    linux wget 命令用法详解(附实例说明)
    Linux的bg和fg命令
    linux中ctrl+z和ctrl+c的区别
  • 原文地址:https://www.cnblogs.com/Taiwantomzhang/p/3993703.html
Copyright © 2011-2022 走看看