zoukankan      html  css  js  c++  java
  • 图形学基础 | 实现OBJ文件的载入

    1. tiny_obj_loader.h 的使用
    include这个头文件需要先定义一个宏

    #define TINYOBJLOADER_IMPLEMENTATION
    #include "tiny_obj_loader.h"
    1
    2
    2. tiny_obj_loader.h 中数据结构的介绍
    2.1 attrib_t
    // Vertex attributes
    typedef struct {
    std::vector<real_t> vertices; // 'v'
    std::vector<real_t> normals; // 'vn'
    std::vector<real_t> texcoords; // 'vt'
    std::vector<real_t> colors; // extension: vertex colors
    } attrib_t;
    1
    2
    3
    4
    5
    6
    7
    attrib_t 主要存放的就是 OBJ文件中所有的顶点数据信息. 比如:

    vertices : 顶点位置信息
    normals : 法线信息
    texcoords : 纹理坐标信息
    colors : 颜色信息
    2.2 shape_t
    typedef struct {
    std::string name;
    mesh_t mesh;
    path_t path;
    } shape_t;
    1
    2
    3
    4
    5
    shape_t 表示的是比如这个物体的一个部分.
    在 OBJ文件中, 如 o xxx 表示一个部分的开始.主要存储的信息有:

    name : 这部分的名称 xxx
    mesh : 构成这个部分的顶点信息. 这里通过使用索引的方式来记录 . 因为所有的数据信息都放在了 attrib_t 中.
    path : pairs of indices for lines 按注释的意思是 线段的索引. 可能有问题. 因为没有用到这个.
    在这里重点在于 mesh_t 这个数据结构:

    // Index struct to support different indices for vtx/normal/texcoord.
    // -1 means not used.
    typedef struct {
    int vertex_index;
    int normal_index;
    int texcoord_index;
    } index_t;

    typedef struct {
    std::vector<index_t> indices;
    std::vector<unsigned char> num_face_vertices; // The number of vertices per
    // face. 3 = polygon, 4 = quad,
    // ... Up to 255.
    std::vector<int> material_ids; // per-face material ID
    std::vector<unsigned int> smoothing_group_ids; // per-face smoothing group
    // ID(0 = off. positive value
    // = group id)
    std::vector<tag_t> tags; // SubD tag
    } mesh_t;
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    索引信息重要放在 std::vector<index_t> indices; 中.
    index_t 中是哪些数据信息的索引下标呢:

    vertices : 顶点位置信息
    normals : 法线信息
    texcoords : 纹理坐标信息
    3. 通过 tiny_obj_loader.h 读取并存储数据
    主要参考了 loader_example.cc 的 PrintInfo(attrib, shapes, materials) 这个函数
    bool Object::make_mesh_and_material_by_obj(const char* filename, const char* basepath,bool triangulate){

    std::cout << "Loading " << filename << std::endl;

    tinyobj::attrib_t attrib; // 所有的数据放在这里
    std::vector<tinyobj::shape_t> shapes;
    // 一个shape,表示一个部分,
    // 其中主要存的是索引坐标 mesh_t类,
    // 放在indices中
    /*
    // -1 means not used.
    typedef struct {
    int vertex_index;
    int normal_index;
    int texcoord_index;
    } index_t;
    */
    std::vector<tinyobj::material_t> materials;

    std::string warn;
    std::string err;

    bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err, filename,
    basepath, triangulate);

    // 接下里就是从上面的属性中取值了
    if (!warn.empty()) {
    std::cout << "WARN: " << warn << std::endl;
    }

    if (!err.empty()) {
    std::cerr << "ERR: " << err << std::endl;
    }

    if (!ret) {
    printf("Failed to load/parse .obj. ");
    return false;
    }

    // ========================== 将读入的模型数据存入自己定义的数据结构中 ========================

    std::cout << "# of vertices : " << (attrib.vertices.size() / 3) << std::endl;
    std::cout << "# of normals : " << (attrib.normals.size() / 3) << std::endl;
    std::cout << "# of texcoords : " << (attrib.texcoords.size() / 2)
    << std::endl;

    std::cout << "# of shapes : " << shapes.size() << std::endl;
    std::cout << "# of materials : " << materials.size() << std::endl;

    ///1. 获取各种材质和纹理
    {
    for (int i = 0; i < materials.size(); i++) {
    Material* m = new Material();
    tinyobj::material_t tm = materials[i];
    string name = tm.name;
    if (name.size()) {
    m->name = name;
    }
    m->ambient.r = tm.ambient[0];
    m->ambient.g = tm.ambient[1];
    m->ambient.b = tm.ambient[2];

    m->diffuse.r = tm.diffuse[0];
    m->diffuse.g = tm.diffuse[1];
    m->diffuse.b = tm.diffuse[2];

    m->specular.r = tm.specular[0];
    m->specular.g = tm.specular[1];
    m->specular.b = tm.specular[2];

    m->transmittance.r = tm.transmittance[0];
    m->transmittance.g = tm.transmittance[1];
    m->transmittance.b = tm.transmittance[2];

    m->emission.r = tm.emission[0];
    m->emission.g = tm.emission[1];
    m->emission.b = tm.emission[2];

    m->shininess = tm.shininess;
    m->ior = tm.ior;
    m->dissolve = tm.dissolve;
    m->illum = tm.illum;
    m->pad0 = tm.pad0;

    m->ambient_tex_id = -1;
    m->diffuse_tex_id = -1;
    m->specular_tex_id = -1;
    m->specular_highlight_tex_id = -1;
    m->bump_tex_id = -1;
    m->displacement_tex_id = -1;
    m->alpha_tex_id = -1;

    m->ambient_texname = "";
    m->diffuse_texname = "";
    m->specular_texname = "";
    m->specular_highlight_texname = "";
    m->bump_texname = "";
    m->displacement_texname = "";
    m->alpha_texname = "";

    if (tm.ambient_texname.size()) {

    }
    if (tm.diffuse_texname.size()) {

    }
    if (tm.specular_texname.size()) {

    }
    if (tm.specular_highlight_texname.size()) {

    }
    if (tm.bump_texname.size()) {

    }
    if (tm.displacement_texname.size()) {
    }
    if (tm.alpha_texname.size()) {

    }

    this->materials.push_back(m);
    }


    }

    /// 2.顶点数据
    {
    // For each shape 遍历每一个部分
    for (size_t i = 0; i < shapes.size(); i++) {
    // 这部分的名称
    printf("shape[%ld].name = %s ", static_cast<long>(i),
    shapes[i].name.c_str());
    // 网格的点数
    printf("Size of shape[%ld].mesh.indices: %lu ", static_cast<long>(i),
    static_cast<unsigned long>(shapes[i].mesh.indices.size()));
    //printf("Size of shape[%ld].path.indices: %lu ", static_cast<long>(i),static_cast<unsigned long>(shapes[i].path.indices.size()));

    //assert(shapes[i].mesh.num_face_vertices.size() == shapes[i].mesh.material_ids.size());
    //assert(shapes[i].mesh.num_face_vertices.size() == shapes[i].mesh.smoothing_group_ids.size());

    printf("shape[%ld].num_faces: %lu ", static_cast<long>(i),
    static_cast<unsigned long>(shapes[i].mesh.num_face_vertices.size()));

    Model* model = new Model(); // 每一部分的模型数据
    // 顶点数量 = face的数量x3
    model->mesh_num = shapes[i].mesh.num_face_vertices.size(http://www.my516.com) * 3;
    // 开辟空间
    Vertex *mesh_data = new Vertex[model->mesh_num];
    size_t index_offset = 0;

    // For each face
    for (size_t f = 0; f < shapes[i].mesh.num_face_vertices.size(); f++) {
    size_t fnum = shapes[i].mesh.num_face_vertices[f];

    // 获得所索引下标
    tinyobj::index_t idx;
    int vertex_index[3];
    int normal_index[3];
    int texcoord_index[3];
    for (size_t v = 0; v < fnum; v++) {
    idx = shapes[i].mesh.indices[index_offset + v];
    vertex_index[v] = idx.vertex_index;
    texcoord_index[v] = idx.texcoord_index;
    normal_index[v] = idx.normal_index;
    }
    for (size_t v = 0; v < fnum; v++) {
    // v
    mesh_data[index_offset + v].pos.x = attrib.vertices[(vertex_index[v]) * 3 + 0];
    mesh_data[index_offset + v].pos.y = attrib.vertices[(vertex_index[v]) * 3 + 1];
    mesh_data[index_offset + v].pos.z = attrib.vertices[(vertex_index[v]) * 3 + 2];
    mesh_data[index_offset + v].pos.w = 1.0f;

    // vt
    mesh_data[index_offset + v].tc.u = attrib.texcoords[texcoord_index[v] * 2 + 0];
    mesh_data[index_offset + v].tc.v = attrib.texcoords[texcoord_index[v] * 2 + 1];

    // vn
    mesh_data[index_offset + v].normal.x = attrib.normals[normal_index[v] * 3 + 0];
    mesh_data[index_offset + v].normal.y = attrib.normals[normal_index[v] * 3 + 1];
    mesh_data[index_offset + v].normal.z = attrib.normals[normal_index[v] * 3 + 2];
    mesh_data[index_offset + v].normal.w = 1.0f;

    // color
    mesh_data[index_offset + v].color.r = 1.0f;
    mesh_data[index_offset + v].color.g = 1.0f;
    mesh_data[index_offset + v].color.b = 1.0f;
    mesh_data[index_offset + v].color.a = 1.0f;
    }

    // 偏移
    index_offset += fnum;
    }
    model->mesh = mesh_data;
    models.push_back(model);
    }
    }

    std::cout << "# Loading Complete #"<< std::endl;
    //PrintInfo(attrib, shapes, materials);
    return true;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    实现结果
    meshlab 观看效果.


    导入光栅化渲染器的线框模型
    --------------------- 

  • 相关阅读:
    开发人员的幽默
    SpaceBuilder 1.0RC源代码提供下载
    什么是Alpha,Beta,RC,RTM版
    SQLite数据库参数化编程时,采用命名参数的方式
    ASP.NET第四天数据库知识
    ASP.NET第五天数据库知识
    ASP.NET第五天HTML基础
    ASP.NET第二天HTML基础
    ASP.NET第四天HTML基础
    ASP.NET第一天HTML基础
  • 原文地址:https://www.cnblogs.com/hyhy904/p/11058057.html
Copyright © 2011-2022 走看看