40 #ifndef TESSERACT_SCENE_GRAPH_MESH_PARSER_H
41 #define TESSERACT_SCENE_GRAPH_MESH_PARSER_H
45 #include <assimp/scene.h>
46 #include <assimp/Importer.hpp>
47 #include <assimp/postprocess.h>
49 #ifdef TESSERACT_ASSIMP_USE_PBRMATERIAL
50 #include <assimp/pbrmaterial.h>
53 #include <console_bridge/console.h>
59 #include <boost/filesystem/path.hpp>
76 const aiMatrix4x4& parent_transform,
77 const Eigen::Vector3d& scale,
81 bool material_and_texture)
83 std::vector<std::shared_ptr<T>> meshes;
84 meshes.reserve(node->mNumMeshes);
86 aiMatrix4x4 transform = parent_transform;
87 transform *= node->mTransformation;
88 for (
unsigned int j = 0; j < node->mNumMeshes; ++j)
90 auto vertices = std::make_shared<tesseract_common::VectorVector3d>();
91 auto triangles = std::make_shared<Eigen::VectorXi>();
92 std::shared_ptr<tesseract_common::VectorVector3d> vertex_normals =
nullptr;
93 std::shared_ptr<tesseract_common::VectorVector4d> vertex_colors =
nullptr;
95 std::shared_ptr<std::vector<MeshTexture::Ptr>> textures =
nullptr;
97 const aiMesh* a = scene->mMeshes[node->mMeshes[j]];
98 vertices->reserve(a->mNumVertices);
99 for (
unsigned int i = 0; i < a->mNumVertices; ++i)
101 aiVector3D v = transform * a->mVertices[i];
102 vertices->emplace_back(
static_cast<double>(v.x) * scale(0),
103 static_cast<double>(v.y) * scale(1),
104 static_cast<double>(v.z) * scale(2));
107 long triangle_count = 0;
108 std::vector<int> local_triangles;
109 local_triangles.reserve(a->mNumFaces);
110 for (
unsigned int i = 0; i < a->mNumFaces; ++i)
112 if (a->mFaces[i].mNumIndices >= 3)
115 local_triangles.push_back(
static_cast<int>(a->mFaces[i].mNumIndices));
116 for (
size_t k = 0; k < a->mFaces[i].mNumIndices; ++k)
117 local_triangles.push_back(
static_cast<int>(a->mFaces[i].mIndices[k]));
121 CONSOLE_BRIDGE_logDebug(
"Mesh had a face with less than three vertices: %s", resource->getUrl().c_str());
125 triangles->resize(
static_cast<long>(local_triangles.size()));
126 for (
long i = 0; i < triangles->size(); ++i)
127 (*triangles)[i] = local_triangles[
static_cast<size_t>(i)];
129 if (normals && a->HasNormals())
131 vertex_normals = std::make_shared<tesseract_common::VectorVector3d>();
132 vertex_normals->reserve(a->mNumVertices);
133 for (
unsigned int i = 0; i < a->mNumVertices; ++i)
135 aiVector3D v = transform * a->mNormals[i];
136 vertex_normals->emplace_back(
static_cast<double>(v.x) * scale(0),
137 static_cast<double>(v.y) * scale(1),
138 static_cast<double>(v.z) * scale(2));
142 if (vertex_colors && a->HasVertexColors(0))
144 vertex_colors = std::make_shared<tesseract_common::VectorVector4d>();
145 vertex_colors->reserve(a->mNumVertices);
146 for (
unsigned int i = 0; i < a->mNumVertices; ++i)
148 aiColor4D v = a->mColors[0][i];
149 vertex_colors->emplace_back(
150 static_cast<double>(v.r),
static_cast<double>(v.g),
static_cast<double>(v.b),
static_cast<double>(v.a));
154 if (material_and_texture)
156 aiMaterial* mat = scene->mMaterials[a->mMaterialIndex];
158 Eigen::Vector4d base_color = Eigen::Vector4d::Zero();
159 double metallic = 0.0;
160 double roughness = 0.5;
161 Eigen::Vector4d emissive = Eigen::Vector4d::Zero();
163 aiColor4D pbr_base_color;
164 #ifdef TESSERACT_ASSIMP_USE_PBRMATERIAL
165 if (mat->Get(AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_FACTOR, pbr_base_color) == AI_SUCCESS)
168 base_color = Eigen::Vector4d(pbr_base_color.r, pbr_base_color.g, pbr_base_color.b, pbr_base_color.a);
169 float metallicFactor{ 0 };
170 if (mat->Get(AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLIC_FACTOR, metallicFactor) == AI_SUCCESS)
172 metallic = metallicFactor;
174 float roughnessFactor{ 0.5 };
175 if (mat->Get(AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_ROUGHNESS_FACTOR, roughnessFactor) == AI_SUCCESS)
177 roughness = roughnessFactor;
179 aiColor4D pbr_emissive_color;
180 if (mat->Get(AI_MATKEY_COLOR_EMISSIVE, pbr_emissive_color) == AI_SUCCESS)
183 Eigen::Vector4d(pbr_emissive_color.r, pbr_emissive_color.g, pbr_emissive_color.b, pbr_emissive_color.a);
190 aiColor4D diffuse_color;
191 if (mat->Get(AI_MATKEY_COLOR_DIFFUSE, diffuse_color) == AI_SUCCESS)
193 base_color = Eigen::Vector4d(diffuse_color.r, diffuse_color.g, diffuse_color.b, diffuse_color.a);
196 aiColor4D emissive_color;
197 if (mat->Get(AI_MATKEY_COLOR_EMISSIVE, emissive_color) == AI_SUCCESS)
199 emissive = Eigen::Vector4d(emissive_color.r, emissive_color.g, emissive_color.b, emissive_color.a);
203 material = std::make_shared<MeshMaterial>(base_color, metallic, roughness, emissive);
205 for (
unsigned int i = 0; i < a->GetNumUVChannels(); i++)
207 if (a->HasTextureCoords(i))
210 aiTextureMapping mapping{ aiTextureMapping_OTHER };
211 unsigned int uvIndex{ 0 };
212 if (mat->GetTexture(aiTextureType_DIFFUSE, i, &texName, &mapping, &uvIndex) == AI_SUCCESS)
217 const char* texNamec = texName.C_Str();
218 if (
'*' == *texNamec)
220 int tex_index = std::atoi(texNamec + 1);
221 if (0 > tex_index || scene->mNumTextures <=
static_cast<unsigned>(tex_index))
223 auto* texture_data = scene->mTextures[tex_index];
225 std::string file_type = texture_data->achFormatHint;
226 if (file_type ==
"jpg" || file_type ==
"png")
228 texture_image = std::make_shared<tesseract_common::BytesResource>(
229 "data://", (
const uint8_t*)texture_data->pcData, texture_data->mWidth);
243 std::string texName_str(texName.C_Str());
244 auto tex_resource = resource->locateResource(texName_str);
249 texture_image = tex_resource;
251 aiVector3D* tex_coords = a->mTextureCoords[i];
252 for (
unsigned int j = 0; j < a->mNumVertices; ++j)
254 aiVector3D v = tex_coords[j];
255 uvs.emplace_back(
static_cast<double>(v.x),
static_cast<double>(v.y));
257 auto tex = std::make_shared<MeshTexture>(
258 texture_image, std::make_shared<tesseract_common::VectorVector2d>(std::move(uvs)));
261 textures = std::make_shared<std::vector<MeshTexture::Ptr>>();
263 textures->push_back(tex);
270 meshes.push_back(std::make_shared<T>(vertices,
272 static_cast<int>(triangle_count),
281 for (
unsigned int n = 0; n < node->mNumChildren; ++n)
283 std::vector<std::shared_ptr<T>> child_meshes = extractMeshData<T>(
284 scene, node->mChildren[n], transform, scale, resource, normals, vertex_colors, material_and_texture);
285 meshes.insert(meshes.end(), child_meshes.begin(), child_meshes.end());
302 const Eigen::Vector3d& scale,
306 bool material_and_texture)
308 if (!scene->HasMeshes())
310 CONSOLE_BRIDGE_logWarn(
"Assimp reports scene in %s has no meshes", resource->getUrl().c_str());
311 return std::vector<std::shared_ptr<T>>();
313 std::vector<std::shared_ptr<T>> meshes = extractMeshData<T>(
314 scene, scene->mRootNode, aiMatrix4x4(), scale, resource, normals, vertex_colors, material_and_texture);
317 CONSOLE_BRIDGE_logWarn(
"There are no meshes in the scene %s", resource->getUrl().c_str());
318 return std::vector<std::shared_ptr<T>>();
339 const Eigen::Vector3d& scale = Eigen::Vector3d(1, 1, 1),
340 bool triangulate =
false,
341 bool flatten =
false,
342 bool normals =
false,
343 bool vertex_colors =
false,
344 bool material_and_texture =
false)
347 Assimp::Importer importer;
352 unsigned int ai_config_pp_rcv_flags = aiComponent_TANGENTS_AND_BITANGENTS | aiComponent_BONEWEIGHTS |
353 aiComponent_ANIMATIONS | aiComponent_LIGHTS | aiComponent_CAMERAS;
356 ai_config_pp_rcv_flags |= aiComponent_NORMALS;
360 ai_config_pp_rcv_flags |= aiComponent_COLORS;
362 if (!material_and_texture)
364 ai_config_pp_rcv_flags |= aiComponent_TEXCOORDS | aiComponent_TEXTURES | aiComponent_MATERIALS;
366 importer.SetPropertyInteger(AI_CONFIG_PP_RVC_FLAGS, (
int)ai_config_pp_rcv_flags);
369 const aiScene* scene =
nullptr;
371 scene = importer.ReadFile(path.c_str(),
372 aiProcess_Triangulate | aiProcess_JoinIdenticalVertices | aiProcess_SortByPType |
373 aiProcess_RemoveComponent);
375 scene = importer.ReadFile(path.c_str(),
376 aiProcess_JoinIdenticalVertices | aiProcess_SortByPType | aiProcess_RemoveComponent);
380 CONSOLE_BRIDGE_logError(
"Could not load mesh from \"%s\": %s", path.c_str(), importer.GetErrorString());
381 return std::vector<std::shared_ptr<T>>();
390 scene->mRootNode->mTransformation = aiMatrix4x4();
396 importer.ApplyPostProcessing(aiProcess_OptimizeMeshes | aiProcess_OptimizeGraph);
400 importer.ApplyPostProcessing(aiProcess_OptimizeGraph);
403 return createMeshFromAsset<T>(scene, scale,
nullptr, normals, vertex_colors, material_and_texture);
421 const Eigen::Vector3d& scale = Eigen::Vector3d(1, 1, 1),
422 bool triangulate =
false,
423 bool flatten =
false,
424 bool normals =
false,
425 bool vertex_colors =
false,
426 bool material_and_texture =
false)
429 return std::vector<std::shared_ptr<T>>();
431 const char* hint =
nullptr;
432 std::string hint_storage;
434 std::string resource_url = resource->getUrl();
435 std::regex hint_re(
"^.*\\.([A-Za-z0-9]{1,8})$");
436 std::smatch hint_match;
437 if (std::regex_match(resource_url, hint_match, hint_re))
439 if (hint_match.size() == 2)
441 hint_storage = hint_match[1].str();
442 hint = hint_storage.c_str();
446 std::vector<uint8_t> data = resource->getResourceContents();
449 if (resource->isFile())
450 return createMeshFromPath<T>(
451 resource->getFilePath(), scale, triangulate, flatten, normals, vertex_colors, material_and_texture);
453 return std::vector<std::shared_ptr<T>>();
457 Assimp::Importer importer;
462 unsigned int ai_config_pp_rcv_flags = aiComponent_TANGENTS_AND_BITANGENTS | aiComponent_BONEWEIGHTS |
463 aiComponent_ANIMATIONS | aiComponent_LIGHTS | aiComponent_CAMERAS;
466 ai_config_pp_rcv_flags |= aiComponent_NORMALS;
470 ai_config_pp_rcv_flags |= aiComponent_COLORS;
472 if (!material_and_texture)
474 ai_config_pp_rcv_flags |= aiComponent_TEXCOORDS | aiComponent_TEXTURES | aiComponent_MATERIALS;
476 importer.SetPropertyInteger(AI_CONFIG_PP_RVC_FLAGS, (
int)ai_config_pp_rcv_flags);
479 const aiScene* scene =
nullptr;
481 scene = importer.ReadFileFromMemory(data.data(),
483 aiProcess_Triangulate | aiProcess_JoinIdenticalVertices |
484 aiProcess_SortByPType | aiProcess_RemoveComponent,
488 importer.ReadFileFromMemory(data.data(),
490 aiProcess_JoinIdenticalVertices | aiProcess_SortByPType | aiProcess_RemoveComponent,
495 CONSOLE_BRIDGE_logError(
496 "Could not load mesh from \"%s\": %s", resource->getUrl().c_str(), importer.GetErrorString());
497 return std::vector<std::shared_ptr<T>>();
505 scene->mRootNode->mTransformation = aiMatrix4x4();
511 importer.ApplyPostProcessing(aiProcess_OptimizeMeshes | aiProcess_OptimizeGraph);
515 importer.ApplyPostProcessing(aiProcess_OptimizeGraph);
518 return createMeshFromAsset<T>(scene, scale, resource, normals, vertex_colors, material_and_texture);
536 template <
typename T>
538 const uint8_t* bytes,
540 const Eigen::Vector3d& scale = Eigen::Vector3d(1, 1, 1),
541 bool triangulate =
false,
542 bool flatten =
false,
543 bool normals =
false,
544 bool vertex_colors =
false,
545 bool material_and_texture =
false)
547 std::shared_ptr<tesseract_common::Resource> resource =
548 std::make_shared<tesseract_common::BytesResource>(url, bytes, bytes_len);
549 return tesseract_geometry::createMeshFromResource<T>(
550 resource, scale, triangulate, flatten, normals, vertex_colors, material_and_texture);