Implementing OBJ File Loading by Renting ssc One-color Program

Posted by Rado001 on Sun, 05 May 2019 13:16:04 +0200

OBJ File Format Introduces ssc One-color Program Rental QQ2952777280

An introduction to file format can be found in the previous article.
Graphics Foundation | Explain obj file format in 3D

OBJ file loading

Here we find an open source library for OBJ file parsing, tinyobjloader.
There is only one header file tiny_obj_loader.h
The main usage can refer to loader_example.ccDemo on Github.

  1. Use of tiny_obj_loader.h

include This header file needs to define a macro first

#define TINYOBJLOADER_IMPLEMENTATION
#include "tiny_obj_loader.h"

  1. Introduction of Data Structure in 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;

attrib_t mainly stores all vertex data information in OBJ files. For example:

vertices: vertex location information
Norals: Normal information
texcoords: Texture coordinate information
colors: Color information
2.2 shape_t

typedef struct {
std::string name;
mesh_t mesh;
path_t path;
} shape_t;

shape_t denotes, for example, a part of the object.
In OBJ files, for example, o xxx represents the beginning of a part. The main information stored is:

Name: The name of this section xxx
mesh: Vertex information that makes up this part. Here it is recorded by using an index. Because all data information is placed in attrib_t.
Path: pairs of indices for lines are indexed by annotation. It may be problematic because this is not used.
The emphasis here is on the mesh_t data structure:

// 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;

Index information is important in std:: vector < index_t > indices.
What data information index subscripts are in index_t?

vertices: vertex location information
Norals: Normal information
texcoords: Texture coordinate information

  1. Read and store data through tiny_obj_loader.h

This paper mainly refers to the function of PrintInfo(attrib, shapes, materials) of loader_example.cc.
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; // All the data is put here.
std::vector<tinyobj::shape_t> shapes; 
// A shape represents a part.
// The main storage is the indexed coordinate mesh_t class.
// Put it in 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);

// The next step is to take values from the above attributes.
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.\n");
    return false;
}

// ========================== Store the model data read into the data structure defined by the user========================

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. Getting all kinds of materials and textures
{
    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. Vertex data
{
    // For each shape traverses each part
    for (size_t i = 0; i < shapes.size(); i++) {
        // Name of this section
        printf("shape[%ld].name = %s\n", static_cast<long>(i),
            shapes[i].name.c_str());
        // Points of grid
        printf("Size of shape[%ld].mesh.indices: %lu\n", static_cast<long>(i),
            static_cast<unsigned long>(shapes[i].mesh.indices.size()));
        //printf("Size of shape[%ld].path.indices: %lu\n", 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\n", static_cast<long>(i),
            static_cast<unsigned long>(shapes[i].mesh.num_face_vertices.size()));

        Model* model = new Model(); // Model data for each part
        // Number of vertices = number of face s x3 
        model->mesh_num = shapes[i].mesh.num_face_vertices.size() * 3; 
        // Open up space
        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];

            // Get the indexed Subscripts
            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;
            }

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

std::cout << "# Loading Complete #"<< std::endl;
//PrintInfo(attrib, shapes, materials);
return true;

}

Topics: Big Data github