Return parsed material information in parseObj API..

Parse PBR extension in MTL
This commit is contained in:
Syoyo Fujita
2016-08-13 18:38:45 +09:00
parent 110b49a0c8
commit 2b50b31657
2 changed files with 125 additions and 14 deletions

View File

@@ -292,6 +292,22 @@ typedef struct {
std::string bump_texname; // map_bump, bump
std::string displacement_texname; // disp
std::string alpha_texname; // map_d
// PBR extension
// http://exocortex.com/blog/extending_wavefront_mtl_to_support_pbr
float roughness; // [0, 1] default 0
float metallic; // [0, 1] default 0
float sheen; // [0, 1] default 0
float clearcoat_thickness; // [0, 1] default 0
float clearcoat_roughness; // [0, 1] default 0
float anisotropy; // aniso. [0, 1] default 0
float anisotropy_rotation; // anisor. [0, 1] default 0
std::string roughness_texname; // map_Pr
std::string metallic_texname; // map_Pm
std::string sheen_texname; // map_Ps
std::string emissive_texname; // map_Ke
std::string normal_texname; // norm. For normal mapping.
std::map<std::string, std::string> unknown_parameter;
} material_t;
@@ -304,7 +320,8 @@ typedef struct {
struct index_t {
int vertex_index, texcoord_index, normal_index;
index_t() : vertex_index(-1), texcoord_index(-1), normal_index(-1) {}
explicit index_t(int idx) : vertex_index(idx), texcoord_index(idx), normal_index(idx) {}
explicit index_t(int idx)
: vertex_index(idx), texcoord_index(idx), normal_index(idx) {}
index_t(int vidx, int vtidx, int vnidx)
: vertex_index(vidx), texcoord_index(vtidx), normal_index(vnidx) {}
};
@@ -660,6 +677,11 @@ static void LoadMtl(std::map<std::string, int> *material_map,
std::string linebuf(&buf[0]);
// Trim trailing whitespace.
if (linebuf.size() > 0) {
linebuf = linebuf.substr(0, linebuf.find_last_not_of(" \t") + 1);
}
// Trim newline '\r\n' or '\n'
if (linebuf.size() > 0) {
if (linebuf[linebuf.size() - 1] == '\n')
@@ -790,6 +812,7 @@ static void LoadMtl(std::map<std::string, int> *material_map,
material.dissolve = parseFloat(&token);
continue;
}
if (token[0] == 'T' && token[1] == 'r' && IS_SPACE(token[2])) {
token += 2;
// Invert value of Tr(assume Tr is in range [0, 1])
@@ -797,6 +820,55 @@ static void LoadMtl(std::map<std::string, int> *material_map,
continue;
}
// PBR: roughness
if (token[0] == 'P' && token[1] == 'r' && IS_SPACE(token[2])) {
token += 2;
material.roughness = parseFloat(&token);
continue;
}
// PBR: metallic
if (token[0] == 'P' && token[1] == 'm' && IS_SPACE(token[2])) {
token += 2;
material.metallic = parseFloat(&token);
continue;
}
// PBR: sheen
if (token[0] == 'P' && token[1] == 's' && IS_SPACE(token[2])) {
token += 2;
material.sheen = parseFloat(&token);
continue;
}
// PBR: clearcoat thickness
if (token[0] == 'P' && token[1] == 'c' && IS_SPACE(token[2])) {
token += 2;
material.clearcoat_thickness = parseFloat(&token);
continue;
}
// PBR: clearcoat roughness
if ((0 == strncmp(token, "Pcr", 3)) && IS_SPACE(token[3])) {
token += 4;
material.clearcoat_roughness = parseFloat(&token);
continue;
}
// PBR: anisotropy
if ((0 == strncmp(token, "aniso", 5)) && IS_SPACE(token[5])) {
token += 6;
material.anisotropy = parseFloat(&token);
continue;
}
// PBR: anisotropy rotation
if ((0 == strncmp(token, "anisor", 6)) && IS_SPACE(token[6])) {
token += 7;
material.anisotropy_rotation = parseFloat(&token);
continue;
}
// ambient texture
if ((0 == strncmp(token, "map_Ka", 6)) && IS_SPACE(token[6])) {
token += 7;
@@ -853,6 +925,41 @@ static void LoadMtl(std::map<std::string, int> *material_map,
continue;
}
// PBR: roughness texture
if ((0 == strncmp(token, "map_Pr", 6)) && IS_SPACE(token[6])) {
token += 7;
material.roughness_texname = token;
continue;
}
// PBR: metallic texture
if ((0 == strncmp(token, "map_Pm", 6)) && IS_SPACE(token[6])) {
token += 7;
material.metallic_texname = token;
continue;
}
// PBR: sheen texture
if ((0 == strncmp(token, "map_Ps", 6)) && IS_SPACE(token[6])) {
token += 7;
material.sheen_texname = token;
continue;
}
// PBR: emissive texture
if ((0 == strncmp(token, "map_Ke", 6)) && IS_SPACE(token[6])) {
token += 7;
material.emissive_texname = token;
continue;
}
// PBR: normal map texture
if ((0 == strncmp(token, "norm", 4)) && IS_SPACE(token[4])) {
token += 5;
material.normal_texname = token;
continue;
}
// unknown parameter
const char *_space = strchr(token, ' ');
if (!_space) {
@@ -935,8 +1042,9 @@ class LoadOption {
/// Parse wavefront .obj(.obj string data is expanded to linear char array
/// `buf')
/// -1 to req_num_threads use the number of HW threads in the running system.
bool parseObj(attrib_t *attrib, std::vector<shape_t> *shapes, const char *buf,
size_t len, const LoadOption &option);
bool parseObj(attrib_t *attrib, std::vector<shape_t> *shapes,
std::vector<material_t> *materials, const char *buf, size_t len,
const LoadOption &option);
#ifdef TINYOBJ_LOADER_OPT_IMPLEMENTATION
@@ -1137,8 +1245,9 @@ static inline bool is_line_ending(const char *p, size_t i, size_t end_i) {
return false;
}
bool parseObj(attrib_t *attrib, std::vector<shape_t> *shapes, const char *buf,
size_t len, const LoadOption &option) {
bool parseObj(attrib_t *attrib, std::vector<shape_t> *shapes,
std::vector<material_t> *materials, const char *buf, size_t len,
const LoadOption &option) {
attrib->vertices.clear();
attrib->normals.clear();
attrib->texcoords.clear();
@@ -1313,7 +1422,6 @@ bool parseObj(attrib_t *attrib, std::vector<shape_t> *shapes, const char *buf,
}
std::map<std::string, int> material_map;
std::vector<material_t> materials;
// Load material(if exits)
if (mtllib_i_index >= 0 && mtllib_t_index >= 0 &&
@@ -1328,7 +1436,7 @@ bool parseObj(attrib_t *attrib, std::vector<shape_t> *shapes, const char *buf,
std::ifstream ifs(material_filename);
if (ifs.good()) {
LoadMtl(&material_map, &materials, &ifs);
LoadMtl(&material_map, materials, &ifs);
// std::cout << "maetrials = " << materials.size() << std::endl;
@@ -1361,10 +1469,10 @@ bool parseObj(attrib_t *attrib, std::vector<shape_t> *shapes, const char *buf,
num_indices += command_count[t].num_indices;
}
//std::cout << "# v " << num_v << std::endl;
//std::cout << "# vn " << num_vn << std::endl;
//std::cout << "# vt " << num_vt << std::endl;
//std::cout << "# f " << num_f << std::endl;
// std::cout << "# v " << num_v << std::endl;
// std::cout << "# vn " << num_vn << std::endl;
// std::cout << "# vt " << num_vt << std::endl;
// std::cout << "# f " << num_f << std::endl;
// 4. merge
// @todo { parallelize merge. }
@@ -1445,7 +1553,8 @@ bool parseObj(attrib_t *attrib, std::vector<shape_t> *shapes, const char *buf,
int vertex_index = fixIndex(vi.vertex_index, v_count);
int texcoord_index = fixIndex(vi.texcoord_index, t_count);
int normal_index = fixIndex(vi.normal_index, n_count);
attrib->indices[f_count + k] = index_t(vertex_index, texcoord_index, normal_index);
attrib->indices[f_count + k] =
index_t(vertex_index, texcoord_index, normal_index);
}
attrib->material_ids[face_count] = material_id;
attrib->face_num_verts[face_count] = commands[t][i].f.size();

View File

@@ -218,6 +218,7 @@ bool LoadObjAndConvert(float bmin[3], float bmax[3], const char* filename, int n
{
tinyobj_opt::attrib_t attrib;
std::vector<tinyobj_opt::shape_t> shapes;
std::vector<tinyobj_opt::material_t> materials;
size_t data_len = 0;
const char* data = get_file_data(&data_len, filename);
@@ -229,7 +230,7 @@ bool LoadObjAndConvert(float bmin[3], float bmax[3], const char* filename, int n
tinyobj_opt::LoadOption option;
option.req_num_threads = num_threads;
option.verbose = verbose;
bool ret = parseObj(&attrib, &shapes, data, data_len, option);
bool ret = parseObj(&attrib, &shapes, &materials, data, data_len, option);
bmin[0] = bmin[1] = bmin[2] = std::numeric_limits<float>::max();
bmax[0] = bmax[1] = bmax[2] = -std::numeric_limits<float>::max();
@@ -528,6 +529,7 @@ int main(int argc, char **argv)
tinyobj_opt::attrib_t attrib;
std::vector<tinyobj_opt::shape_t> shapes;
std::vector<tinyobj_opt::material_t> materials;
size_t data_len = 0;
const char* data = get_file_data(&data_len, argv[1]);
@@ -540,7 +542,7 @@ int main(int argc, char **argv)
option.req_num_threads = num_threads;
option.verbose = true;
bool ret = parseObj(&attrib, &shapes, data, data_len, option);
bool ret = parseObj(&attrib, &shapes, &materials, data, data_len, option);
return ret;
}