diff options
author | erwincoumans <erwincoumans@google.com> | 2019-08-14 13:37:14 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-08-14 13:37:14 -0700 |
commit | 75df77611aaa3151ac857c7d8da97bae6bcc8261 (patch) | |
tree | 38c34997ae6df6e8378c9eb44af8b566f7ec4fd6 | |
parent | 3301b46367ea174f866465ce2ff7e1863aaf4a91 (diff) | |
parent | eacebc80d54fdb19152805901f51137b1ae48172 (diff) | |
download | bullet3-75df77611aaa3151ac857c7d8da97bae6bcc8261.tar.gz |
Merge pull request #2366 from fuchuyuan/tinyObjUpdate
update obj loader
12 files changed, 475 insertions, 365 deletions
diff --git a/Extras/obj2sdf/obj2sdf.cpp b/Extras/obj2sdf/obj2sdf.cpp index b6a638c7f..8d3db3955 100644 --- a/Extras/obj2sdf/obj2sdf.cpp +++ b/Extras/obj2sdf/obj2sdf.cpp @@ -77,9 +77,10 @@ int main(int argc, char* argv[]) b3FileUtils::extractPath(fileNameWithPath, materialPrefixPath, MAX_PATH_LEN); std::vector<tinyobj::shape_t> shapes; + tinyobj::attrib_t attribute; b3BulletDefaultFileIO fileIO; - std::string err = tinyobj::LoadObj(shapes, fileNameWithPath, materialPrefixPath,&fileIO); + std::string err = tinyobj::LoadObj(attribute, shapes, fileNameWithPath, materialPrefixPath,&fileIO); char sdfFileName[MAX_PATH_LEN]; sprintf(sdfFileName, "%s%s.sdf", materialPrefixPath, "newsdf"); @@ -117,20 +118,20 @@ int main(int argc, char* argv[]) int curTexcoords = shapeC->texcoords.size() / 2; int faceCount = shape.mesh.indices.size(); - int vertexCount = shape.mesh.positions.size(); + int vertexCount = attribute.vertices.size(); for (int v = 0; v < vertexCount; v++) { - shapeC->positions.push_back(shape.mesh.positions[v]); + shapeC->positions.push_back(attribute.vertices[v]); } - int numNormals = int(shape.mesh.normals.size()); + int numNormals = int(attribute.normals.size()); for (int vn = 0; vn < numNormals; vn++) { - shapeC->normals.push_back(shape.mesh.normals[vn]); + shapeC->normals.push_back(attribute.normals[vn]); } - int numTexCoords = int(shape.mesh.texcoords.size()); + int numTexCoords = int(attribute.texcoords.size()); for (int vt = 0; vt < numTexCoords; vt++) { - shapeC->texcoords.push_back(shape.mesh.texcoords[vt]); + shapeC->texcoords.push_back(attribute.texcoords[vt]); } for (int face = 0; face < faceCount; face += 3) @@ -140,9 +141,9 @@ int main(int argc, char* argv[]) continue; } - shapeC->indices.push_back(shape.mesh.indices[face] + curPositions); - shapeC->indices.push_back(shape.mesh.indices[face + 1] + curPositions); - shapeC->indices.push_back(shape.mesh.indices[face + 2] + curPositions); + shapeC->indices.push_back(shape.mesh.indices[face].vertex_index + curPositions); + shapeC->indices.push_back(shape.mesh.indices[face + 1].vertex_index + curPositions); + shapeC->indices.push_back(shape.mesh.indices[face + 2].vertex_index + curPositions); } } } @@ -329,7 +330,7 @@ int main(int argc, char* argv[]) } int faceCount = shape.mesh.indices.size(); - int vertexCount = shape.mesh.positions.size(); + int vertexCount = attribute.vertices.size(); tinyobj::material_t mat = shape.material; if (shape.name.length()) { @@ -339,7 +340,7 @@ int main(int argc, char* argv[]) } for (int v = 0; v < vertexCount / 3; v++) { - fprintf(f, "v %f %f %f\n", shape.mesh.positions[v * 3 + 0], shape.mesh.positions[v * 3 + 1], shape.mesh.positions[v * 3 + 2]); + fprintf(f, "v %f %f %f\n", attribute.vertices[v * 3 + 0], attribute.vertices[v * 3 + 1], attribute.vertices[v * 3 + 2]); } if (mat.name.length()) @@ -352,18 +353,18 @@ int main(int argc, char* argv[]) } fprintf(f, "\n"); - int numNormals = int(shape.mesh.normals.size()); + int numNormals = int(attribute.normals.size()); for (int vn = 0; vn < numNormals / 3; vn++) { - fprintf(f, "vn %f %f %f\n", shape.mesh.normals[vn * 3 + 0], shape.mesh.normals[vn * 3 + 1], shape.mesh.normals[vn * 3 + 2]); + fprintf(f, "vn %f %f %f\n", attribute.normals[vn * 3 + 0], attribute.normals[vn * 3 + 1], attribute.normals[vn * 3 + 2]); } fprintf(f, "\n"); - int numTexCoords = int(shape.mesh.texcoords.size()); + int numTexCoords = int(attribute.texcoords.size()); for (int vt = 0; vt < numTexCoords / 2; vt++) { - fprintf(f, "vt %f %f\n", shape.mesh.texcoords[vt * 2 + 0], shape.mesh.texcoords[vt * 2 + 1]); + fprintf(f, "vt %f %f\n", attribute.texcoords[vt * 2 + 0], attribute.texcoords[vt * 2 + 1]); } fprintf(f, "s off\n"); @@ -375,9 +376,9 @@ int main(int argc, char* argv[]) continue; } fprintf(f, "f %d/%d/%d %d/%d/%d %d/%d/%d\n", - shape.mesh.indices[face] + 1, shape.mesh.indices[face] + 1, shape.mesh.indices[face] + 1, - shape.mesh.indices[face + 1] + 1, shape.mesh.indices[face + 1] + 1, shape.mesh.indices[face + 1] + 1, - shape.mesh.indices[face + 2] + 1, shape.mesh.indices[face + 2] + 1, shape.mesh.indices[face + 2] + 1); + shape.mesh.indices[face].vertex_index + 1, shape.mesh.indices[face].vertex_index + 1, shape.mesh.indices[face].vertex_index + 1, + shape.mesh.indices[face + 1].vertex_index + 1, shape.mesh.indices[face + 1].vertex_index + 1, shape.mesh.indices[face + 1].vertex_index + 1, + shape.mesh.indices[face + 2].vertex_index + 1, shape.mesh.indices[face + 2].vertex_index + 1, shape.mesh.indices[face + 2].vertex_index + 1); } fclose(f); @@ -437,4 +438,4 @@ int main(int argc, char* argv[]) fclose(sdfFile); return 0; -}
\ No newline at end of file +} diff --git a/examples/Importers/ImportMJCFDemo/BulletMJCFImporter.cpp b/examples/Importers/ImportMJCFDemo/BulletMJCFImporter.cpp index d630f8599..f868bcb13 100644 --- a/examples/Importers/ImportMJCFDemo/BulletMJCFImporter.cpp +++ b/examples/Importers/ImportMJCFDemo/BulletMJCFImporter.cpp @@ -2265,7 +2265,7 @@ int BulletMJCFImporter::getBodyUniqueId() const return m_data->m_activeBodyUniqueId; } -static btCollisionShape* MjcfCreateConvexHullFromShapes(std::vector<tinyobj::shape_t>& shapes, const btVector3& geomScale, btScalar collisionMargin) +static btCollisionShape* MjcfCreateConvexHullFromShapes(const tinyobj::attrib_t& attribute, std::vector<tinyobj::shape_t>& shapes, const btVector3& geomScale, btScalar collisionMargin) { btCompoundShape* compound = new btCompoundShape(); compound->setMargin(collisionMargin); @@ -2278,25 +2278,26 @@ static btCollisionShape* MjcfCreateConvexHullFromShapes(std::vector<tinyobj::sha btConvexHullShape* convexHull = new btConvexHullShape(); convexHull->setMargin(collisionMargin); tinyobj::shape_t& shape = shapes[s]; + int faceCount = shape.mesh.indices.size(); for (int f = 0; f < faceCount; f += 3) { btVector3 pt; - pt.setValue(shape.mesh.positions[shape.mesh.indices[f] * 3 + 0], - shape.mesh.positions[shape.mesh.indices[f] * 3 + 1], - shape.mesh.positions[shape.mesh.indices[f] * 3 + 2]); + pt.setValue(attribute.vertices[3 * shape.mesh.indices[f].vertex_index + 0], + attribute.vertices[3 * shape.mesh.indices[f].vertex_index + 1], + attribute.vertices[3 * shape.mesh.indices[f].vertex_index + 2]); convexHull->addPoint(pt * geomScale, false); - pt.setValue(shape.mesh.positions[shape.mesh.indices[f + 1] * 3 + 0], - shape.mesh.positions[shape.mesh.indices[f + 1] * 3 + 1], - shape.mesh.positions[shape.mesh.indices[f + 1] * 3 + 2]); + pt.setValue(attribute.vertices[3 * shape.mesh.indices[f + 1].vertex_index + 0], + attribute.vertices[3 * shape.mesh.indices[f + 1].vertex_index + 1], + attribute.vertices[3 * shape.mesh.indices[f + 1].vertex_index + 2]); convexHull->addPoint(pt * geomScale, false); - pt.setValue(shape.mesh.positions[shape.mesh.indices[f + 2] * 3 + 0], - shape.mesh.positions[shape.mesh.indices[f + 2] * 3 + 1], - shape.mesh.positions[shape.mesh.indices[f + 2] * 3 + 2]); + pt.setValue(attribute.vertices[3 * shape.mesh.indices[f + 2].vertex_index + 0], + attribute.vertices[3 * shape.mesh.indices[f + 2].vertex_index + 1], + attribute.vertices[3 * shape.mesh.indices[f + 2].vertex_index + 2]); convexHull->addPoint(pt * geomScale, false); } @@ -2391,10 +2392,11 @@ class btCompoundShape* BulletMJCFImporter::convertLinkCollisionShapes(int linkIn else { std::vector<tinyobj::shape_t> shapes; - std::string err = tinyobj::LoadObj(shapes, col->m_geometry.m_meshFileName.c_str(),"",m_data->m_fileIO); + tinyobj::attrib_t attribute; + std::string err = tinyobj::LoadObj(attribute, shapes, col->m_geometry.m_meshFileName.c_str(), "", m_data->m_fileIO); //create a convex hull for each shape, and store it in a btCompoundShape - childShape = MjcfCreateConvexHullFromShapes(shapes, col->m_geometry.m_meshScale, m_data->m_globalDefaults.m_defaultCollisionMargin); + childShape = MjcfCreateConvexHullFromShapes(attribute, shapes, col->m_geometry.m_meshScale, m_data->m_globalDefaults.m_defaultCollisionMargin); } break; } diff --git a/examples/Importers/ImportMeshUtility/b3ImportMeshUtility.cpp b/examples/Importers/ImportMeshUtility/b3ImportMeshUtility.cpp index b4e02243d..6f13d86b2 100644 --- a/examples/Importers/ImportMeshUtility/b3ImportMeshUtility.cpp +++ b/examples/Importers/ImportMeshUtility/b3ImportMeshUtility.cpp @@ -65,13 +65,14 @@ bool b3ImportMeshUtility::loadAndRegisterMeshFromFileInternal(const std::string& btVector3 shift(0, 0, 0); std::vector<tinyobj::shape_t> shapes; + tinyobj::attrib_t attribute; { B3_PROFILE("tinyobj::LoadObj"); - std::string err = LoadFromCachedOrFromObj(shapes, relativeFileName, pathPrefix,fileIO); + std::string err = LoadFromCachedOrFromObj(attribute, shapes, relativeFileName, pathPrefix, fileIO); //std::string err = tinyobj::LoadObj(shapes, relativeFileName, pathPrefix); } - GLInstanceGraphicsShape* gfxShape = btgCreateGraphicsShapeFromWavefrontObj(shapes); + GLInstanceGraphicsShape* gfxShape = btgCreateGraphicsShapeFromWavefrontObj(attribute, shapes); { B3_PROFILE("Load Texture"); //int textureIndex = -1; @@ -84,7 +85,7 @@ bool b3ImportMeshUtility::loadAndRegisterMeshFromFileInternal(const std::string& meshData.m_rgbaColor[2] = shape.material.diffuse[2]; meshData.m_rgbaColor[3] = shape.material.transparency; meshData.m_flags |= B3_IMPORT_MESH_HAS_RGBA_COLOR; - + meshData.m_specularColor[0] = shape.material.specular[0]; meshData.m_specularColor[1] = shape.material.specular[1]; meshData.m_specularColor[2] = shape.material.specular[2]; diff --git a/examples/Importers/ImportObjDemo/LoadMeshFromObj.cpp b/examples/Importers/ImportObjDemo/LoadMeshFromObj.cpp index 566682d0a..e5bd6633c 100644 --- a/examples/Importers/ImportObjDemo/LoadMeshFromObj.cpp +++ b/examples/Importers/ImportObjDemo/LoadMeshFromObj.cpp @@ -12,6 +12,7 @@ struct CachedObjResult { std::string m_msg; std::vector<tinyobj::shape_t> m_shapes; + tinyobj::attrib_t m_attribute; }; static b3HashMap<b3HashString, CachedObjResult> gCachedObjResults; @@ -31,24 +32,26 @@ void b3EnableFileCaching(int enable) } std::string LoadFromCachedOrFromObj( + tinyobj::attrib_t& attribute, std::vector<tinyobj::shape_t>& shapes, // [output] const char* filename, const char* mtl_basepath, - struct CommonFileIOInterface* fileIO - ) + struct CommonFileIOInterface* fileIO) { CachedObjResult* resultPtr = gCachedObjResults[filename]; if (resultPtr) { const CachedObjResult& result = *resultPtr; shapes = result.m_shapes; + attribute = result.m_attribute; return result.m_msg; } - std::string err = tinyobj::LoadObj(shapes, filename, mtl_basepath,fileIO); + std::string err = tinyobj::LoadObj(attribute, shapes, filename, mtl_basepath, fileIO); CachedObjResult result; result.m_msg = err; result.m_shapes = shapes; + result.m_attribute = attribute; if (gEnableFileCaching) { gCachedObjResults.insert(filename, result); @@ -60,14 +63,15 @@ GLInstanceGraphicsShape* LoadMeshFromObj(const char* relativeFileName, const cha { B3_PROFILE("LoadMeshFromObj"); std::vector<tinyobj::shape_t> shapes; + tinyobj::attrib_t attribute; { B3_PROFILE("tinyobj::LoadObj2"); - std::string err = LoadFromCachedOrFromObj(shapes, relativeFileName, materialPrefixPath,fileIO); + std::string err = LoadFromCachedOrFromObj(attribute, shapes, relativeFileName, materialPrefixPath, fileIO); } { B3_PROFILE("btgCreateGraphicsShapeFromWavefrontObj"); - GLInstanceGraphicsShape* gfxShape = btgCreateGraphicsShapeFromWavefrontObj(shapes); + GLInstanceGraphicsShape* gfxShape = btgCreateGraphicsShapeFromWavefrontObj(attribute, shapes); return gfxShape; } } diff --git a/examples/Importers/ImportObjDemo/LoadMeshFromObj.h b/examples/Importers/ImportObjDemo/LoadMeshFromObj.h index 9b62074c1..54bc66312 100644 --- a/examples/Importers/ImportObjDemo/LoadMeshFromObj.h +++ b/examples/Importers/ImportObjDemo/LoadMeshFromObj.h @@ -8,8 +8,8 @@ struct GLInstanceGraphicsShape; int b3IsFileCachingEnabled(); void b3EnableFileCaching(int enable); - std::string LoadFromCachedOrFromObj( + tinyobj::attrib_t& attribute, std::vector<tinyobj::shape_t>& shapes, // [output] const char* filename, const char* mtl_basepath, diff --git a/examples/Importers/ImportObjDemo/Wavefront2GLInstanceGraphicsShape.cpp b/examples/Importers/ImportObjDemo/Wavefront2GLInstanceGraphicsShape.cpp index ead2769a0..08fa521ae 100644 --- a/examples/Importers/ImportObjDemo/Wavefront2GLInstanceGraphicsShape.cpp +++ b/examples/Importers/ImportObjDemo/Wavefront2GLInstanceGraphicsShape.cpp @@ -9,7 +9,7 @@ #include "../../OpenGLWindow/GLInstancingRenderer.h" #include "../../OpenGLWindow/GLInstanceGraphicsShape.h" -GLInstanceGraphicsShape* btgCreateGraphicsShapeFromWavefrontObj(std::vector<tinyobj::shape_t>& shapes, bool flatShading) +GLInstanceGraphicsShape* btgCreateGraphicsShapeFromWavefrontObj(const tinyobj::attrib_t& attribute, std::vector<tinyobj::shape_t>& shapes, bool flatShading) { b3AlignedObjectArray<GLInstanceVertex>* vertices = new b3AlignedObjectArray<GLInstanceVertex>; { @@ -36,19 +36,20 @@ GLInstanceGraphicsShape* btgCreateGraphicsShapeFromWavefrontObj(std::vector<tiny } GLInstanceVertex vtx0; - vtx0.xyzw[0] = shape.mesh.positions[shape.mesh.indices[f] * 3 + 0]; - vtx0.xyzw[1] = shape.mesh.positions[shape.mesh.indices[f] * 3 + 1]; - vtx0.xyzw[2] = shape.mesh.positions[shape.mesh.indices[f] * 3 + 2]; + tinyobj::index_t v_0 = shape.mesh.indices[f]; + vtx0.xyzw[0] = attribute.vertices[3 * v_0.vertex_index]; + vtx0.xyzw[1] = attribute.vertices[3 * v_0.vertex_index + 1]; + vtx0.xyzw[2] = attribute.vertices[3 * v_0.vertex_index + 2]; vtx0.xyzw[3] = 0.f; - if (shape.mesh.texcoords.size()) + if (attribute.texcoords.size()) { - int uv0Index = shape.mesh.indices[f] * 2 + 0; - int uv1Index = shape.mesh.indices[f] * 2 + 1; - if (uv0Index >= 0 && uv1Index >= 0 && (uv0Index < int(shape.mesh.texcoords.size()) && (uv1Index < shape.mesh.texcoords.size()))) + int uv0Index = 2 * v_0.texcoord_index; + int uv1Index = 2 * v_0.texcoord_index + 1; + if (uv0Index >= 0 && uv1Index >= 0 && (uv0Index < int(attribute.texcoords.size()) && (uv1Index < attribute.texcoords.size()))) { - vtx0.uv[0] = shape.mesh.texcoords[uv0Index]; - vtx0.uv[1] = shape.mesh.texcoords[uv1Index]; + vtx0.uv[0] = attribute.texcoords[uv0Index]; + vtx0.uv[1] = attribute.texcoords[uv1Index]; } else { @@ -64,19 +65,20 @@ GLInstanceGraphicsShape* btgCreateGraphicsShapeFromWavefrontObj(std::vector<tiny } GLInstanceVertex vtx1; - vtx1.xyzw[0] = shape.mesh.positions[shape.mesh.indices[f + 1] * 3 + 0]; - vtx1.xyzw[1] = shape.mesh.positions[shape.mesh.indices[f + 1] * 3 + 1]; - vtx1.xyzw[2] = shape.mesh.positions[shape.mesh.indices[f + 1] * 3 + 2]; + tinyobj::index_t v_1 = shape.mesh.indices[f + 1]; + vtx1.xyzw[0] = attribute.vertices[3 * v_1.vertex_index]; + vtx1.xyzw[1] = attribute.vertices[3 * v_1.vertex_index + 1]; + vtx1.xyzw[2] = attribute.vertices[3 * v_1.vertex_index + 2]; vtx1.xyzw[3] = 0.f; - if (shape.mesh.texcoords.size()) + if (attribute.texcoords.size()) { - int uv0Index = shape.mesh.indices[f + 1] * 2 + 0; - int uv1Index = shape.mesh.indices[f + 1] * 2 + 1; - if (uv0Index >= 0 && uv1Index >= 0 && (uv0Index < shape.mesh.texcoords.size()) && (uv1Index < shape.mesh.texcoords.size())) + int uv0Index = 2 * v_1.texcoord_index; + int uv1Index = 2 * v_1.texcoord_index + 1; + if (uv0Index >= 0 && uv1Index >= 0 && (uv0Index < attribute.texcoords.size()) && (uv1Index < attribute.texcoords.size())) { - vtx1.uv[0] = shape.mesh.texcoords[uv0Index]; - vtx1.uv[1] = shape.mesh.texcoords[uv1Index]; + vtx1.uv[0] = attribute.texcoords[uv0Index]; + vtx1.uv[1] = attribute.texcoords[uv1Index]; } else { @@ -92,18 +94,20 @@ GLInstanceGraphicsShape* btgCreateGraphicsShapeFromWavefrontObj(std::vector<tiny } GLInstanceVertex vtx2; - vtx2.xyzw[0] = shape.mesh.positions[shape.mesh.indices[f + 2] * 3 + 0]; - vtx2.xyzw[1] = shape.mesh.positions[shape.mesh.indices[f + 2] * 3 + 1]; - vtx2.xyzw[2] = shape.mesh.positions[shape.mesh.indices[f + 2] * 3 + 2]; + tinyobj::index_t v_2 = shape.mesh.indices[f + 2]; + vtx2.xyzw[0] = attribute.vertices[3 * v_2.vertex_index]; + vtx2.xyzw[1] = attribute.vertices[3 * v_2.vertex_index + 1]; + vtx2.xyzw[2] = attribute.vertices[3 * v_2.vertex_index + 2]; vtx2.xyzw[3] = 0.f; - if (shape.mesh.texcoords.size()) + if (attribute.texcoords.size()) { - int uv0Index = shape.mesh.indices[f + 2] * 2 + 0; - int uv1Index = shape.mesh.indices[f + 2] * 2 + 1; - if (uv0Index >= 0 && uv1Index >= 0 && (uv0Index < shape.mesh.texcoords.size()) && (uv1Index < shape.mesh.texcoords.size())) + int uv0Index = 2 * v_2.texcoord_index; + int uv1Index = 2 * v_2.texcoord_index + 1; + + if (uv0Index >= 0 && uv1Index >= 0 && (uv0Index < attribute.texcoords.size()) && (uv1Index < attribute.texcoords.size())) { - vtx2.uv[0] = shape.mesh.texcoords[uv0Index]; - vtx2.uv[1] = shape.mesh.texcoords[uv1Index]; + vtx2.uv[0] = attribute.texcoords[uv0Index]; + vtx2.uv[1] = attribute.texcoords[uv1Index]; } else { @@ -123,16 +127,21 @@ GLInstanceGraphicsShape* btgCreateGraphicsShapeFromWavefrontObj(std::vector<tiny btVector3 v2(vtx2.xyzw[0], vtx2.xyzw[1], vtx2.xyzw[2]); unsigned int maxIndex = 0; - maxIndex = b3Max(maxIndex, shape.mesh.indices[f] * 3 + 0); - maxIndex = b3Max(maxIndex, shape.mesh.indices[f] * 3 + 1); - maxIndex = b3Max(maxIndex, shape.mesh.indices[f] * 3 + 2); - maxIndex = b3Max(maxIndex, shape.mesh.indices[f + 1] * 3 + 0); - maxIndex = b3Max(maxIndex, shape.mesh.indices[f + 1] * 3 + 1); - maxIndex = b3Max(maxIndex, shape.mesh.indices[f + 1] * 3 + 2); - maxIndex = b3Max(maxIndex, shape.mesh.indices[f + 2] * 3 + 0); - maxIndex = b3Max(maxIndex, shape.mesh.indices[f + 2] * 3 + 1); - maxIndex = b3Max(maxIndex, shape.mesh.indices[f + 2] * 3 + 2); - bool hasNormals = (shape.mesh.normals.size() && maxIndex < shape.mesh.normals.size()); + unsigned n0Index = shape.mesh.indices[f].normal_index; + unsigned n1Index = shape.mesh.indices[f + 1].normal_index; + unsigned n2Index = shape.mesh.indices[f + 2].normal_index; + + maxIndex = b3Max(maxIndex, 3 * n0Index + 0); + maxIndex = b3Max(maxIndex, 3 * n0Index + 1); + maxIndex = b3Max(maxIndex, 3 * n0Index + 2); + maxIndex = b3Max(maxIndex, 3 * n1Index + 0); + maxIndex = b3Max(maxIndex, 3 * n1Index + 1); + maxIndex = b3Max(maxIndex, 3 * n1Index + 2); + maxIndex = b3Max(maxIndex, 3 * n2Index + 0); + maxIndex = b3Max(maxIndex, 3 * n2Index + 1); + maxIndex = b3Max(maxIndex, 3 * n2Index + 2); + + bool hasNormals = (attribute.normals.size() && maxIndex < attribute.normals.size()); if (flatShading || !hasNormals) { @@ -159,15 +168,15 @@ GLInstanceGraphicsShape* btgCreateGraphicsShapeFromWavefrontObj(std::vector<tiny } else { - vtx0.normal[0] = shape.mesh.normals[shape.mesh.indices[f] * 3 + 0]; - vtx0.normal[1] = shape.mesh.normals[shape.mesh.indices[f] * 3 + 1]; - vtx0.normal[2] = shape.mesh.normals[shape.mesh.indices[f] * 3 + 2]; //shape.mesh.indices[f+1]*3+0 - vtx1.normal[0] = shape.mesh.normals[shape.mesh.indices[f + 1] * 3 + 0]; - vtx1.normal[1] = shape.mesh.normals[shape.mesh.indices[f + 1] * 3 + 1]; - vtx1.normal[2] = shape.mesh.normals[shape.mesh.indices[f + 1] * 3 + 2]; - vtx2.normal[0] = shape.mesh.normals[shape.mesh.indices[f + 2] * 3 + 0]; - vtx2.normal[1] = shape.mesh.normals[shape.mesh.indices[f + 2] * 3 + 1]; - vtx2.normal[2] = shape.mesh.normals[shape.mesh.indices[f + 2] * 3 + 2]; + vtx0.normal[0] = attribute.normals[3 * n0Index+ 0]; + vtx0.normal[1] = attribute.normals[3 * n0Index+ 1]; + vtx0.normal[2] = attribute.normals[3 * n0Index+ 2]; + vtx1.normal[0] = attribute.normals[3 * n1Index+ 0]; + vtx1.normal[1] = attribute.normals[3 * n1Index+ 1]; + vtx1.normal[2] = attribute.normals[3 * n1Index+ 2]; + vtx2.normal[0] = attribute.normals[3 * n2Index+ 0]; + vtx2.normal[1] = attribute.normals[3 * n2Index+ 1]; + vtx2.normal[2] = attribute.normals[3 * n2Index+ 2]; } vertices->push_back(vtx0); vertices->push_back(vtx1); diff --git a/examples/Importers/ImportObjDemo/Wavefront2GLInstanceGraphicsShape.h b/examples/Importers/ImportObjDemo/Wavefront2GLInstanceGraphicsShape.h index 2840a85d7..4054b4dab 100644 --- a/examples/Importers/ImportObjDemo/Wavefront2GLInstanceGraphicsShape.h +++ b/examples/Importers/ImportObjDemo/Wavefront2GLInstanceGraphicsShape.h @@ -4,6 +4,6 @@ #include "../../ThirdPartyLibs/Wavefront/tiny_obj_loader.h" #include <vector> -struct GLInstanceGraphicsShape* btgCreateGraphicsShapeFromWavefrontObj(std::vector<tinyobj::shape_t>& shapes, bool flatShading = false); +struct GLInstanceGraphicsShape* btgCreateGraphicsShapeFromWavefrontObj(const tinyobj::attrib_t& attribute, std::vector<tinyobj::shape_t>& shapes, bool flatShading = false); #endif //WAVEFRONT2GRAPHICS_H diff --git a/examples/Importers/ImportURDFDemo/BulletUrdfImporter.cpp b/examples/Importers/ImportURDFDemo/BulletUrdfImporter.cpp index f295458a8..16c85d0b5 100644 --- a/examples/Importers/ImportURDFDemo/BulletUrdfImporter.cpp +++ b/examples/Importers/ImportURDFDemo/BulletUrdfImporter.cpp @@ -509,7 +509,7 @@ bool BulletURDFImporter::getRootTransformInWorld(btTransform& rootTransformInWor return true; } -static btCollisionShape* createConvexHullFromShapes(std::vector<tinyobj::shape_t>& shapes, const btVector3& geomScale, int flags) +static btCollisionShape* createConvexHullFromShapes(const tinyobj::attrib_t& attribute, std::vector<tinyobj::shape_t>& shapes, const btVector3& geomScale, int flags) { B3_PROFILE("createConvexHullFromShapes"); btCompoundShape* compound = new btCompoundShape(); @@ -528,20 +528,20 @@ static btCollisionShape* createConvexHullFromShapes(std::vector<tinyobj::shape_t for (int f = 0; f < faceCount; f += 3) { btVector3 pt; - pt.setValue(shape.mesh.positions[shape.mesh.indices[f] * 3 + 0], - shape.mesh.positions[shape.mesh.indices[f] * 3 + 1], - shape.mesh.positions[shape.mesh.indices[f] * 3 + 2]); + pt.setValue(attribute.vertices[3 * shape.mesh.indices[f + 0].vertex_index + 0], + attribute.vertices[3 * shape.mesh.indices[f + 0].vertex_index + 1], + attribute.vertices[3 * shape.mesh.indices[f + 0].vertex_index + 2]); convexHull->addPoint(pt * geomScale, false); - pt.setValue(shape.mesh.positions[shape.mesh.indices[f + 1] * 3 + 0], - shape.mesh.positions[shape.mesh.indices[f + 1] * 3 + 1], - shape.mesh.positions[shape.mesh.indices[f + 1] * 3 + 2]); + pt.setValue(attribute.vertices[3 * shape.mesh.indices[f + 1].vertex_index + 0], + attribute.vertices[3 * shape.mesh.indices[f + 1].vertex_index + 1], + attribute.vertices[3 * shape.mesh.indices[f + 1].vertex_index + 2]); convexHull->addPoint(pt * geomScale, false); - pt.setValue(shape.mesh.positions[shape.mesh.indices[f + 2] * 3 + 0], - shape.mesh.positions[shape.mesh.indices[f + 2] * 3 + 1], - shape.mesh.positions[shape.mesh.indices[f + 2] * 3 + 2]); + pt.setValue(attribute.vertices[3 * shape.mesh.indices[f + 2].vertex_index + 0], + attribute.vertices[3 * shape.mesh.indices[f + 2].vertex_index + 1], + attribute.vertices[3 * shape.mesh.indices[f + 2].vertex_index + 2]); convexHull->addPoint(pt * geomScale, false); } @@ -558,8 +558,6 @@ static btCollisionShape* createConvexHullFromShapes(std::vector<tinyobj::shape_t return compound; } - - int BulletURDFImporter::getUrdfFromCollisionShape(const btCollisionShape* collisionShape, UrdfCollision& collision) const { UrdfCollision* col = m_data->m_bulletCollisionShape2UrdfCollision.find(collisionShape); @@ -718,10 +716,10 @@ btCollisionShape* BulletURDFImporter::convertURDFToCollisionShape(const UrdfColl else { std::vector<tinyobj::shape_t> shapes; - std::string err = tinyobj::LoadObj(shapes, collision->m_geometry.m_meshFileName.c_str(),"",m_data->m_fileIO); + tinyobj::attrib_t attribute; + std::string err = tinyobj::LoadObj(attribute, shapes, collision->m_geometry.m_meshFileName.c_str(), "", m_data->m_fileIO); //create a convex hull for each shape, and store it in a btCompoundShape - - shape = createConvexHullFromShapes(shapes, collision->m_geometry.m_meshScale, m_data->m_flags); + shape = createConvexHullFromShapes(attribute, shapes, collision->m_geometry.m_meshScale, m_data->m_flags); m_data->m_bulletCollisionShape2UrdfCollision.insert(shape, *collision); return shape; } diff --git a/examples/SharedMemory/PhysicsServerCommandProcessor.cpp b/examples/SharedMemory/PhysicsServerCommandProcessor.cpp index b8e0275cd..961fc617a 100644 --- a/examples/SharedMemory/PhysicsServerCommandProcessor.cpp +++ b/examples/SharedMemory/PhysicsServerCommandProcessor.cpp @@ -4764,7 +4764,8 @@ bool PhysicsServerCommandProcessor::processCreateCollisionShapeCommand(const str else { std::vector<tinyobj::shape_t> shapes; - std::string err = tinyobj::LoadObj(shapes, out_found_filename.c_str(),"",fileIO); + tinyobj::attrib_t attribute; + std::string err = tinyobj::LoadObj(attribute, shapes, out_found_filename.c_str(), "", fileIO); //shape = createConvexHullFromShapes(shapes, collision->m_geometry.m_meshScale); //static btCollisionShape* createConvexHullFromShapes(std::vector<tinyobj::shape_t>& shapes, const btVector3& geomScale) @@ -4785,20 +4786,20 @@ bool PhysicsServerCommandProcessor::processCreateCollisionShapeCommand(const str for (int f = 0; f < faceCount; f += 3) { btVector3 pt; - pt.setValue(shape.mesh.positions[shape.mesh.indices[f] * 3 + 0], - shape.mesh.positions[shape.mesh.indices[f] * 3 + 1], - shape.mesh.positions[shape.mesh.indices[f] * 3 + 2]); + pt.setValue(attribute.vertices[3 * shape.mesh.indices[f + 0].vertex_index + 0], + attribute.vertices[3 * shape.mesh.indices[f + 0].vertex_index + 1], + attribute.vertices[3 * shape.mesh.indices[f + 0].vertex_index + 2]); convexHull->addPoint(pt * meshScale, false); - pt.setValue(shape.mesh.positions[shape.mesh.indices[f + 1] * 3 + 0], - shape.mesh.positions[shape.mesh.indices[f + 1] * 3 + 1], - shape.mesh.positions[shape.mesh.indices[f + 1] * 3 + 2]); + pt.setValue(attribute.vertices[3 * shape.mesh.indices[f + 1].vertex_index + 0], + attribute.vertices[3 * shape.mesh.indices[f + 1].vertex_index + 1], + attribute.vertices[3 * shape.mesh.indices[f + 1].vertex_index + 2]); convexHull->addPoint(pt * meshScale, false); - pt.setValue(shape.mesh.positions[shape.mesh.indices[f + 2] * 3 + 0], - shape.mesh.positions[shape.mesh.indices[f + 2] * 3 + 1], - shape.mesh.positions[shape.mesh.indices[f + 2] * 3 + 2]); + pt.setValue(attribute.vertices[3 * shape.mesh.indices[f + 2].vertex_index + 0], + attribute.vertices[3 * shape.mesh.indices[f + 2].vertex_index + 1], + attribute.vertices[3 * shape.mesh.indices[f + 2].vertex_index + 2]); convexHull->addPoint(pt * meshScale, false); } @@ -7915,23 +7916,24 @@ bool PhysicsServerCommandProcessor::processLoadSoftBodyCommand(const struct Shar std::string out_found_filename; int out_type; - bool foundFile = UrdfFindMeshFile(fileIO,pathPrefix, relativeFileName, error_message_prefix, &out_found_filename, &out_type); + bool foundFile = UrdfFindMeshFile(fileIO, pathPrefix, relativeFileName, error_message_prefix, &out_found_filename, &out_type); std::vector<tinyobj::shape_t> shapes; - std::string err = tinyobj::LoadObj(shapes, out_found_filename.c_str(),"",fileIO); + tinyobj::attrib_t attribute; + std::string err = tinyobj::LoadObj(attribute, shapes, out_found_filename.c_str(), "", fileIO); if (!shapes.empty()) { const tinyobj::shape_t& shape = shapes[0]; btAlignedObjectArray<btScalar> vertices; btAlignedObjectArray<int> indices; - for (int i = 0; i < shape.mesh.positions.size(); i++) + for (int i = 0; i < attribute.vertices.size(); i++) { - vertices.push_back(shape.mesh.positions[i]); + vertices.push_back(attribute.vertices[i]); } for (int i = 0; i < shape.mesh.indices.size(); i++) { - indices.push_back(shape.mesh.indices[i]); + indices.push_back(shape.mesh.indices[i].vertex_index); } - int numTris = indices.size() / 3; + int numTris = shape.mesh.indices.size() / 3; if (numTris > 0) { btSoftBody* psb = btSoftBodyHelpers::CreateFromTriMesh(m_data->m_dynamicsWorld->getWorldInfo(), &vertices[0], &indices[0], numTris); diff --git a/examples/ThirdPartyLibs/Wavefront/README.md b/examples/ThirdPartyLibs/Wavefront/README.md index 6f911e523..de226acd3 100644 --- a/examples/ThirdPartyLibs/Wavefront/README.md +++ b/examples/ThirdPartyLibs/Wavefront/README.md @@ -38,51 +38,102 @@ Licensed under 2 clause BSD. Usage ----- +Data format +attrib_t contains single and linear array of vertex data(position, normal and texcoord). - std::string inputfile = "cornell_box.obj"; - std::vector<tinyobj::shape_t> shapes; - - std::string err = tinyobj::LoadObj(shapes, inputfile.c_str()); - - if (!err.empty()) { - std::cerr << err << std::endl; - exit(1); - } - - std::cout << "# of shapes : " << shapes.size() << std::endl; - - for (size_t i = 0; i < shapes.size(); i++) { - printf("shape[%ld].name = %s\n", i, shapes[i].name.c_str()); - printf("shape[%ld].indices: %ld\n", i, shapes[i].mesh.indices.size()); - assert((shapes[i].mesh.indices.size() % 3) == 0); - for (size_t f = 0; f < shapes[i].mesh.indices.size(); f++) { - printf(" idx[%ld] = %d\n", f, shapes[i].mesh.indices[f]); - } - - printf("shape[%ld].vertices: %ld\n", i, shapes[i].mesh.positions.size()); - assert((shapes[i].mesh.positions.size() % 3) == 0); - for (size_t v = 0; v < shapes[i].mesh.positions.size() / 3; v++) { - printf(" v[%ld] = (%f, %f, %f)\n", v, - shapes[i].mesh.positions[3*v+0], - shapes[i].mesh.positions[3*v+1], - shapes[i].mesh.positions[3*v+2]); - } - - printf("shape[%ld].material.name = %s\n", i, shapes[i].material.name.c_str()); - printf(" material.Ka = (%f, %f ,%f)\n", shapes[i].material.ambient[0], shapes[i].material.ambient[1], shapes[i].material.ambient[2]); - printf(" material.Kd = (%f, %f ,%f)\n", shapes[i].material.diffuse[0], shapes[i].material.diffuse[1], shapes[i].material.diffuse[2]); - printf(" material.Ks = (%f, %f ,%f)\n", shapes[i].material.specular[0], shapes[i].material.specular[1], shapes[i].material.specular[2]); - printf(" material.Tr = (%f, %f ,%f)\n", shapes[i].material.transmittance[0], shapes[i].material.transmittance[1], shapes[i].material.transmittance[2]); - printf(" material.Ke = (%f, %f ,%f)\n", shapes[i].material.emission[0], shapes[i].material.emission[1], shapes[i].material.emission[2]); - printf(" material.Ns = %f\n", shapes[i].material.shininess); - printf(" material.map_Ka = %s\n", shapes[i].material.ambient_texname.c_str()); - printf(" material.map_Kd = %s\n", shapes[i].material.diffuse_texname.c_str()); - printf(" material.map_Ks = %s\n", shapes[i].material.specular_texname.c_str()); - printf(" material.map_Ns = %s\n", shapes[i].material.normal_texname.c_str()); - std::map<std::string, std::string>::iterator it(shapes[i].material.unknown_parameter.begin()); - std::map<std::string, std::string>::iterator itEnd(shapes[i].material.unknown_parameter.end()); - for (; it != itEnd; it++) { - printf(" material.%s = %s\n", it->first.c_str(), it->second.c_str()); - } - printf("\n"); +attrib_t::vertices => 3 floats per vertex + + v[0] v[1] v[2] v[3] v[n-1] + +-----------+-----------+-----------+-----------+ +-----------+ + | x | y | z | x | y | z | x | y | z | x | y | z | .... | x | y | z | + +-----------+-----------+-----------+-----------+ +-----------+ + +attrib_t::normals => 3 floats per vertex + + n[0] n[1] n[2] n[3] n[n-1] + +-----------+-----------+-----------+-----------+ +-----------+ + | x | y | z | x | y | z | x | y | z | x | y | z | .... | x | y | z | + +-----------+-----------+-----------+-----------+ +-----------+ + +attrib_t::texcoords => 2 floats per vertex + + t[0] t[1] t[2] t[3] t[n-1] + +-----------+-----------+-----------+-----------+ +-----------+ + | u | v | u | v | u | v | u | v | .... | u | v | + +-----------+-----------+-----------+-----------+ +-----------+ + +attrib_t::colors => 3 floats per vertex(vertex color. optional) + + c[0] c[1] c[2] c[3] c[n-1] + +-----------+-----------+-----------+-----------+ +-----------+ + | x | y | z | x | y | z | x | y | z | x | y | z | .... | x | y | z | + +-----------+-----------+-----------+-----------+ +-----------+ + +Each shape_t::mesh_t does not contain vertex data but contains array index to attrib_t. See loader_example.cc for more details. + + +mesh_t::indices => array of vertex indices. + + +----+----+----+----+----+----+----+----+----+----+ +--------+ + | i0 | i1 | i2 | i3 | i4 | i5 | i6 | i7 | i8 | i9 | ... | i(n-1) | + +----+----+----+----+----+----+----+----+----+----+ +--------+ + +Each index has an array index to attrib_t::vertices, attrib_t::normals and attrib_t::texcoords. + +mesh_t::num_face_vertices => array of the number of vertices per face(e.g. 3 = triangle, 4 = quad , 5 or more = N-gons). + + + +---+---+---+ +---+ + | 3 | 4 | 3 | ...... | 3 | + +---+---+---+ +---+ + | | | | + | | | +-----------------------------------------+ + | | | | + | | +------------------------------+ | + | | | | + | +------------------+ | | + | | | | + |/ |/ |/ |/ + + mesh_t::indices + + | face[0] | face[1] | face[2] | | face[n-1] | + +----+----+----+----+----+----+----+----+----+----+ +--------+--------+--------+ + | i0 | i1 | i2 | i3 | i4 | i5 | i6 | i7 | i8 | i9 | ... | i(n-3) | i(n-2) | i(n-1) | + +----+----+----+----+----+----+----+----+----+----+ +--------+--------+--------+ + +```c++ +#define TINYOBJLOADER_IMPLEMENTATION // define this in only *one* .cc +#include "tiny_obj_loader.h" + +std::string inputfile = "cornell_box.obj"; +tinyobj::attrib_t attrib; +std::vector<tinyobj::shape_t> shapes; + +LoadObj(attrib, shapes, inputfile.c_str()); + +// Loop over shapes +for (size_t s = 0; s < shapes.size(); s++) { + // Loop over faces(polygon) + size_t index_offset = 0; + for (size_t f = 0; f < shapes[s].mesh.indices.size(); f++) { + int fv = 3; + // Loop over vertices in the face. + for (size_t v = 0; v < fv; v++) { + // access to vertex + tinyobj::index_t idx = shapes[s].mesh.indices[index_offset + v]; + tinyobj::real_t vx = attrib.vertices[3*idx.vertex_index+0]; + tinyobj::real_t vy = attrib.vertices[3*idx.vertex_index+1]; + tinyobj::real_t vz = attrib.vertices[3*idx.vertex_index+2]; + tinyobj::real_t nx = attrib.normals[3*idx.normal_index+0]; + tinyobj::real_t ny = attrib.normals[3*idx.normal_index+1]; + 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 ty = attrib.texcoords[2*idx.texcoord_index+1]; } + index_offset += fv; + } +} + +``` + diff --git a/examples/ThirdPartyLibs/Wavefront/tiny_obj_loader.cpp b/examples/ThirdPartyLibs/Wavefront/tiny_obj_loader.cpp index 9cd2f2092..d1b9c6362 100644 --- a/examples/ThirdPartyLibs/Wavefront/tiny_obj_loader.cpp +++ b/examples/ThirdPartyLibs/Wavefront/tiny_obj_loader.cpp @@ -70,25 +70,6 @@ std::istream& safeGetline(std::istream& is, std::string& t) } } #endif -struct vertex_index -{ - int v_idx, vt_idx, vn_idx, dummy; -}; -struct MyIndices -{ - int m_offset; - int m_numIndices; -}; - -// for std::map -static inline bool operator<(const vertex_index& a, const vertex_index& b) -{ - if (a.v_idx != b.v_idx) return (a.v_idx < b.v_idx); - if (a.vn_idx != b.vn_idx) return (a.vn_idx < b.vn_idx); - if (a.vt_idx != b.vt_idx) return (a.vt_idx < b.vt_idx); - - return false; -} static inline bool isSpace(const char c) { @@ -101,25 +82,33 @@ static inline bool isNewLine(const char c) } // Make index zero-base, and also support relative index. -static inline int fixIndex(int idx, int n) +static inline bool fixIndex(int idx, int n, int* ret) { - int i; + if (!ret) + { + return false; + } if (idx > 0) { - i = idx - 1; + (*ret) = idx - 1; + return true; } - else if (idx == 0) + + if (idx == 0) { - i = 0; + // zero is not allowed according to the spec. + return false; } - else - { // negative value = relative - i = n + idx; + + if (idx < 0) + { + (*ret) = n + idx; // negative value = relative + return true; } - return i; -} + return false; // never reach here. +} static inline std::string parseString(const char*& token) { std::string s; @@ -156,170 +145,184 @@ static inline void parseFloat3( z = parseFloat(token); } -// Parse triples: i, i/j/k, i//k, i/j -static vertex_index parseTriple( - const char*& token, - int vsize, - int vnsize, - int vtsize) +// Parse triples with index offsets: i, i/j/k, i//k, i/j +static bool parseTriple(const char** token, int vsize, int vnsize, int vtsize, + vertex_index_t* ret) { - vertex_index vi; - vi.vn_idx = -1; - vi.vt_idx = -1; - vi.v_idx = -1; - - vi.v_idx = fixIndex(atoi(token), vsize); - token += strcspn(token, "/ \t\r"); - if (token[0] != '/') + if (!ret) { - return vi; + return false; } - token++; - // i//k - if (token[0] == '/') + vertex_index_t vi(-1); + + if (!fixIndex(atoi((*token)), vsize, &(vi.v_idx))) { - token++; - vi.vn_idx = fixIndex(atoi(token), vnsize); - token += strcspn(token, "/ \t\r"); - return vi; + return false; } - // i/j/k or i/j - vi.vt_idx = fixIndex(atoi(token), vtsize); - token += strcspn(token, "/ \t\r"); - if (token[0] != '/') + (*token) += strcspn((*token), "/ \t\r"); + if ((*token)[0] != '/') { - return vi; + (*ret) = vi; + return true; } + (*token)++; - // i/j/k - token++; // skip '/' - vi.vn_idx = fixIndex(atoi(token), vnsize); - token += strcspn(token, "/ \t\r"); - return vi; -} - -static unsigned int -updateVertex( - std::map<vertex_index, unsigned int>& vertexCache, - std::vector<float>& positions, - std::vector<float>& normals, - std::vector<float>& texcoords, - const std::vector<float>& in_positions, - const std::vector<float>& in_normals, - const std::vector<float>& in_texcoords, - const vertex_index& i) -{ - const std::map<vertex_index, unsigned int>::iterator it = vertexCache.find(i); - - if (it != vertexCache.end()) + // i//k + if ((*token)[0] == '/') { - // found cache - return it->second; + (*token)++; + if (!fixIndex(atoi((*token)), vnsize, &(vi.vn_idx))) + { + return false; + } + (*token) += strcspn((*token), "/ \t\r"); + (*ret) = vi; + return true; } - assert(static_cast<int>(in_positions.size()) > (3 * i.v_idx + 2)); - - positions.push_back(in_positions[3 * i.v_idx + 0]); - positions.push_back(in_positions[3 * i.v_idx + 1]); - positions.push_back(in_positions[3 * i.v_idx + 2]); - - if (i.vn_idx >= 0 && ((3 * i.vn_idx + 2) < in_normals.size())) + // i/j/k or i/j + if (!fixIndex(atoi((*token)), vtsize, &(vi.vt_idx))) { - normals.push_back(in_normals[3 * i.vn_idx + 0]); - normals.push_back(in_normals[3 * i.vn_idx + 1]); - normals.push_back(in_normals[3 * i.vn_idx + 2]); + return false; } - if (i.vt_idx >= 0) + (*token) += strcspn((*token), "/ \t\r"); + if ((*token)[0] != '/') { - int numTexCoords = in_texcoords.size(); - int index0 = 2 * i.vt_idx + 0; - int index1 = 2 * i.vt_idx + 1; + (*ret) = vi; + return true; + } - if (index0 >= 0 && (index0) < numTexCoords) - { - texcoords.push_back(in_texcoords[index0]); - } - if (index1 >= 0 && (index1) < numTexCoords) - { - texcoords.push_back(in_texcoords[index1]); - } + // i/j/k + (*token)++; // skip '/' + if (!fixIndex(atoi((*token)), vnsize, &(vi.vn_idx))) + { + return false; } + (*token) += strcspn((*token), "/ \t\r"); - unsigned int idx = positions.size() / 3 - 1; - vertexCache[i] = idx; + (*ret) = vi; - return idx; + return true; } -static bool -exportFaceGroupToShape( - shape_t& shape, - const std::vector<float>& in_positions, - const std::vector<float>& in_normals, - const std::vector<float>& in_texcoords, - const std::vector<MyIndices>& faceGroup, - const material_t material, - const std::string name, - std::vector<vertex_index>& allIndices) +static bool exportFaceGroupToShape(shape_t* shape, const std::vector<face_t>& face_group, + const material_t material, const std::string& name, + const std::vector<float>& v) { - if (faceGroup.empty()) + if (face_group.empty()) { return false; } + shape->name = name; // Flattened version of vertex data - std::vector<float> positions; - std::vector<float> normals; - std::vector<float> texcoords; - std::map<vertex_index, unsigned int> vertexCache; - std::vector<unsigned int> indices; // Flatten vertices and indices - for (size_t i = 0; i < faceGroup.size(); i++) + for (size_t i = 0; i < face_group.size(); i++) { - const MyIndices& face = faceGroup[i]; + const face_t& face = face_group[i]; + size_t npolys = face.size(); + + if (npolys < 3) + { + // Face must have 3+ vertices. + continue; + } + vertex_index_t i0 = face[0]; + vertex_index_t i1(-1); + vertex_index_t i2 = face[1]; - vertex_index i0 = allIndices[face.m_offset]; - vertex_index i1; - i1.vn_idx = -1; - i1.vt_idx = -1; - i1.v_idx = -1; - vertex_index i2 = allIndices[face.m_offset + 1]; + face_t remainingFace = face; // copy + size_t guess_vert = 0; + vertex_index_t ind[3]; - size_t npolys = face.m_numIndices; //.size(); + // How many iterations can we do without decreasing the remaining + // vertices. + size_t remainingIterations = face.size(); + size_t previousRemainingVertices = remainingFace.size(); + while (remainingFace.size() > 3 && remainingIterations > 0) { - // Polygon -> triangle fan conversion - for (size_t k = 2; k < npolys; k++) + npolys = remainingFace.size(); + if (guess_vert >= npolys) { - i1 = i2; - i2 = allIndices[face.m_offset + k]; - - unsigned int v0 = updateVertex(vertexCache, positions, normals, texcoords, in_positions, in_normals, in_texcoords, i0); - unsigned int v1 = updateVertex(vertexCache, positions, normals, texcoords, in_positions, in_normals, in_texcoords, i1); - unsigned int v2 = updateVertex(vertexCache, positions, normals, texcoords, in_positions, in_normals, in_texcoords, i2); + guess_vert -= npolys; + } - indices.push_back(v0); - indices.push_back(v1); - indices.push_back(v2); + if (previousRemainingVertices != npolys) + { + // The number of remaining vertices decreased. Reset counters. + previousRemainingVertices = npolys; + remainingIterations = npolys; + } + else + { + // We didn't consume a vertex on previous iteration, reduce the + // available iterations. + remainingIterations--; } - } - } - // - // Construct shape. - // - shape.name = name; - shape.mesh.positions.swap(positions); - shape.mesh.normals.swap(normals); - shape.mesh.texcoords.swap(texcoords); - shape.mesh.indices.swap(indices); + for (size_t k = 0; k < 3; k++) + { + ind[k] = remainingFace[(guess_vert + k) % npolys]; + size_t vi = size_t(ind[k].v_idx); + } + // this triangle is an ear + { + index_t idx0, idx1, idx2; + idx0.vertex_index = ind[0].v_idx; + idx0.normal_index = ind[0].vn_idx; + idx0.texcoord_index = ind[0].vt_idx; + idx1.vertex_index = ind[1].v_idx; + idx1.normal_index = ind[1].vn_idx; + idx1.texcoord_index = ind[1].vt_idx; + idx2.vertex_index = ind[2].v_idx; + idx2.normal_index = ind[2].vn_idx; + idx2.texcoord_index = ind[2].vt_idx; + + shape->mesh.indices.push_back(idx0); + shape->mesh.indices.push_back(idx1); + shape->mesh.indices.push_back(idx2); + } - shape.material = material; + // remove v1 from the list + size_t removed_vert_index = (guess_vert + 1) % npolys; + while (removed_vert_index + 1 < npolys) + { + remainingFace[removed_vert_index] = + remainingFace[removed_vert_index + 1]; + removed_vert_index += 1; + } + remainingFace.pop_back(); + } + if (remainingFace.size() == 3) + { + i0 = remainingFace[0]; + i1 = remainingFace[1]; + i2 = remainingFace[2]; + { + index_t idx0, idx1, idx2; + idx0.vertex_index = i0.v_idx; + idx0.normal_index = i0.vn_idx; + idx0.texcoord_index = i0.vt_idx; + idx1.vertex_index = i1.v_idx; + idx1.normal_index = i1.vn_idx; + idx1.texcoord_index = i1.vt_idx; + idx2.vertex_index = i2.v_idx; + idx2.normal_index = i2.vn_idx; + idx2.texcoord_index = i2.vt_idx; + + shape->mesh.indices.push_back(idx0); + shape->mesh.indices.push_back(idx1); + shape->mesh.indices.push_back(idx2); + } + } + } + shape->material = material; return true; } @@ -329,7 +332,6 @@ void InitMaterial(material_t& material) material.ambient_texname = ""; material.diffuse_texname = ""; material.specular_texname = ""; - material.normal_texname = ""; for (int i = 0; i < 3; i++) { material.ambient[i] = 0.f; @@ -369,8 +371,8 @@ std::string LoadMtl( return err.str(); } #else - int fileHandle = fileIO->fileOpen(filepath.c_str(),"r"); - if (fileHandle<0) + int fileHandle = fileIO->fileOpen(filepath.c_str(), "r"); + if (fileHandle < 0) { err << "Cannot open file [" << filepath << "]" << std::endl; return err.str(); @@ -396,7 +398,7 @@ std::string LoadMtl( line = fileIO->readLine(fileHandle, tmpBuf, 1024); if (line) { - linebuf=line; + linebuf = line; } #endif @@ -420,7 +422,7 @@ std::string LoadMtl( // Skip leading space. const char* token = linebuf.c_str(); token += strspn(token, " \t"); - + assert(token); if (token[0] == '\0') continue; // empty line @@ -574,12 +576,13 @@ std::string LoadMtl( } } #ifndef USE_STREAM - while (line); + while (line) + ; #endif // flush last material. material_map.insert(std::pair<std::string, material_t>(material.name, material)); - if (fileHandle>=0) + if (fileHandle >= 0) { fileIO->fileClose(fileHandle); } @@ -588,11 +591,16 @@ std::string LoadMtl( std::string LoadObj( + attrib_t& attrib, std::vector<shape_t>& shapes, const char* filename, const char* mtl_basepath, CommonFileIOInterface* fileIO) { + attrib.vertices.clear(); + attrib.normals.clear(); + attrib.texcoords.clear(); + shapes.clear(); std::string tmp = filename; if (!mtl_basepath) { @@ -604,13 +612,6 @@ LoadObj( mtl_basepath = tmp.c_str(); //fprintf(stderr, "MTL PATH '%s' orig '%s'\n", mtl_basepath, filename); } - - shapes.resize(0); - std::vector<vertex_index> allIndices; - allIndices.reserve(1024 * 1024); - - MyIndices face; - std::stringstream err; #ifdef USE_STREAM std::ifstream ifs(filename); @@ -620,8 +621,8 @@ LoadObj( return err.str(); } #else - int fileHandle = fileIO->fileOpen(filename,"r"); - if (fileHandle<0) + int fileHandle = fileIO->fileOpen(filename, "r"); + if (fileHandle < 0) { err << "Cannot open file [" << filename << "]" << std::endl; return err.str(); @@ -629,16 +630,15 @@ LoadObj( #endif std::vector<float> v; - v.reserve(1024 * 1024); std::vector<float> vn; - vn.reserve(1024 * 1024); std::vector<float> vt; - vt.reserve(1024 * 1024); - //std::vector<std::vector<vertex_index> > faceGroup; - std::vector<MyIndices> faceGroup; - faceGroup.reserve(1024 * 1024); std::string name; + int greatest_v_idx = -1; + int greatest_vn_idx = -1; + int greatest_vt_idx = -1; + + std::vector<face_t> faceGroup; // material std::map<std::string, material_t> material_map; material_t material; @@ -664,10 +664,9 @@ LoadObj( line = fileIO->readLine(fileHandle, tmpBuf, 1024); if (line) { - linebuf=line; + linebuf = line; } #endif - // Trim newline '\r\n' or '\r' if (linebuf.size() > 0) { @@ -734,23 +733,34 @@ LoadObj( token += 2; token += strspn(token, " \t"); - face.m_offset = allIndices.size(); - face.m_numIndices = 0; + face_t face; + + face.reserve(3); while (!isNewLine(token[0])) { - vertex_index vi = parseTriple(token, v.size() / 3, vn.size() / 3, vt.size() / 2); - allIndices.push_back(vi); - face.m_numIndices++; - int n = strspn(token, " \t\r"); + vertex_index_t vi; + if (!parseTriple(&token, static_cast<int>(v.size() / 3), + static_cast<int>(vn.size() / 3), + static_cast<int>(vt.size() / 2), &vi)) + { + err << "Failed parse `f' line(e.g. zero value for face index."; + return err.str(); + } + + greatest_v_idx = greatest_v_idx > vi.v_idx ? greatest_v_idx : vi.v_idx; + greatest_vn_idx = + greatest_vn_idx > vi.vn_idx ? greatest_vn_idx : vi.vn_idx; + greatest_vt_idx = + greatest_vt_idx > vi.vt_idx ? greatest_vt_idx : vi.vt_idx; + + face.push_back(vi); + size_t n = strspn(token, " \t\r"); token += n; } - faceGroup.push_back(face); - continue; } - // use mtl if ((0 == strncmp(token, "usemtl", 6)) && isSpace((token[6]))) { @@ -777,10 +787,10 @@ LoadObj( token += 7; sscanf(token, "%s", namebuf); - std::string err_mtl = LoadMtl(material_map, namebuf, mtl_basepath,fileIO); + std::string err_mtl = LoadMtl(material_map, namebuf, mtl_basepath, fileIO); if (!err_mtl.empty()) { - //faceGroup.resize(0); // for safety + //face_group.resize(0); // for safety //return err_mtl; } continue; @@ -791,7 +801,7 @@ LoadObj( { // flush previous face group. shape_t shape; - bool ret = exportFaceGroupToShape(shape, v, vn, vt, faceGroup, material, name, allIndices); + bool ret = exportFaceGroupToShape(&shape, faceGroup, material, name, v); if (ret) { shapes.push_back(shape); @@ -827,7 +837,7 @@ LoadObj( { // flush previous face group. shape_t shape; - bool ret = exportFaceGroupToShape(shape, v, vn, vt, faceGroup, material, name, allIndices); + bool ret = exportFaceGroupToShape(&shape, faceGroup, material, name, v); if (ret) { shapes.push_back(shape); @@ -847,18 +857,23 @@ LoadObj( // Ignore unknown command. } #ifndef USE_STREAM - while (line); + while (line) + ; #endif shape_t shape; - bool ret = exportFaceGroupToShape(shape, v, vn, vt, faceGroup, material, name, allIndices); + bool ret = exportFaceGroupToShape(&shape, faceGroup, material, name, v); if (ret) { shapes.push_back(shape); } faceGroup.resize(0); // for safety - if (fileHandle>=0) + attrib.vertices.swap(v); + attrib.normals.swap(vn); + attrib.texcoords.swap(vt); + + if (fileHandle >= 0) { fileIO->fileClose(fileHandle); } diff --git a/examples/ThirdPartyLibs/Wavefront/tiny_obj_loader.h b/examples/ThirdPartyLibs/Wavefront/tiny_obj_loader.h index 0319b7c0d..1fb15b34a 100644 --- a/examples/ThirdPartyLibs/Wavefront/tiny_obj_loader.h +++ b/examples/ThirdPartyLibs/Wavefront/tiny_obj_loader.h @@ -14,6 +14,17 @@ struct CommonFileIOInterface; namespace tinyobj { +struct vertex_index_t +{ + int v_idx, vt_idx, vn_idx; + vertex_index_t() : v_idx(-1), vt_idx(-1), vn_idx(-1) {} + explicit vertex_index_t(int idx) : v_idx(idx), vt_idx(idx), vn_idx(idx) {} + vertex_index_t(int vidx, int vtidx, int vnidx) + : v_idx(vidx), vt_idx(vtidx), vn_idx(vnidx) {} +}; + +typedef std::vector<vertex_index_t> face_t; + typedef struct { std::string name; @@ -24,21 +35,27 @@ typedef struct float transmittance[3]; float emission[3]; float shininess; - float transparency; + float transparency; // 1 == opaque; 0 == fully transparent - std::string ambient_texname; - std::string diffuse_texname; - std::string specular_texname; + std::string ambient_texname; // map_Ka + std::string diffuse_texname; // map_Kd + std::string specular_texname; // map_Ks std::string normal_texname; std::map<std::string, std::string> unknown_parameter; } material_t; +// Index struct to support different indices for vtx/normal/texcoord. +// -1 means not used. typedef struct { - std::vector<float> positions; - std::vector<float> normals; - std::vector<float> texcoords; - std::vector<unsigned int> indices; + int vertex_index; + int normal_index; + int texcoord_index; +} index_t; + +typedef struct +{ + std::vector<index_t> indices; } mesh_t; typedef struct @@ -48,6 +65,14 @@ typedef struct mesh_t mesh; } shape_t; +// Vertex attributes +struct attrib_t +{ + std::vector<float> vertices; // 'v'(xyz) + std::vector<float> normals; // 'vn' + std::vector<float> texcoords; // 'vt'(uv) + attrib_t() {} +}; /// Loads .obj from a file. /// 'shapes' will be filled with parsed shape data /// The function returns error string. @@ -55,12 +80,14 @@ typedef struct /// 'mtl_basepath' is optional, and used for base path for .mtl file. #ifdef USE_STREAM std::string LoadObj( + attrib_t& attrib, std::vector<shape_t>& shapes, // [output] const char* filename, const char* mtl_basepath = NULL); #else std::string LoadObj( + attrib_t& attrib, std::vector<shape_t>& shapes, const char* filename, const char* mtl_basepath, |