AssimpImport.cpp
Go to the documentation of this file.
00001 /*************************************************************************\
00002    Copyright 2014 Institute of Industrial and Control Engineering (IOC)
00003                 Universitat Politecnica de Catalunya
00004                 BarcelonaTech
00005    All Rights Reserved.
00006 
00007    This program is free software; you can redistribute it and/or modify
00008    it under the terms of the GNU General Public License as published by
00009    the Free Software Foundation; either version 2 of the License, or
00010    (at your option) any later version.
00011 
00012    This program is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015    GNU General Public License for more details.
00016 
00017    You should have received a copy of the GNU General Public License
00018    along with this program; if not, write to the
00019    Free Software Foundation, Inc.,
00020    59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00021 \*************************************************************************/
00022 
00023 /* Author: Nestor Garcia Hidalgo, extended by Jennifer Buehler */
00024 
00025 #include <ros/ros.h>
00026 #include <urdf2inventor/AssimpImport.h>
00027 
00028 #include <assimp/Importer.hpp>
00029 #include <assimp/importerdesc.h>
00030 #include <assimp/postprocess.h>
00031 
00032 #include <boost/filesystem.hpp>
00033 
00034 #include <Inventor/nodes/SoTransform.h>
00035 #include <Inventor/nodes/SoIndexedPointSet.h>
00036 #include <Inventor/nodes/SoIndexedLineSet.h>
00037 #include <Inventor/nodes/SoIndexedTriangleStripSet.h>
00038 #include <Inventor/nodes/SoMaterial.h>
00039 #include <Inventor/nodes/SoTexture2.h>
00040 
00041 #include <iostream>
00042 #include <sstream>
00043 
00044 
00045 SbName getName(const std::string &name)
00046 {
00047     std::stringstream strs;
00048     for (std::string::const_iterator it(name.begin());
00049             it != name.end(); ++it)
00050     {
00051         if (it == name.begin())
00052         {
00053             if (SbName::isBaseNameStartChar(*it) == TRUE)
00054             {
00055                 strs << *it;
00056             }
00057             else if (SbName::isBaseNameChar(*it) == TRUE)
00058             {
00059                 strs << "_" << *it;
00060             }
00061         }
00062         else
00063         {
00064             if (SbName::isBaseNameChar(*it) == TRUE)
00065             {
00066                 strs << *it;
00067             }
00068             else
00069             {
00070                 strs << "_";
00071             }
00072         }
00073     }
00074 
00075     return SbName(strs.str().c_str());
00076 }
00077 
00078 void printTransform(const aiMatrix4x4 &matrix)
00079 {
00080     aiVector3D scaling;
00081     aiQuaternion rotation;
00082     aiVector3D position;
00083     matrix.Decompose(scaling, rotation, position);
00084 
00085     SoTransform *transform(new SoTransform);
00086     transform->translation.setValue(position.x,
00087                                     position.y,
00088                                     position.z);
00089     transform->rotation.setValue(rotation.x,
00090                                  rotation.y,
00091                                  rotation.z,
00092                                  rotation.w);
00093     transform->scaleFactor.setValue(scaling.x,
00094                                     scaling.y,
00095                                     scaling.z);
00096 
00097     ROS_INFO("Rotation: %lf %lf %lf %lf, scale = %lf %lf %lf", rotation.x,
00098              rotation.y,
00099              rotation.z,
00100              rotation.w,
00101              scaling.x,
00102              scaling.y,
00103              scaling.z);
00104 }
00105 
00106 
00107 
00108 SoTransform *getTransform(const aiMatrix4x4 &matrix)
00109 {
00110     aiVector3D scaling;
00111     aiQuaternion rotation;
00112     aiVector3D position;
00113     matrix.Decompose(scaling, rotation, position);
00114 
00115     SoTransform *transform(new SoTransform);
00116     transform->translation.setValue(position.x,
00117                                     position.y,
00118                                     position.z);
00119     transform->rotation.setValue(rotation.x,
00120                                  rotation.y,
00121                                  rotation.z,
00122                                  rotation.w);
00123     transform->scaleFactor.setValue(scaling.x,
00124                                     scaling.y,
00125                                     scaling.z);
00126 
00127     return transform;
00128 }
00129 
00130 
00131 SoTexture2 *getTexture(const aiTexture *const texture)
00132 {
00133     if (texture->mHeight == 0)  //Compressed texture
00134     {
00135         std::cout << "Found a compressed embedded texture. "
00136                   << "It will be ignored." << std::endl;
00140         return NULL;
00141     }
00142     else    //Uncompressed texture
00143     {
00144         unsigned char pixels[texture->mWidth * texture->mHeight * 4];
00145         for (std::size_t i(0); i < texture->mWidth; ++i)
00146         {
00147             for (std::size_t j(0); j < texture->mHeight; ++j)
00148             {
00149                 pixels[4 * (texture->mHeight * i + j) + 0] = texture->pcData[texture->mHeight * i + j].r;
00150                 pixels[4 * (texture->mHeight * i + j) + 1] = texture->pcData[texture->mHeight * i + j].g;
00151                 pixels[4 * (texture->mHeight * i + j) + 2] = texture->pcData[texture->mHeight * i + j].b;
00152                 pixels[4 * (texture->mHeight * i + j) + 3] = texture->pcData[texture->mHeight * i + j].a;
00153             }
00154         }
00155         SoTexture2 *soTexture(new SoTexture2);
00156         soTexture->image.setValue(SbVec2s(texture->mWidth, texture->mHeight), 4, pixels);
00157 
00158         return soTexture;
00159     }
00160 }
00161 
00162 
00163 SoTexture *getTexture(const aiMaterial *const material, const std::string &sceneDir)
00164 {
00178 
00179     //Check if there is a texture
00180     unsigned int numTextures(material->GetTextureCount(aiTextureType_DIFFUSE));
00181     if (numTextures == 0) return NULL;
00182     if (numTextures > 1)
00183     {
00184         std::cout << "Found a material with " << numTextures
00185                   << " textures. Only the first one will be used." << std::endl;
00186     }
00187 
00188     //Get path
00189     aiString path;
00190     if (material->Get(AI_MATKEY_TEXTURE(aiTextureType_DIFFUSE, 0), path) != aiReturn_SUCCESS)
00191     {
00192         std::cout << "Error while getting the texture path. "
00193                   << "Texture will be ignored." << std::endl;
00194         return NULL;
00195     }
00196 
00197     //Check mapping
00199     int mapping;
00200     if (material->Get(AI_MATKEY_MAPPING(aiTextureType_DIFFUSE, 0), mapping) == aiReturn_SUCCESS)
00201     {
00202         if (mapping != aiTextureMapping_UV)
00203         {
00204             std::cout << "Invalid texture mapping. Texture will be ignored." << std::endl;
00205             return NULL;
00206         }
00207     }
00208 
00209     //Check UV transform
00210     aiUVTransform transform;
00211     if (material->Get(AI_MATKEY_UVTRANSFORM(aiTextureType_DIFFUSE, 0),
00212                       transform) == aiReturn_SUCCESS)
00213     {
00214         std::cout << "Error I did not expect a texture transform. " <<
00215                   "Property will be ignored." << std::endl;
00216     }
00217 
00218     SoTexture2 *texture(new SoTexture2);
00219 
00220     //Load image
00221     boost::filesystem::path relFilePath(path.C_Str());
00222     boost::filesystem::path absPath = relFilePath;
00223     if (relFilePath.is_relative())
00224     {
00225         boost::filesystem::path sceneDirPath(sceneDir);
00226         absPath = boost::filesystem::canonical(relFilePath, sceneDirPath);
00227         // ROS_INFO_STREAM("Absolute file path: "<<absPath.string());
00228     }
00229 
00230     // ROS_INFO_STREAM("Clean absolute file path: "<<absPath.string());
00231     std::string filename = absPath.string();
00232     // ROS_INFO_STREAM("Filename: "<<filename);
00233 
00234     texture->filename.setValue(filename.c_str());
00235     // texture->setName(getName(boost::filesystem::path(filename).filename().string()));
00236     texture->setName(getName(filename));
00237 
00238     //Set model
00239     texture->model.setValue(SoTexture2::DECAL);
00240 
00241     //Set wrap
00242     int mapMode;
00243     if (material->Get(AI_MATKEY_MAPPINGMODE_U(aiTextureType_DIFFUSE, 0),
00244                       mapMode) == aiReturn_SUCCESS)
00245     {
00246         switch (mapMode)
00247         {
00248         case aiTextureMapMode_Wrap:
00249             texture->wrapS.setValue(SoTexture2::REPEAT);
00250             break;
00251         case aiTextureMapMode_Clamp:
00252             texture->wrapS.setValue(SoTexture2::CLAMP);
00253             break;
00254         case aiTextureMapMode_Decal:
00255         case aiTextureMapMode_Mirror:
00256         default:
00257             std::cout << "Wrong S texture mapping mode. "
00258                       << "Property will be ignored." << std::endl;
00259             break;
00260         }
00261     }
00262     if (material->Get(AI_MATKEY_MAPPINGMODE_V(aiTextureType_DIFFUSE, 0),
00263                       mapMode) == aiReturn_SUCCESS)
00264     {
00265         switch (mapMode)
00266         {
00267         case aiTextureMapMode_Wrap:
00268             texture->wrapT.setValue(SoTexture2::REPEAT);
00269             break;
00270         case aiTextureMapMode_Clamp:
00271             texture->wrapT.setValue(SoTexture2::CLAMP);
00272             break;
00273         case aiTextureMapMode_Decal:
00274         case aiTextureMapMode_Mirror:
00275         default:
00276             std::cout << "Wrong T texture mapping mode. "
00277                       << "Property will be ignored." << std::endl;
00278             break;
00279         }
00280     }
00281 
00282     return texture;
00283 }
00284 
00285 SoMaterial *cloneMaterial(const SoMaterial& m)
00286 {
00287     SoMaterial * ret = new SoMaterial();
00288     ret->ambientColor = m.ambientColor;
00289     ret->diffuseColor = m.diffuseColor;
00290     ret->emissiveColor = m.emissiveColor;
00291     ret->shininess = m.shininess;
00292     ret->specularColor = m.specularColor;
00293     ret->transparency = m.transparency;
00294     return ret;
00295 }
00296 
00297 SoMaterial *getMaterial(const aiMaterial *const material)
00298 {
00299     SoMaterial *soMat(new SoMaterial);
00300 
00301     aiString name;
00302     aiColor3D color;
00303     float value;
00304 
00305     //Add name
00306     if (material->Get(AI_MATKEY_NAME, name) == aiReturn_SUCCESS)
00307     {
00308         soMat->setName(getName(name.C_Str()));
00309     }
00310 
00311     //Add diffuse color
00312     if (material->Get(AI_MATKEY_COLOR_DIFFUSE, color) == aiReturn_SUCCESS)
00313     {
00314         soMat->diffuseColor.setValue(color.r,
00315                                      color.g,
00316                                      color.b);
00317     }
00318 
00319     //Add specular color
00320     if (material->Get(AI_MATKEY_COLOR_SPECULAR, color) == aiReturn_SUCCESS)
00321     {
00322         soMat->specularColor.setValue(color.r,
00323                                       color.g,
00324                                       color.b);
00325     }
00326 
00327     //Add ambient color
00328     if (material->Get(AI_MATKEY_COLOR_AMBIENT, color) == aiReturn_SUCCESS)
00329     {
00330         soMat->ambientColor.setValue(color.r,
00331                                      color.g,
00332                                      color.b);
00333     }
00334 
00335     //Add emissive color
00336     if (material->Get(AI_MATKEY_COLOR_EMISSIVE, color) == aiReturn_SUCCESS)
00337     {
00338         soMat->emissiveColor.setValue(color.r,
00339                                       color.g,
00340                                       color.b);
00341     }
00342 
00343     //Add transparency
00344     if (material->Get(AI_MATKEY_OPACITY, value) == aiReturn_SUCCESS)
00345     {
00346         soMat->transparency.setValue(1.0 - value);
00347     }
00348 
00349     //Add shininess
00350     if (material->Get(AI_MATKEY_SHININESS_STRENGTH, value) == aiReturn_SUCCESS)
00351     {
00352         soMat->shininess.setValue(value);
00353     }
00354 
00355     return soMat;
00356 }
00357 
00358 
00359 SoIndexedShape *getShape(const aiMesh *const mesh)
00360 {
00361     if (!mesh->HasPositions() || !mesh->HasFaces()) return NULL; //Mesh is empty
00362 
00363     //Get shape type
00364     SoIndexedShape *shape;
00365     std::size_t numIndices;
00366     switch (mesh->mPrimitiveTypes)
00367     {
00368     case aiPrimitiveType_POINT:
00369         shape = new SoIndexedPointSet;
00370         numIndices = 1;
00371         break;
00372     case aiPrimitiveType_LINE:
00373         shape = new SoIndexedLineSet;
00374         numIndices = 2;
00375         break;
00376     case aiPrimitiveType_TRIANGLE:
00377         shape = new SoIndexedTriangleStripSet;
00378         numIndices = 3;
00379         break;
00380     default:
00381         //Or the faces are polygons or the shape contains more than one primitive
00382         //This should have been solved by the triangulate and sort-by-type post processing steps
00383         std::cout << "Wrong primitive type. Mesh will be ignored." << std::endl;
00384         return NULL;
00385         break;
00386     }
00387 
00388     //Set name
00389     shape->setName(getName(mesh->mName.C_Str()));
00390 
00391     SoVertexProperty *vertexProperty(new SoVertexProperty);
00392     shape->vertexProperty.setValue(vertexProperty);
00393 
00394     //Set vertices
00395     float vertices[mesh->mNumVertices][3];
00396     for (std::size_t i(0); i < mesh->mNumVertices; ++i)
00397     {
00398         vertices[i][0] = mesh->mVertices[i].x;
00399         vertices[i][1] = mesh->mVertices[i].y;
00400         vertices[i][2] = mesh->mVertices[i].z;
00401     }
00402     vertexProperty->vertex.setValues(0, mesh->mNumVertices, vertices);
00403 
00404     if (mesh->HasNormals())
00405     {
00406         //Set normals
00407         float normals[mesh->mNumVertices][3];
00408         for (std::size_t i(0); i < mesh->mNumVertices; ++i)
00409         {
00410             normals[i][0] = mesh->mNormals[i].x;
00411             normals[i][1] = mesh->mNormals[i].y;
00412             normals[i][2] = mesh->mNormals[i].z;
00413         }
00414         vertexProperty->normal.setValues(0, mesh->mNumVertices, normals);
00415     }
00416 
00417     if (mesh->GetNumColorChannels() > 0)
00418     {
00419         std::cout << "Mesh has " << mesh->GetNumColorChannels()
00420                   << " vertex color channels. Property will be ignored." << std::endl;
00421     }
00422 
00423     if (mesh->GetNumUVChannels() > 0)
00424     {
00425         if (mesh->GetNumUVChannels() > 1)
00426         {
00427             std::cout << "Mesh has " << mesh->GetNumUVChannels()
00428                       << " UV channels. Only the first one will be used." << std::endl;
00446         }
00447 
00448         //Set texture coordinates
00449         if (mesh->mNumUVComponents[0] == 2)
00450         {
00451             float texCoords[mesh->mNumVertices][2];
00452             for (std::size_t i(0); i < mesh->mNumVertices; ++i)
00453             {
00454                 texCoords[i][0] = mesh->mTextureCoords[0][i].x;
00455                 texCoords[i][1] = mesh->mTextureCoords[0][i].y;
00456             }
00457             vertexProperty->texCoord.setValues(0, mesh->mNumVertices, texCoords);
00458         }
00459         else if (mesh->mNumUVComponents[0] == 3)
00460         {
00461             std::cout << "Setting texture coordinates of 3 components "
00462                       << "but all the loaded textures will be of 2 components." << std::endl;
00463 
00464             float texCoords3[mesh->mNumVertices][3];
00465             for (std::size_t i(0); i < mesh->mNumVertices; ++i)
00466             {
00467                 texCoords3[i][0] = mesh->mTextureCoords[0][i].x;
00468                 texCoords3[i][1] = mesh->mTextureCoords[0][i].y;
00469                 texCoords3[i][2] = mesh->mTextureCoords[0][i].z;
00470             }
00471             vertexProperty->texCoord3.setValues(0, mesh->mNumVertices, texCoords3);
00472         }
00473         else
00474         {
00475             std::cout << "Mesh has texture coordinates of " << mesh->mNumUVComponents[0]
00476                       << " components. Property will be ignored." << std::endl;
00477         }
00478     }
00479 
00480     //Set faces
00481     int indices[mesh->mNumFaces * (numIndices + 1)];
00482     for (std::size_t i(0); i < mesh->mNumFaces; ++i)
00483     {
00484         for (std::size_t j(0); j < numIndices; ++j)
00485         {
00486             indices[i * (numIndices + 1) + j] = mesh->mFaces[i].mIndices[j];
00487         }
00488         indices[i * (numIndices + 1) + numIndices] = -1;
00489     }
00490     shape->coordIndex.setValues(0, mesh->mNumFaces * (numIndices + 1), indices);
00491 
00492     return shape;
00493 }
00494 
00495 
00496 SoSeparator *getMesh(const aiMesh *const mesh, const aiMaterial *const material,
00497                      const std::string& sceneDir, SoSeparator *meshSep = NULL, const SoMaterial * materialOverride = NULL)
00498 {
00499     SoIndexedShape *shape(getShape(mesh));
00500     if (shape)
00501     {
00502         if (!meshSep) meshSep = new SoSeparator;
00503 
00504         //Add texture
00505         SoTexture *texture(getTexture(material, sceneDir));
00506         if (texture) meshSep->addChild(texture);
00507 
00508         //Add material
00509         if (!materialOverride) meshSep->addChild(getMaterial(material));
00510         else meshSep->addChild(cloneMaterial(*materialOverride));
00511 
00512         //Add shape
00513         meshSep->addChild(shape);
00514 
00515         return meshSep;
00516     }
00517     else
00518     {
00519         return NULL;
00520     }
00521 }
00522 
00523 
00524 bool hasMesh(const aiNode *node)
00525 {
00526     if (node->mNumMeshes > 0) return true;
00527     for (std::size_t i(0); i < node->mNumChildren; ++i)
00528     {
00529         if (hasMesh(node->mChildren[i])) return true;
00530     }
00531     return false;
00532 }
00533 
00537 void addNode(SoSeparator *const parent, const aiNode *const node,
00538              const aiMaterial *const *const materials, const aiMesh *const *const meshes,
00539              const aiTexture *const *const textures, const std::string& sceneDir,
00540              const SoMaterial * materialOverride)
00541 {
00542     if (hasMesh(node))
00543     {
00544         SoSeparator *nodeSep;
00545         if (node->mTransformation.IsIdentity() &&
00546                 node->mNumMeshes == 0)
00547         {
00548             nodeSep = parent;
00549         }
00550         else
00551         {
00552             //Create separator
00553             nodeSep = new SoSeparator;
00554             nodeSep->setName(getName(node->mName.C_Str()));
00555             parent->addChild(nodeSep);
00556 
00557             //Add transform
00558             if (!node->mTransformation.IsIdentity())
00559                 nodeSep->addChild(getTransform(node->mTransformation));
00560 
00561             //Add meshes
00562             if (node->mNumMeshes == 1 && node->mNumChildren == 0)
00563             {
00564                 getMesh(meshes[node->mMeshes[0]],
00565                         materials[meshes[node->mMeshes[0]]->mMaterialIndex],
00566                         sceneDir, nodeSep,
00567                         materialOverride);
00568             }
00569             else
00570             {
00571                 for (std::size_t i(0); i < node->mNumMeshes; ++i)
00572                 {
00573                     SoNode *child(getMesh(meshes[node->mMeshes[i]],
00574                                           //useMaterial,
00575                                           materials[meshes[node->mMeshes[i]]->mMaterialIndex],
00576                                           sceneDir, NULL,
00577                                           materialOverride));
00578                     //delete useMaterial; // delete because this was a temporary copy
00579                     if (child) nodeSep->addChild(child);
00580                 }
00581             }
00582         }
00583 
00584         //Add children nodes
00585         for (std::size_t i(0); i < node->mNumChildren; ++i)
00586         {
00587             addNode(nodeSep, node->mChildren[i], materials, meshes, textures, sceneDir, materialOverride);
00588         }
00589     }
00590 }
00591 
00595 SoSeparator *Assimp2Inventor(const aiScene *const scene, const std::string& sceneDir,
00596                              const SoMaterial * materialOverride)
00597 {
00598     SoSeparator *root(new SoSeparator);
00599     /*    ROS_INFO_STREAM("Imported a scene with " << scene->mNumTextures << " embedded textures, "
00600                   << scene->mNumMaterials << " materials and "
00601                   << scene->mNumMeshes << " meshes.");*/
00602     if (scene->mNumTextures > 0)
00603     {
00604         std::cout << "Found a scene with embedded textures. They will be ignored." << std::endl;
00606     }
00607     addNode(root, scene->mRootNode, scene->mMaterials,
00608             scene->mMeshes, scene->mTextures, sceneDir, materialOverride);
00609     return root;
00610 }
00611 
00612 
00613 std::vector<std::string> tokenize(const std::string &str, const std::string &token)
00614 {
00615     std::vector<std::string> tokenized;
00616     size_t from(0), size(str.size());
00617     for (size_t to(std::min(str.find(token, from), size));
00618             from < to; to = std::min(str.find(token, from), size))
00619     {
00620         tokenized.push_back(str.substr(from, to - from));
00621         from = to + token.size();
00622     }
00623     return tokenized;
00624 }
00625 
00626 
00627 std::vector<std::string> assimpImportedExtensions()
00628 {
00629     aiString tmp;
00630     Assimp::Importer importer;
00631     importer.GetExtensionList(tmp);
00632     std::string extensions(tmp.C_Str());
00633 
00634     return tokenize(extensions.substr(2, std::string::npos), ";*.");
00635 }
00636 
00637 
00638 std::vector<std::pair<std::string, std::vector<std::string> > > assimpImportedFormats()
00639 {
00640     std::vector<std::pair<std::string, std::vector<std::string> > > importedFormats;
00641     const aiImporterDesc *importerDesc;
00642     Assimp::Importer importer;
00643     std::string name;
00644     std::vector<std::string> extensions;
00645     std::size_t k, pos;
00646     for (std::size_t i(0); i < importer.GetImporterCount(); ++i)
00647     {
00648         importerDesc = importer.GetImporterInfo(i);
00649 
00650         name = importerDesc->mName;
00651         pos = name.find(" Importer");
00652         if (pos != std::string::npos) name.erase(pos, 9);
00653         pos = name.find(" Reader");
00654         if (pos != std::string::npos) name.erase(pos, 7);
00655         pos = name.find("\n");
00656         if (pos != std::string::npos) name.erase(pos, std::string::npos);
00657         while (name.substr(name.size() - 1) == " ")
00658         {
00659             name.erase(name.size() - 1, 1);
00660         }
00661         extensions = tokenize(importerDesc->mFileExtensions, " ");
00662 
00663         k = 0;
00664         while (k < importedFormats.size() &&
00665                 importedFormats.at(k).first != name)
00666         {
00667             k++;
00668         }
00669         if (k < importedFormats.size())
00670         {
00671             for (std::size_t j(0); j < extensions.size(); ++j)
00672             {
00673                 importedFormats.at(k).second.push_back(extensions.at(j));
00674             }
00675         }
00676         else
00677         {
00678             std::pair< std::string, std::vector<std::string> > format;
00679             format.first = name;
00680             format.second = extensions;
00681             importedFormats.push_back(format);
00682         }
00683     }
00684 
00685     return importedFormats;
00686 }
00687 


urdf2inventor
Author(s): Jennifer Buehler
autogenerated on Fri Mar 1 2019 03:38:11