17 Commits

Author SHA1 Message Date
Syoyo Fujita
dcad3e6c50 Add per-face smoothing groupd ids to mesh_t.
Add unit test for smoothing groups.
2018-01-31 22:13:52 +09:00
Syoyo Fujita
2dfc37a475 Introduce face_t structure which stores per-face smoothing group and vertex indices. 2018-01-31 20:07:34 +09:00
Syoyo Fujita
9a6390cdee Add padding. 2018-01-31 14:24:37 +09:00
gopalss
78c7c9011a Fix for #29 Normal Generation by Smoothing Group Id - Commit 4 2018-01-30 10:55:10 -05:00
gopalss
1754669b07 Fix for #29 Normal Generation by Smoothing Group Id - Commit 3 2018-01-30 10:31:02 -05:00
gopalss
1f7b4a49c0 Fix for #29 Normal Generation by Smoothing Group Id - Commit 2 2018-01-30 09:51:16 -05:00
gopalss
15f47e2e35 Fix for #29 Normal Generation by Smoothing Group Id 2018-01-29 18:37:39 -05:00
Syoyo Fujita
12bf4165be Fix assertion when there is no normal/texcoord assigned to the face. Fixes #161.
Suppress clang warnings.
2018-01-29 13:41:33 +09:00
Syoyo Fujita
f206a56362 Merge pull request #160 from arosh/master
PR for open bounty test 2.
2018-01-17 01:56:07 +09:00
Sho Iizuka
13951d6459 Remove empty lines at EOF 2018-01-16 18:11:05 +09:00
Syoyo Fujita
5383e3400a Merge pull request #156 from raspofabs/master
ear clipping using pnpoly algorithm
2018-01-15 17:26:11 +09:00
Richard Fabian
ac3c36ffda increase the size of the epsilon to give better axis choice for triangulation 2018-01-14 18:53:20 +00:00
Richard Fabian
3b681805aa fixed the bug where the wrong axis was selected for doing the pnpoly check 2018-01-14 16:45:59 +00:00
Richard Fabian
ca49183639 added ear clipping triangulation 2018-01-14 14:21:46 +00:00
Syoyo Fujita
b29d34f2e1 Merge pull request #154 from ogrex/master
Bugfix for multiple texture
2017-12-21 01:23:03 +09:00
ogrex
cb085d1fb6 fix multiple texture wrong id problem 2017-12-20 22:17:19 +09:00
ogrex
b38e97b7ec trimming '\r' in material_file name 2017-12-20 22:13:58 +09:00
21 changed files with 1208 additions and 1361 deletions

View File

@@ -26,20 +26,11 @@ Old version is available `v0.9.x` branch https://github.com/syoyo/tinyobjloader/
## What's new ## What's new
### Version 2.x
* Refactor API
* Support triangulation for concave polygons(#151)
### Version 1.x
Avaiable in `v1.x.y` branch.
* 20 Aug, 2016 : Bump version v1.0.0. New data structure and API! * 20 Aug, 2016 : Bump version v1.0.0. New data structure and API!
### Older version ### Old version
Older version is avaiable in `v0.9.x` branch. Previous old version is avaiable in `v0.9.x` branch.
## Example ## Example
@@ -58,11 +49,7 @@ http://casual-effects.com/data/index.html
TinyObjLoader is successfully used in ... TinyObjLoader is successfully used in ...
### New version(v2.x) ### New version(v1.0.x)
* Your project here! (Letting us know via github issue is welcome!)
### Old version(v1.x)
* Double precision support through `TINYOBJLOADER_USE_DOUBLE` thanks to noma * Double precision support through `TINYOBJLOADER_USE_DOUBLE` thanks to noma
* Loading models in Vulkan Tutorial https://vulkan-tutorial.com/Loading_models * Loading models in Vulkan Tutorial https://vulkan-tutorial.com/Loading_models
@@ -73,7 +60,7 @@ TinyObjLoader is successfully used in ...
* VFPR - a Vulkan Forward Plus Renderer : https://github.com/WindyDarian/Vulkan-Forward-Plus-Renderer * VFPR - a Vulkan Forward Plus Renderer : https://github.com/WindyDarian/Vulkan-Forward-Plus-Renderer
* Your project here! (Letting us know via github issue is welcome!) * Your project here! (Letting us know via github issue is welcome!)
### Older version(v0.9.x) ### Old version(v0.9.x)
* bullet3 https://github.com/erwincoumans/bullet3 * bullet3 https://github.com/erwincoumans/bullet3
* pbrt-v2 https://github.com/mmp/pbrt-v2 * pbrt-v2 https://github.com/mmp/pbrt-v2
@@ -241,12 +228,12 @@ for (size_t s = 0; s < shapes.size(); s++) {
for (size_t v = 0; v < fv; v++) { for (size_t v = 0; v < fv; v++) {
// access to vertex // access to vertex
tinyobj::index_t idx = shapes[s].mesh.indices[index_offset + v]; tinyobj::index_t idx = shapes[s].mesh.indices[index_offset + v];
tinyobj::real_t vx = attrib.vertices[idx.vertex_index].x; tinyobj::real_t vx = attrib.vertices[3*idx.vertex_index+0];
tinyobj::real_t vy = attrib.vertices[idx.vertex_index].y; tinyobj::real_t vy = attrib.vertices[3*idx.vertex_index+1];
tinyobj::real_t vz = attrib.vertices[idx.vertex_index].z; tinyobj::real_t vz = attrib.vertices[3*idx.vertex_index+2];
tinyobj::real_t nx = attrib.normals[idx.normal_index].x; tinyobj::real_t nx = attrib.normals[3*idx.normal_index+0];
tinyobj::real_t ny = attrib.normals[idx.normal_index].y; tinyobj::real_t ny = attrib.normals[3*idx.normal_index+1];
tinyobj::real_t nz = attrib.normals[idx.normal_index].z; tinyobj::real_t nz = attrib.normals[3*idx.normal_index+2];
tinyobj::real_t tx = attrib.texcoords[2*idx.texcoord_index+0]; tinyobj::real_t tx = attrib.texcoords[2*idx.texcoord_index+0];
tinyobj::real_t ty = attrib.texcoords[2*idx.texcoord_index+1]; tinyobj::real_t ty = attrib.texcoords[2*idx.texcoord_index+1];
// Optional: vertex colors // Optional: vertex colors

View File

@@ -172,5 +172,3 @@ bool WriteObj(const std::string& filename, const std::vector<tinyobj::shape_t>&
return ret; return ret;
} }

View File

@@ -37,11 +37,11 @@ extern "C" {
#include <windows.h> #include <windows.h>
#ifdef max #ifdef max
#undef max #undef max
#endif #endif
#ifdef min #ifdef min
#undef min #undef min
#endif #endif
#include <mmsystem.h> #include <mmsystem.h>
@@ -143,15 +143,15 @@ float eye[3], lookat[3], up[3];
GLFWwindow* window; GLFWwindow* window;
static std::string GetBaseDir(const std::string &filepath) { static std::string GetBaseDir(const std::string& filepath) {
if (filepath.find_last_of("/\\") != std::string::npos) if (filepath.find_last_of("/\\") != std::string::npos)
return filepath.substr(0, filepath.find_last_of("/\\")); return filepath.substr(0, filepath.find_last_of("/\\"));
return ""; return "";
} }
static bool FileExists(const std::string &abs_filename) { static bool FileExists(const std::string& abs_filename) {
bool ret; bool ret;
FILE *fp = fopen(abs_filename.c_str(), "rb"); FILE* fp = fopen(abs_filename.c_str(), "rb");
if (fp) { if (fp) {
ret = true; ret = true;
fclose(fp); fclose(fp);
@@ -191,9 +191,90 @@ static void CalcNormal(float N[3], float v0[3], float v1[3], float v2[3]) {
N[0] /= len; N[0] /= len;
N[1] /= len; N[1] /= len;
N[2] /= len;
} }
} }
namespace // Local utility functions
{
void addBtoA(float a[3], float b[3])
{
for (size_t i = 0; i < 3; ++i)
a[i] += b[i];
}
void assignBtoA(float a[3], float b[3])
{
for (size_t i = 0; i < 3; ++i)
a[i] = b[i];
}
void normalizeVector(float N[3])
{
float len2 = N[0] * N[0] + N[1] * N[1] + N[2] * N[2];
if (len2 > 0.0f) {
float len = sqrtf(len2);
N[0] /= len;
N[1] /= len;
N[2] /= len;
}
}
void computeSmoothingNormals(tinyobj::attrib_t &attrib, tinyobj::shape_t &shape,
std::map<int, float[3]>& smoothVertexNormals)
{
smoothVertexNormals.clear();
std::map<int, float[3]>::iterator iter;
for (size_t f = 0; f < shape.mesh.indices.size() / 3; f++) {
// Get the three indexes of the face (all faces are triangular)
tinyobj::index_t idx0 = shape.mesh.indices[3 * f + 0];
tinyobj::index_t idx1 = shape.mesh.indices[3 * f + 1];
tinyobj::index_t idx2 = shape.mesh.indices[3 * f + 2];
// Get the three vertex indexes and coordinates
int vi[3]; // indexes
float v[3][3]; // coordinates
for (int k = 0; k < 3; k++) {
vi[0] = idx0.vertex_index;
vi[1] = idx1.vertex_index;
vi[2] = idx2.vertex_index;
assert(vi[0] >= 0);
assert(vi[1] >= 0);
assert(vi[2] >= 0);
v[0][k] = attrib.vertices[3 * vi[0] + k];
v[1][k] = attrib.vertices[3 * vi[1] + k];
v[2][k] = attrib.vertices[3 * vi[2] + k];
}
// Compute the normal of the face
float normal[3];
CalcNormal(normal, v[0], v[1], v[2]);
// Add the normal to the three vertexes
for (size_t i = 0; i < 3; ++i)
{
iter = smoothVertexNormals.find(vi[i]);
if (iter != smoothVertexNormals.end())
addBtoA(iter->second, normal);
else
assignBtoA(smoothVertexNormals[vi[i]], normal);
}
} // f
// Normalize the normals, that is, make them unit vectors
for (iter = smoothVertexNormals.begin(); iter != smoothVertexNormals.end(); iter++)
{
normalizeVector(iter->second);
}
} // computeSmoothingNormals
} // namespace
static bool LoadObjAndConvert(float bmin[3], float bmax[3], static bool LoadObjAndConvert(float bmin[3], float bmax[3],
std::vector<DrawObject>* drawObjects, std::vector<DrawObject>* drawObjects,
std::vector<tinyobj::material_t>& materials, std::vector<tinyobj::material_t>& materials,
@@ -217,8 +298,8 @@ static bool LoadObjAndConvert(float bmin[3], float bmax[3],
#endif #endif
std::string err; std::string err;
bool ret = bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &err, filename,
tinyobj::LoadObj(&attrib, &shapes, &materials, &err, filename, base_dir.c_str()); base_dir.c_str());
if (!err.empty()) { if (!err.empty()) {
std::cerr << err << std::endl; std::cerr << err << std::endl;
} }
@@ -242,7 +323,8 @@ static bool LoadObjAndConvert(float bmin[3], float bmax[3],
materials.push_back(tinyobj::material_t()); materials.push_back(tinyobj::material_t());
for (size_t i = 0; i < materials.size(); i++) { for (size_t i = 0; i < materials.size(); i++) {
printf("material[%d].diffuse_texname = %s\n", int(i), materials[i].diffuse_texname.c_str()); printf("material[%d].diffuse_texname = %s\n", int(i),
materials[i].diffuse_texname.c_str());
} }
// Load diffuse textures // Load diffuse textures
@@ -262,27 +344,32 @@ static bool LoadObjAndConvert(float bmin[3], float bmax[3],
// Append base dir. // Append base dir.
texture_filename = base_dir + mp->diffuse_texname; texture_filename = base_dir + mp->diffuse_texname;
if (!FileExists(texture_filename)) { if (!FileExists(texture_filename)) {
std::cerr << "Unable to find file: " << mp->diffuse_texname << std::endl; std::cerr << "Unable to find file: " << mp->diffuse_texname
<< std::endl;
exit(1); exit(1);
} }
} }
unsigned char* image = stbi_load(texture_filename.c_str(), &w, &h, &comp, STBI_default); unsigned char* image =
stbi_load(texture_filename.c_str(), &w, &h, &comp, STBI_default);
if (!image) { if (!image) {
std::cerr << "Unable to load texture: " << texture_filename << std::endl; std::cerr << "Unable to load texture: " << texture_filename
<< std::endl;
exit(1); exit(1);
} }
std::cout << "Loaded texture: " << texture_filename << ", w = " << w << ", h = " << h << ", comp = " << comp << std::endl; std::cout << "Loaded texture: " << texture_filename << ", w = " << w
<< ", h = " << h << ", comp = " << comp << std::endl;
glGenTextures(1, &texture_id); glGenTextures(1, &texture_id);
glBindTexture(GL_TEXTURE_2D, texture_id); glBindTexture(GL_TEXTURE_2D, texture_id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
if (comp == 3) { if (comp == 3) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, image); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB,
} GL_UNSIGNED_BYTE, image);
else if (comp == 4) { } else if (comp == 4) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, image); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
GL_UNSIGNED_BYTE, image);
} else { } else {
assert(0); // TODO assert(0); // TODO
} }
@@ -301,6 +388,12 @@ static bool LoadObjAndConvert(float bmin[3], float bmax[3],
for (size_t s = 0; s < shapes.size(); s++) { for (size_t s = 0; s < shapes.size(); s++) {
DrawObject o; DrawObject o;
std::vector<float> buffer; // pos(3float), normal(3float), color(3float) std::vector<float> buffer; // pos(3float), normal(3float), color(3float)
// Check for smoothing group and compute smoothing normals
std::map<int, float[3]> smoothVertexNormals;
if (shapes[s].smoothingGroupId > 0)
computeSmoothingNormals(attrib, shapes[s], smoothVertexNormals);
for (size_t f = 0; f < shapes[s].mesh.indices.size() / 3; f++) { 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 idx0 = shapes[s].mesh.indices[3 * f + 0];
tinyobj::index_t idx1 = shapes[s].mesh.indices[3 * f + 1]; tinyobj::index_t idx1 = shapes[s].mesh.indices[3 * f + 1];
@@ -308,12 +401,16 @@ static bool LoadObjAndConvert(float bmin[3], float bmax[3],
int current_material_id = shapes[s].mesh.material_ids[f]; int current_material_id = shapes[s].mesh.material_ids[f];
if ((current_material_id < 0) || (current_material_id >= static_cast<int>(materials.size()))) { if ((current_material_id < 0) ||
(current_material_id >= static_cast<int>(materials.size()))) {
// Invaid material ID. Use default material. // Invaid material ID. Use default material.
current_material_id = materials.size() - 1; // Default material is added to the last item in `materials`. current_material_id =
materials.size() -
1; // Default material is added to the last item in `materials`.
} }
//if (current_material_id >= materials.size()) { // if (current_material_id >= materials.size()) {
// std::cerr << "Invalid material index: " << current_material_id << std::endl; // std::cerr << "Invalid material index: " << current_material_id <<
// std::endl;
//} //}
// //
float diffuse[3]; float diffuse[3];
@@ -322,9 +419,22 @@ static bool LoadObjAndConvert(float bmin[3], float bmax[3],
} }
float tc[3][2]; float tc[3][2];
if (attrib.texcoords.size() > 0) { if (attrib.texcoords.size() > 0) {
assert(attrib.texcoords.size() > 2 * idx0.texcoord_index + 1); if ((idx0.texcoord_index < 0) || (idx1.texcoord_index < 0) ||
assert(attrib.texcoords.size() > 2 * idx1.texcoord_index + 1); (idx2.texcoord_index < 0)) {
assert(attrib.texcoords.size() > 2 * idx2.texcoord_index + 1); // face does not contain valid uv index.
tc[0][0] = 0.0f;
tc[0][1] = 0.0f;
tc[1][0] = 0.0f;
tc[1][1] = 0.0f;
tc[2][0] = 0.0f;
tc[2][1] = 0.0f;
} else {
assert(attrib.texcoords.size() >
size_t(2 * idx0.texcoord_index + 1));
assert(attrib.texcoords.size() >
size_t(2 * idx1.texcoord_index + 1));
assert(attrib.texcoords.size() >
size_t(2 * idx2.texcoord_index + 1));
// Flip Y coord. // Flip Y coord.
tc[0][0] = attrib.texcoords[2 * idx0.texcoord_index]; tc[0][0] = attrib.texcoords[2 * idx0.texcoord_index];
@@ -333,6 +443,7 @@ static bool LoadObjAndConvert(float bmin[3], float bmax[3],
tc[1][1] = 1.0f - attrib.texcoords[2 * idx1.texcoord_index + 1]; tc[1][1] = 1.0f - attrib.texcoords[2 * idx1.texcoord_index + 1];
tc[2][0] = attrib.texcoords[2 * idx2.texcoord_index]; tc[2][0] = attrib.texcoords[2 * idx2.texcoord_index];
tc[2][1] = 1.0f - attrib.texcoords[2 * idx2.texcoord_index + 1]; tc[2][1] = 1.0f - attrib.texcoords[2 * idx2.texcoord_index + 1];
}
} else { } else {
tc[0][0] = 0.0f; tc[0][0] = 0.0f;
tc[0][1] = 0.0f; tc[0][1] = 0.0f;
@@ -363,19 +474,45 @@ static bool LoadObjAndConvert(float bmin[3], float bmax[3],
} }
float n[3][3]; float n[3][3];
{
bool invalid_normal_index = false;
if (attrib.normals.size() > 0) { if (attrib.normals.size() > 0) {
int f0 = idx0.normal_index; int nf0 = idx0.normal_index;
int f1 = idx1.normal_index; int nf1 = idx1.normal_index;
int f2 = idx2.normal_index; int nf2 = idx2.normal_index;
assert(f0 >= 0);
assert(f1 >= 0); if ((nf0 < 0) || (nf1 < 0) || (nf2 < 0)) {
assert(f2 >= 0); // normal index is missing from this face.
invalid_normal_index = true;
} else {
for (int k = 0; k < 3; k++) { for (int k = 0; k < 3; k++) {
n[0][k] = attrib.normals[3 * f0 + k]; assert(size_t(3 * nf0 + k) < attrib.normals.size());
n[1][k] = attrib.normals[3 * f1 + k]; assert(size_t(3 * nf1 + k) < attrib.normals.size());
n[2][k] = attrib.normals[3 * f2 + k]; assert(size_t(3 * nf2 + k) < attrib.normals.size());
n[0][k] = attrib.normals[3 * nf0 + k];
n[1][k] = attrib.normals[3 * nf1 + k];
n[2][k] = attrib.normals[3 * nf2 + k];
}
} }
} else { } else {
invalid_normal_index = true;
}
if (invalid_normal_index && !smoothVertexNormals.empty()) {
// Use smoothing normals
int f0 = idx0.vertex_index;
int f1 = idx1.vertex_index;
int f2 = idx2.vertex_index;
if (f0 >= 0 && f1 >= 0 && f2 >= 0) {
assignBtoA(n[0], smoothVertexNormals[f0]);
assignBtoA(n[1], smoothVertexNormals[f1]);
assignBtoA(n[2], smoothVertexNormals[f2]);
invalid_normal_index = false;
}
}
if (invalid_normal_index) {
// compute geometric normal // compute geometric normal
CalcNormal(n[0], v[0], v[1], v[2]); CalcNormal(n[0], v[0], v[1], v[2]);
n[1][0] = n[0][0]; n[1][0] = n[0][0];
@@ -385,6 +522,7 @@ static bool LoadObjAndConvert(float bmin[3], float bmax[3],
n[2][1] = n[0][1]; n[2][1] = n[0][1];
n[2][2] = n[0][2]; n[2][2] = n[0][2];
} }
}
for (int k = 0; k < 3; k++) { for (int k = 0; k < 3; k++) {
buffer.push_back(v[k][0]); buffer.push_back(v[k][0]);
@@ -396,11 +534,9 @@ static bool LoadObjAndConvert(float bmin[3], float bmax[3],
// Combine normal and diffuse to get color. // Combine normal and diffuse to get color.
float normal_factor = 0.2; float normal_factor = 0.2;
float diffuse_factor = 1 - normal_factor; float diffuse_factor = 1 - normal_factor;
float c[3] = { float c[3] = {n[k][0] * normal_factor + diffuse[0] * diffuse_factor,
n[k][0] * normal_factor + diffuse[0] * diffuse_factor,
n[k][1] * normal_factor + diffuse[1] * diffuse_factor, n[k][1] * normal_factor + diffuse[1] * diffuse_factor,
n[k][2] * normal_factor + diffuse[2] * diffuse_factor n[k][2] * normal_factor + diffuse[2] * diffuse_factor};
};
float len2 = c[0] * c[0] + c[1] * c[1] + c[2] * c[2]; float len2 = c[0] * c[0] + c[1] * c[1] + c[2] * c[2];
if (len2 > 0.0f) { if (len2 > 0.0f) {
float len = sqrtf(len2); float len = sqrtf(len2);
@@ -422,8 +558,10 @@ static bool LoadObjAndConvert(float bmin[3], float bmax[3],
o.numTriangles = 0; o.numTriangles = 0;
// OpenGL viewer does not support texturing with per-face material. // 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) { if (shapes[s].mesh.material_ids.size() > 0 &&
o.material_id = shapes[s].mesh.material_ids[0]; // use the material ID of the first face. shapes[s].mesh.material_ids.size() > s) {
o.material_id = shapes[s].mesh.material_ids[0]; // use the material ID
// of the first face.
} else { } else {
o.material_id = materials.size() - 1; // = ID for default material. o.material_id = materials.size() - 1; // = ID for default material.
} }
@@ -432,9 +570,10 @@ static bool LoadObjAndConvert(float bmin[3], float bmax[3],
if (buffer.size() > 0) { if (buffer.size() > 0) {
glGenBuffers(1, &o.vb_id); glGenBuffers(1, &o.vb_id);
glBindBuffer(GL_ARRAY_BUFFER, o.vb_id); glBindBuffer(GL_ARRAY_BUFFER, o.vb_id);
glBufferData(GL_ARRAY_BUFFER, buffer.size() * sizeof(float), &buffer.at(0), glBufferData(GL_ARRAY_BUFFER, buffer.size() * sizeof(float),
GL_STATIC_DRAW); &buffer.at(0), GL_STATIC_DRAW);
o.numTriangles = buffer.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<int>(s), printf("shape[%d] # of triangles = %d\n", static_cast<int>(s),
o.numTriangles); o.numTriangles);
@@ -549,7 +688,9 @@ static void motionFunc(GLFWwindow* window, double mouse_x, double mouse_y) {
prevMouseY = mouse_y; prevMouseY = mouse_y;
} }
static void Draw(const std::vector<DrawObject>& drawObjects, std::vector<tinyobj::material_t>& materials, std::map<std::string, GLuint>& textures) { static void Draw(const std::vector<DrawObject>& drawObjects,
std::vector<tinyobj::material_t>& materials,
std::map<std::string, GLuint>& textures) {
glPolygonMode(GL_FRONT, GL_FILL); glPolygonMode(GL_FRONT, GL_FILL);
glPolygonMode(GL_BACK, GL_FILL); glPolygonMode(GL_BACK, GL_FILL);
@@ -668,7 +809,8 @@ int main(int argc, char** argv) {
float bmin[3], bmax[3]; float bmin[3], bmax[3];
std::vector<tinyobj::material_t> materials; std::vector<tinyobj::material_t> materials;
std::map<std::string, GLuint> textures; std::map<std::string, GLuint> textures;
if (false == LoadObjAndConvert(bmin, bmax, &gDrawObjects, materials, textures, argv[1])) { if (false == LoadObjAndConvert(bmin, bmax, &gDrawObjects, materials, textures,
argv[1])) {
return -1; return -1;
} }

View File

@@ -1440,7 +1440,9 @@ bool parseObj(attrib_t *attrib, std::vector<shape_t> *shapes,
// std::cout << "mtllib :" << material_filename << std::endl; // std::cout << "mtllib :" << material_filename << std::endl;
auto t1 = std::chrono::high_resolution_clock::now(); auto t1 = std::chrono::high_resolution_clock::now();
if (material_filename.back() == '\r') {
material_filename.pop_back();
}
std::ifstream ifs(material_filename); std::ifstream ifs(material_filename);
if (ifs.good()) { if (ifs.good()) {
LoadMtl(&material_map, materials, &ifs); LoadMtl(&material_map, materials, &ifs);
@@ -1516,13 +1518,13 @@ bool parseObj(attrib_t *attrib, std::vector<shape_t> *shapes,
StackVector<std::thread, 16> workers; StackVector<std::thread, 16> workers;
for (size_t t = 0; t < num_threads; t++) { for (size_t t = 0; t < num_threads; t++) {
int material_id = -1; // -1 = default unknown material.
workers->push_back(std::thread([&, t]() { workers->push_back(std::thread([&, t]() {
size_t v_count = v_offsets[t]; size_t v_count = v_offsets[t];
size_t n_count = n_offsets[t]; size_t n_count = n_offsets[t];
size_t t_count = t_offsets[t]; size_t t_count = t_offsets[t];
size_t f_count = f_offsets[t]; size_t f_count = f_offsets[t];
size_t face_count = face_offsets[t]; size_t face_count = face_offsets[t];
int material_id = -1; // -1 = default unknown material.
for (size_t i = 0; i < commands[t].size(); i++) { for (size_t i = 0; i < commands[t].size(); i++) {
if (commands[t][i].type == COMMAND_EMPTY) { if (commands[t][i].type == COMMAND_EMPTY) {
@@ -1579,7 +1581,19 @@ bool parseObj(attrib_t *attrib, std::vector<shape_t> *shapes,
for (size_t t = 0; t < workers->size(); t++) { for (size_t t = 0; t < workers->size(); t++) {
workers[t].join(); workers[t].join();
} }
if(material_map.size()>1&& num_threads>1) {
for (size_t t = 0; t < num_threads; t++) {
size_t face_count = face_offsets[t];
if (-1 == attrib->material_ids[face_count]) {
int prev_material_id = attrib->material_ids[face_count - 1];
size_t max_face_offset = (t == num_threads - 1) ? attrib->material_ids.size() : face_offsets[t + 1];
for (int i = face_count; i<max_face_offset; ++i) {
if (attrib->material_ids[i] != -1) break;
attrib->material_ids[i] = prev_material_id;
}
}
}
}
auto t_end = std::chrono::high_resolution_clock::now(); auto t_end = std::chrono::high_resolution_clock::now();
ms_merge = t_end - t_start; ms_merge = t_end - t_start;
} }

View File

@@ -30,6 +30,7 @@ extern "C" {
#endif #endif
#ifdef __clang__ #ifdef __clang__
#pragma clang diagnostic push
#if __has_warning("-Wzero-as-null-pointer-constant") #if __has_warning("-Wzero-as-null-pointer-constant")
#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" #pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
#endif #endif
@@ -112,24 +113,24 @@ static void PrintInfo(const tinyobj::attrib_t& attrib,
std::cout << "# of shapes : " << shapes.size() << std::endl; std::cout << "# of shapes : " << shapes.size() << std::endl;
std::cout << "# of materials : " << materials.size() << std::endl; std::cout << "# of materials : " << materials.size() << std::endl;
for (size_t v = 0; v < attrib.vertices.size(); v++) { for (size_t v = 0; v < attrib.vertices.size() / 3; v++) {
printf(" v[%ld] = (%f, %f, %f)\n", static_cast<long>(v), printf(" v[%ld] = (%f, %f, %f)\n", static_cast<long>(v),
static_cast<const double>(attrib.vertices[v].x), static_cast<const double>(attrib.vertices[3 * v + 0]),
static_cast<const double>(attrib.vertices[v].y), static_cast<const double>(attrib.vertices[3 * v + 1]),
static_cast<const double>(attrib.vertices[v].z)); static_cast<const double>(attrib.vertices[3 * v + 2]));
} }
for (size_t v = 0; v < attrib.normals.size(); v++) { for (size_t v = 0; v < attrib.normals.size() / 3; v++) {
printf(" n[%ld] = (%f, %f, %f)\n", static_cast<long>(v), printf(" n[%ld] = (%f, %f, %f)\n", static_cast<long>(v),
static_cast<const double>(attrib.normals[v].x), static_cast<const double>(attrib.normals[3 * v + 0]),
static_cast<const double>(attrib.normals[v].y), static_cast<const double>(attrib.normals[3 * v + 1]),
static_cast<const double>(attrib.normals[v].z)); static_cast<const double>(attrib.normals[3 * v + 2]));
} }
for (size_t v = 0; v < attrib.texcoords.size(); v++) { for (size_t v = 0; v < attrib.texcoords.size() / 2; v++) {
printf(" uv[%ld] = (%f, %f)\n", static_cast<long>(v), printf(" uv[%ld] = (%f, %f)\n", static_cast<long>(v),
static_cast<const double>(attrib.texcoords[v].x), static_cast<const double>(attrib.texcoords[2 * v + 0]),
static_cast<const double>(attrib.texcoords[v].y)); static_cast<const double>(attrib.texcoords[2 * v + 1]));
} }
// For each shape // For each shape
@@ -367,7 +368,7 @@ static bool TestStreamLoadObj() {
virtual ~MaterialStringStreamReader() {} virtual ~MaterialStringStreamReader() {}
virtual bool operator()(const std::string& matId, virtual bool operator()(const std::string& matId,
std::vector<material_t>* materials, std::vector<material_t>* materials,
std::map<unsigned int, int>* matMap, std::map<std::string, int>* matMap,
std::string* err) { std::string* err) {
(void)matId; (void)matId;
std::string warning; std::string warning;

View File

@@ -0,0 +1,37 @@
o cube
mtllib cube.mtl
v -0.500000 -0.500000 0.500000
v 0.500000 -0.500000 0.500000
v -0.500000 0.500000 0.500000
v 0.500000 0.500000 0.500000
v -0.500000 0.500000 -0.500000
v 0.500000 0.500000 -0.500000
v -0.500000 -0.500000 -0.500000
v 0.500000 -0.500000 -0.500000
vt 0.000000 0.000000
vt 1.000000 0.000000
vt 0.000000 1.000000
vt 1.000000 1.000000
g cube
usemtl cube
s 1
f 1/1 2/2 3/3
f 3/3 2/2 4/4
s 2
f 3/1 4/2 5/3
f 5/3 4/2 6/4
s 3
f 5/4 6/3 7/2
f 7/2 6/3 8/1
s 4
f 7/1 8/2 1/3
f 1/3 8/2 2/4
s 5
f 2/1 8/2 4/3
f 4/3 8/2 6/4
s 6
f 7/1 1/2 5/3
f 5 1 3

View File

@@ -0,0 +1,23 @@
newmtl test1
Ns 10.0000
Ni 1.5000
d 1.0000
Tr 0.0000
Tf 1.0000 1.0000 1.0000
illum 2
Ka 0.0000 0.0000 0.0000
Kd 0.5 0.2 0.2
Ks 0.0000 0.0000 0.0000
Ke 0.0000 0.0000 0.0000
newmtl test2
Ns 10.0000
Ni 1.5000
d 1.0000
Tr 0.0000
Tf 1.0000 1.0000 1.0000
illum 2
Ka 0.0000 0.0000 0.0000
Kd 0.2 0.5 0.2
Ks 0.0000 0.0000 0.0000
Ke 0.0000 0.0000 0.0000

View File

@@ -0,0 +1,51 @@
# cube.obj
#
mtllib issue-162-smoothing-group.mtl
v -0.500000 -0.500000 0.500000
v 0.500000 -0.500000 0.500000
v -0.500000 0.500000 0.500000
v 0.500000 0.500000 0.500000
v -0.500000 0.500000 -0.500000
v 0.500000 0.500000 -0.500000
v -0.500000 -0.500000 -0.500000
v 0.500000 -0.500000 -0.500000
vt 0.000000 0.000000
vt 1.000000 0.000000
vt 0.000000 1.000000
vt 1.000000 1.000000
vn 0.000000 0.000000 1.000000
vn 0.000000 1.000000 0.000000
vn 0.000000 0.000000 -1.000000
vn 0.000000 -1.000000 0.000000
vn 1.000000 0.000000 0.000000
vn -1.000000 0.000000 0.000000
usemtl test1
g test1
s 1
f 1/1/1 2/2/1 3/3/1
f 3/3/1 2/2/1 4/4/1
usemtl test2
g test2
s off
f 3/1/2 4/2/2 5/3/2
f 5/3/2 4/2/2 6/4/2
s 3
f 5/4/3 6/3/3 7/2/3
f 7/2/3 6/3/3 8/1/3
s 4
f 7/1/4 8/2/4 1/3/4
f 1/3/4 8/2/4 2/4/4
s 0
f 2/1/5 8/2/5 4/3/5
f 4/3/5 8/2/5 6/4/5
s 6
f 7/1/6 1/2/6 5/3/6
f 5/3/6 1/2/6 3/4/6

View File

@@ -22,22 +22,22 @@ static void PrintInfo(const tinyobj::attrib_t &attrib, const std::vector<tinyobj
for (size_t v = 0; v < attrib.vertices.size() / 3; v++) { for (size_t v = 0; v < attrib.vertices.size() / 3; v++) {
printf(" v[%ld] = (%f, %f, %f)\n", v, printf(" v[%ld] = (%f, %f, %f)\n", v,
static_cast<const double>(attrib.vertices[v].x), static_cast<const double>(attrib.vertices[3*v+0]),
static_cast<const double>(attrib.vertices[v].y), static_cast<const double>(attrib.vertices[3*v+1]),
static_cast<const double>(attrib.vertices[v].z)); static_cast<const double>(attrib.vertices[3*v+2]));
} }
for (size_t v = 0; v < attrib.normals.size() / 3; v++) { for (size_t v = 0; v < attrib.normals.size() / 3; v++) {
printf(" n[%ld] = (%f, %f, %f)\n", v, printf(" n[%ld] = (%f, %f, %f)\n", v,
static_cast<const double>(attrib.normals[v].x), static_cast<const double>(attrib.normals[3*v+0]),
static_cast<const double>(attrib.normals[v].y), static_cast<const double>(attrib.normals[3*v+1]),
static_cast<const double>(attrib.normals[v].z)); static_cast<const double>(attrib.normals[3*v+2]));
} }
for (size_t v = 0; v < attrib.texcoords.size() / 2; v++) { for (size_t v = 0; v < attrib.texcoords.size() / 2; v++) {
printf(" uv[%ld] = (%f, %f)\n", v, printf(" uv[%ld] = (%f, %f)\n", v,
static_cast<const double>(attrib.texcoords[v].x), static_cast<const double>(attrib.texcoords[2*v+0]),
static_cast<const double>(attrib.texcoords[v].y)); static_cast<const double>(attrib.texcoords[2*v+1]));
} }
for (size_t i = 0; i < shapes.size(); i++) { for (size_t i = 0; i < shapes.size(); i++) {
@@ -303,8 +303,7 @@ std::string matStream(
virtual bool operator() ( virtual bool operator() (
const std::string& matId, const std::string& matId,
std::vector<material_t>* materials, std::vector<material_t>* materials,
//std::map<std::string, int>* matMap, std::map<std::string, int>* matMap,
std::map<uint32_t, int>* matMap,
std::string* err) std::string* err)
{ {
(void)matId; (void)matId;
@@ -718,6 +717,40 @@ TEST_CASE("texture-name-whitespace", "[Issue145]") {
} }
TEST_CASE("smoothing-group", "[Issue162]") {
tinyobj::attrib_t attrib;
std::vector<tinyobj::shape_t> shapes;
std::vector<tinyobj::material_t> materials;
std::string err;
bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &err, "../models/issue-162-smoothing-group.obj", gMtlBasePath);
if (!err.empty()) {
std::cerr << "[Issue162] " << err << std::endl;
}
REQUIRE(true == ret);
REQUIRE(2 == shapes.size());
REQUIRE(2 == shapes[0].mesh.smoothing_group_ids.size());
REQUIRE(1 == shapes[0].mesh.smoothing_group_ids[0]);
REQUIRE(1 == shapes[0].mesh.smoothing_group_ids[1]);
REQUIRE(10 == shapes[1].mesh.smoothing_group_ids.size());
REQUIRE(0 == shapes[1].mesh.smoothing_group_ids[0]);
REQUIRE(0 == shapes[1].mesh.smoothing_group_ids[1]);
REQUIRE(3 == shapes[1].mesh.smoothing_group_ids[2]);
REQUIRE(3 == shapes[1].mesh.smoothing_group_ids[3]);
REQUIRE(4 == shapes[1].mesh.smoothing_group_ids[4]);
REQUIRE(4 == shapes[1].mesh.smoothing_group_ids[5]);
REQUIRE(0 == shapes[1].mesh.smoothing_group_ids[6]);
REQUIRE(0 == shapes[1].mesh.smoothing_group_ids[7]);
REQUIRE(6 == shapes[1].mesh.smoothing_group_ids[8]);
REQUIRE(6 == shapes[1].mesh.smoothing_group_ids[9]);
}
#if 0 #if 0
int int
main( main(

File diff suppressed because it is too large Load Diff