diff --git a/README.md b/README.md index 582e6db..2737f08 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ Old version is available `v0.9.x` branch https://github.com/syoyo/tinyobjloader/ ## What's new -* 20 Aug, 2016 : Bump version v1.0.0. New data strcutre and API! +* 20 Aug, 2016 : Bump version v1.0.0. New data structure and API! ### Old version @@ -37,7 +37,7 @@ Previous old version is avaiable in `v0.9.x` branch. ![Rungholt](images/rungholt.jpg) tinyobjloader can successfully load 6M triangles Rungholt scene. -http://graphics.cs.williams.edu/data/meshes.xml +http://casual-effects.com/data/index.html ![](images/sanmugel.png) diff --git a/examples/viewer/README.md b/examples/viewer/README.md index 79e544e..9cb032c 100644 --- a/examples/viewer/README.md +++ b/examples/viewer/README.md @@ -6,7 +6,6 @@ * glfw3 * glew - ## Build on MaCOSX Install glfw3 and glew using brew. @@ -35,3 +34,9 @@ Put glfw3 and glew library somewhere and replace include and lib path in `premak Then, > premake5.exe vs2013 + +## TODO + +* [ ] Support per-face material. +* [ ] Use shader-based GL rendering. +* [ ] PBR shader support. diff --git a/examples/viewer/viewer.cc b/examples/viewer/viewer.cc index c660de9..4747232 100644 --- a/examples/viewer/viewer.cc +++ b/examples/viewer/viewer.cc @@ -123,7 +123,7 @@ class timerutil { }; typedef struct { - GLuint vb; // vertex buffer + GLuint vb_id; // vertex buffer id int numTriangles; size_t material_id; } DrawObject; @@ -207,6 +207,9 @@ static bool LoadObjAndConvert(float bmin[3], float bmax[3], tm.start(); std::string base_dir = GetBaseDir(filename); + if (base_dir.empty()) { + base_dir = "."; + } #ifdef _WIN32 base_dir += "\\"; #else @@ -238,6 +241,10 @@ static bool LoadObjAndConvert(float bmin[3], float bmax[3], // Append `default` material materials.push_back(tinyobj::material_t()); + for (size_t i = 0; i < materials.size(); i++) { + printf("material[%d].diffuse_texname = %s\n", int(i), materials[i].diffuse_texname.c_str()); + } + // Load diffuse textures { for (size_t m = 0; m < materials.size(); m++) { @@ -265,15 +272,19 @@ static bool LoadObjAndConvert(float bmin[3], float bmax[3], std::cerr << "Unable to load texture: " << texture_filename << std::endl; exit(1); } + std::cout << "Loaded texture: " << texture_filename << ", w = " << w << ", h = " << h << ", comp = " << comp << std::endl; + glGenTextures(1, &texture_id); glBindTexture(GL_TEXTURE_2D, texture_id); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); if (comp == 3) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, image); } else if (comp == 4) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, image); + } else { + assert(0); // TODO } glBindTexture(GL_TEXTURE_2D, 0); stbi_image_free(image); @@ -289,7 +300,7 @@ static bool LoadObjAndConvert(float bmin[3], float bmax[3], { for (size_t s = 0; s < shapes.size(); s++) { DrawObject o; - std::vector vb; // pos(3float), normal(3float), color(3float) + std::vector buffer; // pos(3float), normal(3float), color(3float) for (size_t f = 0; f < shapes[s].mesh.indices.size() / 3; f++) { tinyobj::index_t idx0 = shapes[s].mesh.indices[3 * f + 0]; tinyobj::index_t idx1 = shapes[s].mesh.indices[3 * f + 1]; @@ -314,6 +325,8 @@ static bool LoadObjAndConvert(float bmin[3], float bmax[3], assert(attrib.texcoords.size() > 2 * idx0.texcoord_index + 1); assert(attrib.texcoords.size() > 2 * idx1.texcoord_index + 1); assert(attrib.texcoords.size() > 2 * idx2.texcoord_index + 1); + + // Flip Y coord. tc[0][0] = attrib.texcoords[2 * idx0.texcoord_index]; tc[0][1] = 1.0f - attrib.texcoords[2 * idx0.texcoord_index + 1]; tc[1][0] = attrib.texcoords[2 * idx1.texcoord_index]; @@ -374,12 +387,12 @@ static bool LoadObjAndConvert(float bmin[3], float bmax[3], } for (int k = 0; k < 3; k++) { - vb.push_back(v[k][0]); - vb.push_back(v[k][1]); - vb.push_back(v[k][2]); - vb.push_back(n[k][0]); - vb.push_back(n[k][1]); - vb.push_back(n[k][2]); + buffer.push_back(v[k][0]); + buffer.push_back(v[k][1]); + buffer.push_back(v[k][2]); + buffer.push_back(n[k][0]); + buffer.push_back(n[k][1]); + buffer.push_back(n[k][2]); // Combine normal and diffuse to get color. float normal_factor = 0.2; float diffuse_factor = 1 - normal_factor; @@ -396,32 +409,32 @@ static bool LoadObjAndConvert(float bmin[3], float bmax[3], c[1] /= len; c[2] /= len; } - vb.push_back(c[0] * 0.5 + 0.5); - vb.push_back(c[1] * 0.5 + 0.5); - vb.push_back(c[2] * 0.5 + 0.5); + buffer.push_back(c[0] * 0.5 + 0.5); + buffer.push_back(c[1] * 0.5 + 0.5); + buffer.push_back(c[2] * 0.5 + 0.5); - vb.push_back(tc[k][0]); - vb.push_back(tc[k][1]); + buffer.push_back(tc[k][0]); + buffer.push_back(tc[k][1]); } } - o.vb = 0; + o.vb_id = 0; o.numTriangles = 0; // OpenGL viewer does not support texturing with per-face material. if (shapes[s].mesh.material_ids.size() > 0 && shapes[s].mesh.material_ids.size() > s) { - // Base case - o.material_id = shapes[s].mesh.material_ids[s]; + o.material_id = shapes[s].mesh.material_ids[0]; // use the material ID of the first face. } else { o.material_id = materials.size() - 1; // = ID for default material. } + printf("shape[%d] material_id %d\n", int(s), int(o.material_id)); - if (vb.size() > 0) { - glGenBuffers(1, &o.vb); - glBindBuffer(GL_ARRAY_BUFFER, o.vb); - glBufferData(GL_ARRAY_BUFFER, vb.size() * sizeof(float), &vb.at(0), + if (buffer.size() > 0) { + glGenBuffers(1, &o.vb_id); + glBindBuffer(GL_ARRAY_BUFFER, o.vb_id); + glBufferData(GL_ARRAY_BUFFER, buffer.size() * sizeof(float), &buffer.at(0), GL_STATIC_DRAW); - o.numTriangles = vb.size() / (3 + 3 + 3 + 2) / 3; // 3:vtx, 3:normal, 3:col, 2:texcoord + o.numTriangles = buffer.size() / (3 + 3 + 3 + 2) / 3; // 3:vtx, 3:normal, 3:col, 2:texcoord printf("shape[%d] # of triangles = %d\n", static_cast(s), o.numTriangles); @@ -545,16 +558,17 @@ static void Draw(const std::vector& drawObjects, std::vector& drawObjects, std::vector shapes; + std::vector materials; + + std::string err; + bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &err, "../models/map-bump.obj", gMtlBasePath); + + if (!err.empty()) { + std::cerr << err << std::endl; + } + + PrintInfo(attrib, shapes, materials); + + REQUIRE(true == ret); + REQUIRE(2 == materials.size()); + + REQUIRE(materials[0].bump_texname.compare("bump.jpg") == 0); +} + #if 0 int main( diff --git a/tiny_obj_loader.h b/tiny_obj_loader.h index 3273e9d..34cd85e 100644 --- a/tiny_obj_loader.h +++ b/tiny_obj_loader.h @@ -153,7 +153,7 @@ typedef struct { std::string diffuse_texname; // map_Kd std::string specular_texname; // map_Ks std::string specular_highlight_texname; // map_Ns - std::string bump_texname; // map_bump, bump + std::string bump_texname; // map_bump, map_Bump, bump std::string displacement_texname; // disp std::string alpha_texname; // map_d std::string reflection_texname; // refl @@ -1240,6 +1240,15 @@ void LoadMtl(std::map *material_map, continue; } + // bump texture + if ((0 == strncmp(token, "map_Bump", 8)) && IS_SPACE(token[8])) { + token += 9; + ParseTextureNameAndOption(&(material.bump_texname), + &(material.bump_texopt), token, + /* is_bump */ true); + continue; + } + // bump texture if ((0 == strncmp(token, "bump", 4)) && IS_SPACE(token[4])) { token += 5;