From e528741a8b163ebd7f110e25ef2969ce7da674c7 Mon Sep 17 00:00:00 2001 From: Vazquinhos Date: Fri, 13 May 2016 12:25:48 +0200 Subject: [PATCH 1/4] Flat normals calculation of objects that their normals are empty --- tiny_obj_loader.h | 123 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 111 insertions(+), 12 deletions(-) diff --git a/tiny_obj_loader.h b/tiny_obj_loader.h index 8bdd0a3..5127a2e 100644 --- a/tiny_obj_loader.h +++ b/tiny_obj_loader.h @@ -97,6 +97,69 @@ typedef struct { mesh_t mesh; } shape_t; +typedef enum +{ + triangulation = 1, // used whether triangulate polygon face in .obj + calculate_normals = 2, // used whether calculate the normals if the .obj normals are empty + // Some nice stuff here +} load_flags_t; + +class float3 +{ +public: + float3() + : x( 0.0f ) + , y( 0.0f ) + , z( 0.0f ) + { + } + + float3(float coord_x, float coord_y, float coord_z) + : x( coord_x ) + , y( coord_y ) + , z( coord_z ) + { + } + + float3(const float3& from, const float3& to) + { + coord[0] = to.coord[0] - from.coord[0]; + coord[1] = to.coord[1] - from.coord[1]; + coord[2] = to.coord[2] - from.coord[2]; + } + + float3 crossproduct ( const float3 & vec ) + { + float a = y * vec.z - z * vec.y ; + float b = z * vec.x - x * vec.z ; + float c = x * vec.y - y * vec.x ; + return float3( a , b , c ); + } + + void normalize() + { + const float length = sqrt( ( coord[0] * coord[0] ) + + ( coord[1] * coord[1] ) + + ( coord[2] * coord[2] ) ); + if( length != 1 ) + { + coord[0] = (coord[0] / length); + coord[1] = (coord[1] / length); + coord[2] = (coord[2] / length); + } + } + +private: + union + { + float coord[3]; + struct + { + float x,y,z; + }; + }; +}; + class MaterialReader { public: MaterialReader() {} @@ -127,13 +190,12 @@ private: /// Returns true when loading .obj become success. /// Returns warning and error message into `err` /// 'mtl_basepath' is optional, and used for base path for .mtl file. -/// 'triangulate' is optional, and used whether triangulate polygon face in .obj -/// or not. +/// 'optional flags bool LoadObj(std::vector &shapes, // [output] std::vector &materials, // [output] std::string &err, // [output] const char *filename, const char *mtl_basepath = NULL, - bool triangulate = true); + unsigned int flags = 1 ); /// Loads object from a std::istream, uses GetMtlIStreamFn to retrieve /// std::istream for materials. @@ -143,7 +205,7 @@ bool LoadObj(std::vector &shapes, // [output] std::vector &materials, // [output] std::string &err, // [output] std::istream &inStream, MaterialReader &readMatFn, - bool triangulate = true); + unsigned int flags = 1); /// Loads materials into std::map void LoadMtl(std::map &material_map, // [output] @@ -516,11 +578,14 @@ static bool exportFaceGroupToShape( const std::vector &in_texcoords, const std::vector > &faceGroup, std::vector &tags, const int material_id, const std::string &name, - bool clearCache, bool triangulate) { + bool clearCache, unsigned int flags, std::string& err ) { if (faceGroup.empty()) { return false; } + bool triangulate( ( flags & triangulation ) == triangulation ); + bool normals_calculation( ( flags & calculate_normals ) == calculate_normals ); + // Flatten vertices and indices for (size_t i = 0; i < faceGroup.size(); i++) { const std::vector &face = faceGroup[i]; @@ -569,6 +634,38 @@ static bool exportFaceGroupToShape( shape.mesh.num_vertices.push_back(static_cast(npolys)); shape.mesh.material_ids.push_back(material_id); // per face } + + if( normals_calculation && shape.mesh.normals.empty() ) + { + const unsigned int nIndexs = shape.mesh.indices.size(); + shape.mesh.normals.resize(shape.mesh.positions.size()); + if( nIndexs % 3 == 0 ) + { + for ( register unsigned int iIndices = 0; iIndices < nIndexs; iIndices+=3 ) + { + float3 v1, v2, v3; + memcpy(&v1, &shape.mesh.positions[shape.mesh.indices[iIndices] * 3], sizeof(float3)); + memcpy(&v2, &shape.mesh.positions[shape.mesh.indices[iIndices + 1] * 3], sizeof(float3)); + memcpy(&v3, &shape.mesh.positions[shape.mesh.indices[iIndices + 2] * 3], sizeof(float3)); + + float3 v12( v1,v2 ); + float3 v13( v1,v3 ); + + float3 normal = v12.crossproduct(v13); + normal.normalize(); + + memcpy(&shape.mesh.normals[shape.mesh.indices[iIndices] * 3], &normal, sizeof(float3)); + memcpy(&shape.mesh.normals[shape.mesh.indices[iIndices + 1] * 3], &normal, sizeof(float3)); + memcpy(&shape.mesh.normals[shape.mesh.indices[iIndices + 2] * 3], &normal, sizeof(float3)); + } + } + else + { + std::stringstream ss; + ss << "WARN: The shape " << name << " does not have a topology of triangles, therfore the normals calculation could not be performed. Select the tinyobj::triangulation flag for this object." << std::endl; + err += ss.str(); + } + } } shape.name = name; @@ -834,7 +931,7 @@ bool MaterialFileReader::operator()(const std::string &matId, bool LoadObj(std::vector &shapes, // [output] std::vector &materials, // [output] std::string &err, const char *filename, const char *mtl_basepath, - bool trianglulate) { + unsigned int flags) { shapes.clear(); @@ -853,13 +950,14 @@ bool LoadObj(std::vector &shapes, // [output] } MaterialFileReader matFileReader(basePath); - return LoadObj(shapes, materials, err, ifs, matFileReader, trianglulate); + return LoadObj(shapes, materials, err, ifs, matFileReader, flags); } bool LoadObj(std::vector &shapes, // [output] std::vector &materials, // [output] std::string &err, std::istream &inStream, - MaterialReader &readMatFn, bool triangulate) { + MaterialReader &readMatFn, unsigned int flags) { + std::stringstream errss; std::vector v; @@ -986,7 +1084,7 @@ bool LoadObj(std::vector &shapes, // [output] if (newMaterialId != material) { // Create per-face material exportFaceGroupToShape(shape, vertexCache, v, vn, vt, faceGroup, tags, - material, name, true, triangulate); + material, name, true, flags, err ); faceGroup.clear(); material = newMaterialId; } @@ -1022,7 +1120,7 @@ bool LoadObj(std::vector &shapes, // [output] // flush previous face group. bool ret = exportFaceGroupToShape(shape, vertexCache, v, vn, vt, faceGroup, tags, - material, name, true, triangulate); + material, name, true, flags, err ); if (ret) { shapes.push_back(shape); } @@ -1059,7 +1157,7 @@ bool LoadObj(std::vector &shapes, // [output] // flush previous face group. bool ret = exportFaceGroupToShape(shape, vertexCache, v, vn, vt, faceGroup, tags, - material, name, true, triangulate); + material, name, true, flags, err ); if (ret) { shapes.push_back(shape); } @@ -1130,13 +1228,14 @@ bool LoadObj(std::vector &shapes, // [output] } bool ret = exportFaceGroupToShape(shape, vertexCache, v, vn, vt, faceGroup, - tags, material, name, true, triangulate); + tags, material, name, true, flags, err ); if (ret) { shapes.push_back(shape); } faceGroup.clear(); // for safety err += errss.str(); + return true; } From 33d5e9aa07625db7d24bafab39e3bb55ddf02a5b Mon Sep 17 00:00:00 2001 From: Vazquinhos Date: Fri, 13 May 2016 12:28:10 +0200 Subject: [PATCH 2/4] Test.cc modified with the new flags --- obj/x32/Debug/link.7608-cvtres.read.1.tlog | 1 + obj/x32/Debug/link.7608-cvtres.write.1.tlog | 1 + obj/x32/Debug/link.7608.read.1.tlog | 1 + obj/x32/Debug/link.7608.write.1.tlog | 1 + test.cc | 7 ++++--- 5 files changed, 8 insertions(+), 3 deletions(-) create mode 100644 obj/x32/Debug/link.7608-cvtres.read.1.tlog create mode 100644 obj/x32/Debug/link.7608-cvtres.write.1.tlog create mode 100644 obj/x32/Debug/link.7608.read.1.tlog create mode 100644 obj/x32/Debug/link.7608.write.1.tlog diff --git a/obj/x32/Debug/link.7608-cvtres.read.1.tlog b/obj/x32/Debug/link.7608-cvtres.read.1.tlog new file mode 100644 index 0000000..46b134b --- /dev/null +++ b/obj/x32/Debug/link.7608-cvtres.read.1.tlog @@ -0,0 +1 @@ +ÿþ \ No newline at end of file diff --git a/obj/x32/Debug/link.7608-cvtres.write.1.tlog b/obj/x32/Debug/link.7608-cvtres.write.1.tlog new file mode 100644 index 0000000..46b134b --- /dev/null +++ b/obj/x32/Debug/link.7608-cvtres.write.1.tlog @@ -0,0 +1 @@ +ÿþ \ No newline at end of file diff --git a/obj/x32/Debug/link.7608.read.1.tlog b/obj/x32/Debug/link.7608.read.1.tlog new file mode 100644 index 0000000..46b134b --- /dev/null +++ b/obj/x32/Debug/link.7608.read.1.tlog @@ -0,0 +1 @@ +ÿþ \ No newline at end of file diff --git a/obj/x32/Debug/link.7608.write.1.tlog b/obj/x32/Debug/link.7608.write.1.tlog new file mode 100644 index 0000000..46b134b --- /dev/null +++ b/obj/x32/Debug/link.7608.write.1.tlog @@ -0,0 +1 @@ +ÿþ \ No newline at end of file diff --git a/test.cc b/test.cc index 2539faa..523973f 100644 --- a/test.cc +++ b/test.cc @@ -124,7 +124,7 @@ static bool TestLoadObj( const char* filename, const char* basepath = NULL, - bool triangulate = true) + unsigned int flags = 1 ) { std::cout << "Loading " << filename << std::endl; @@ -132,7 +132,7 @@ TestLoadObj( std::vector materials; std::string err; - bool ret = tinyobj::LoadObj(shapes, materials, err, filename, basepath, triangulate); + bool ret = tinyobj::LoadObj(shapes, materials, err, filename, basepath, flags); if (!err.empty()) { std::cerr << err << std::endl; @@ -143,7 +143,8 @@ TestLoadObj( return false; } - PrintInfo(shapes, materials, triangulate); + bool triangulate( ( flags & tinyobj::triangulation ) == tinyobj::triangulation ); + PrintInfo(shapes, materials, triangulate ); return true; } From 0dcc72239d9f593b7347ed45ce2d71feefff3f6b Mon Sep 17 00:00:00 2001 From: Vazquinhos Date: Fri, 13 May 2016 12:29:42 +0200 Subject: [PATCH 3/4] Files deleted of compilation log --- obj/x32/Debug/link.7608-cvtres.read.1.tlog | 1 - obj/x32/Debug/link.7608-cvtres.write.1.tlog | 1 - obj/x32/Debug/link.7608.read.1.tlog | 1 - obj/x32/Debug/link.7608.write.1.tlog | 1 - 4 files changed, 4 deletions(-) delete mode 100644 obj/x32/Debug/link.7608-cvtres.read.1.tlog delete mode 100644 obj/x32/Debug/link.7608-cvtres.write.1.tlog delete mode 100644 obj/x32/Debug/link.7608.read.1.tlog delete mode 100644 obj/x32/Debug/link.7608.write.1.tlog diff --git a/obj/x32/Debug/link.7608-cvtres.read.1.tlog b/obj/x32/Debug/link.7608-cvtres.read.1.tlog deleted file mode 100644 index 46b134b..0000000 --- a/obj/x32/Debug/link.7608-cvtres.read.1.tlog +++ /dev/null @@ -1 +0,0 @@ -ÿþ \ No newline at end of file diff --git a/obj/x32/Debug/link.7608-cvtres.write.1.tlog b/obj/x32/Debug/link.7608-cvtres.write.1.tlog deleted file mode 100644 index 46b134b..0000000 --- a/obj/x32/Debug/link.7608-cvtres.write.1.tlog +++ /dev/null @@ -1 +0,0 @@ -ÿþ \ No newline at end of file diff --git a/obj/x32/Debug/link.7608.read.1.tlog b/obj/x32/Debug/link.7608.read.1.tlog deleted file mode 100644 index 46b134b..0000000 --- a/obj/x32/Debug/link.7608.read.1.tlog +++ /dev/null @@ -1 +0,0 @@ -ÿþ \ No newline at end of file diff --git a/obj/x32/Debug/link.7608.write.1.tlog b/obj/x32/Debug/link.7608.write.1.tlog deleted file mode 100644 index 46b134b..0000000 --- a/obj/x32/Debug/link.7608.write.1.tlog +++ /dev/null @@ -1 +0,0 @@ -ÿþ \ No newline at end of file From 9aee576b99e38f05cc2e3af804650484358fe3b8 Mon Sep 17 00:00:00 2001 From: Vazquinhos Date: Fri, 13 May 2016 12:37:24 +0200 Subject: [PATCH 4/4] Added dependencies to cmath in order to use sqrt --- tiny_obj_loader.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tiny_obj_loader.h b/tiny_obj_loader.h index 5127a2e..f63ff02 100644 --- a/tiny_obj_loader.h +++ b/tiny_obj_loader.h @@ -44,6 +44,7 @@ #include #include #include +#include namespace tinyobj { @@ -138,9 +139,9 @@ public: void normalize() { - const float length = sqrt( ( coord[0] * coord[0] ) + - ( coord[1] * coord[1] ) + - ( coord[2] * coord[2] ) ); + const float length = std::sqrt( ( coord[0] * coord[0] ) + + ( coord[1] * coord[1] ) + + ( coord[2] * coord[2] ) ); if( length != 1 ) { coord[0] = (coord[0] / length);