00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
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)
00134 {
00135 std::cout << "Found a compressed embedded texture. "
00136 << "It will be ignored." << std::endl;
00140 return NULL;
00141 }
00142 else
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
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
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
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
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
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
00228 }
00229
00230
00231 std::string filename = absPath.string();
00232
00233
00234 texture->filename.setValue(filename.c_str());
00235
00236 texture->setName(getName(filename));
00237
00238
00239 texture->model.setValue(SoTexture2::DECAL);
00240
00241
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
00306 if (material->Get(AI_MATKEY_NAME, name) == aiReturn_SUCCESS)
00307 {
00308 soMat->setName(getName(name.C_Str()));
00309 }
00310
00311
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
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
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
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
00344 if (material->Get(AI_MATKEY_OPACITY, value) == aiReturn_SUCCESS)
00345 {
00346 soMat->transparency.setValue(1.0 - value);
00347 }
00348
00349
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;
00362
00363
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
00382
00383 std::cout << "Wrong primitive type. Mesh will be ignored." << std::endl;
00384 return NULL;
00385 break;
00386 }
00387
00388
00389 shape->setName(getName(mesh->mName.C_Str()));
00390
00391 SoVertexProperty *vertexProperty(new SoVertexProperty);
00392 shape->vertexProperty.setValue(vertexProperty);
00393
00394
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
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
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
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
00505 SoTexture *texture(getTexture(material, sceneDir));
00506 if (texture) meshSep->addChild(texture);
00507
00508
00509 if (!materialOverride) meshSep->addChild(getMaterial(material));
00510 else meshSep->addChild(cloneMaterial(*materialOverride));
00511
00512
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
00553 nodeSep = new SoSeparator;
00554 nodeSep->setName(getName(node->mName.C_Str()));
00555 parent->addChild(nodeSep);
00556
00557
00558 if (!node->mTransformation.IsIdentity())
00559 nodeSep->addChild(getTransform(node->mTransformation));
00560
00561
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
00575 materials[meshes[node->mMeshes[i]]->mMaterialIndex],
00576 sceneDir, NULL,
00577 materialOverride));
00578
00579 if (child) nodeSep->addChild(child);
00580 }
00581 }
00582 }
00583
00584
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
00600
00601
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