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
00026
00027
00028
00029
00030 #include "mesh_loader.h"
00031 #include <resource_retriever/retriever.h>
00032
00033 #include <boost/filesystem.hpp>
00034
00035 #include <ogre_tools/stl_loader.h>
00036
00037 #include <OGRE/OgreMeshManager.h>
00038 #include <OGRE/OgreTextureManager.h>
00039 #include <OGRE/OgreMaterialManager.h>
00040 #include <OGRE/OgreTexture.h>
00041 #include <OGRE/OgrePass.h>
00042 #include <OGRE/OgreTechnique.h>
00043 #include <OGRE/OgreMaterial.h>
00044 #include <OGRE/OgreTextureUnitState.h>
00045 #include <OGRE/OgreMeshSerializer.h>
00046 #include <OGRE/OgreSubMesh.h>
00047 #include <OGRE/OgreHardwareBufferManager.h>
00048
00049 #include <ros/assert.h>
00050
00051 #include <assimp/assimp.hpp>
00052 #include <assimp/aiScene.h>
00053 #include <assimp/aiPostProcess.h>
00054 #include <assimp/IOStream.h>
00055 #include <assimp/IOSystem.h>
00056
00057
00058 namespace fs = boost::filesystem;
00059
00060 namespace rviz
00061 {
00062
00063 class ResourceIOStream : public Assimp::IOStream
00064 {
00065 public:
00066 ResourceIOStream(const resource_retriever::MemoryResource& res)
00067 : res_(res)
00068 , pos_(res.data.get())
00069 {}
00070
00071 ~ResourceIOStream()
00072 {}
00073
00074 size_t Read(void* buffer, size_t size, size_t count)
00075 {
00076 size_t to_read = size * count;
00077 if (pos_ + to_read > res_.data.get() + res_.size)
00078 {
00079 to_read = res_.size - (pos_ - res_.data.get());
00080 }
00081
00082 memcpy(buffer, pos_, to_read);
00083 pos_ += to_read;
00084
00085 return to_read;
00086 }
00087
00088 size_t Write( const void* buffer, size_t size, size_t count) { ROS_BREAK(); return 0; }
00089
00090 aiReturn Seek( size_t offset, aiOrigin origin)
00091 {
00092 uint8_t* new_pos = 0;
00093 switch (origin)
00094 {
00095 case aiOrigin_SET:
00096 new_pos = res_.data.get() + offset;
00097 break;
00098 case aiOrigin_CUR:
00099 new_pos = pos_ + offset;
00100 break;
00101 case aiOrigin_END:
00102 new_pos = res_.data.get() + res_.size - offset;
00103 break;
00104 default:
00105 ROS_BREAK();
00106 }
00107
00108 if (new_pos < res_.data.get() || new_pos > res_.data.get() + res_.size)
00109 {
00110 return aiReturn_FAILURE;
00111 }
00112
00113 pos_ = new_pos;
00114 return aiReturn_SUCCESS;
00115 }
00116
00117 size_t Tell() const
00118 {
00119 return pos_ - res_.data.get();
00120 }
00121
00122 size_t FileSize() const
00123 {
00124 return res_.size;
00125 }
00126
00127 void Flush() {}
00128
00129 private:
00130 resource_retriever::MemoryResource res_;
00131 uint8_t* pos_;
00132 };
00133
00134 class ResourceIOSystem : public Assimp::IOSystem
00135 {
00136 public:
00137 ResourceIOSystem()
00138 {
00139 }
00140
00141 ~ResourceIOSystem()
00142 {
00143 }
00144
00145
00146 bool Exists(const char* file) const
00147 {
00148
00149
00150
00151 resource_retriever::MemoryResource res;
00152 try
00153 {
00154 res = retriever_.get(file);
00155 }
00156 catch (resource_retriever::Exception& e)
00157 {
00158 return false;
00159 }
00160
00161 return true;
00162 }
00163
00164
00165 char getOsSeparator() const
00166 {
00167 return '/';
00168 }
00169
00170
00171 Assimp::IOStream* Open(const char* file, const char* mode)
00172 {
00173 ROS_ASSERT(mode == std::string("r") || mode == std::string("rb"));
00174
00175
00176
00177 resource_retriever::MemoryResource res;
00178 try
00179 {
00180 res = retriever_.get(file);
00181 }
00182 catch (resource_retriever::Exception& e)
00183 {
00184 return 0;
00185 }
00186
00187 return new ResourceIOStream(res);
00188 }
00189
00190 void Close(Assimp::IOStream* stream) { delete stream; }
00191
00192 private:
00193 mutable resource_retriever::Retriever retriever_;
00194 };
00195
00196
00197 void buildMesh(const aiScene* scene, const aiNode* node, const Ogre::MeshPtr& mesh, Ogre::AxisAlignedBox& aabb, float& radius)
00198 {
00199 if (!node)
00200 {
00201 return;
00202 }
00203
00204 aiMatrix4x4 transform = node->mTransformation;
00205 aiNode *pnode = node->mParent;
00206 while (pnode)
00207 {
00208
00209
00210 if (pnode->mParent != NULL)
00211 transform = pnode->mTransformation * transform;
00212 pnode = pnode->mParent;
00213 }
00214
00215 aiMatrix3x3 rotation(transform);
00216 aiMatrix3x3 inverse_transpose_rotation(rotation);
00217 inverse_transpose_rotation.Inverse();
00218 inverse_transpose_rotation.Transpose();
00219
00220 for (uint32_t i = 0; i < node->mNumMeshes; i++)
00221 {
00222 aiMesh* input_mesh = scene->mMeshes[node->mMeshes[i]];
00223
00224 Ogre::SubMesh* submesh = mesh->createSubMesh();
00225 submesh->useSharedVertices = false;
00226 submesh->vertexData = new Ogre::VertexData();
00227 Ogre::VertexData* vertex_data = submesh->vertexData;
00228 Ogre::VertexDeclaration* vertex_decl = vertex_data->vertexDeclaration;
00229
00230 size_t offset = 0;
00231
00232 vertex_decl->addElement(0, offset, Ogre::VET_FLOAT3, Ogre::VES_POSITION);
00233 offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
00234
00235
00236 if (input_mesh->HasNormals())
00237 {
00238 vertex_decl->addElement(0, offset, Ogre::VET_FLOAT3, Ogre::VES_NORMAL);
00239 offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
00240 }
00241
00242
00243 if (input_mesh->HasTextureCoords(0))
00244 {
00245 vertex_decl->addElement(0, offset, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, 0);
00246 offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2);
00247 }
00248
00249
00250
00251
00252 vertex_data->vertexCount = input_mesh->mNumVertices;
00253 Ogre::HardwareVertexBufferSharedPtr vbuf = Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(vertex_decl->getVertexSize(0),
00254 vertex_data->vertexCount,
00255 Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY,
00256 false);
00257
00258 vertex_data->vertexBufferBinding->setBinding(0, vbuf);
00259 float* vertices = static_cast<float*>(vbuf->lock(Ogre::HardwareBuffer::HBL_DISCARD));
00260
00261
00262 for (uint32_t j = 0; j < input_mesh->mNumVertices; j++)
00263 {
00264 aiVector3D p = input_mesh->mVertices[j];
00265 p *= transform;
00266 *vertices++ = p.x;
00267 *vertices++ = p.y;
00268 *vertices++ = p.z;
00269
00270 Ogre::Vector3 v(p.x, p.y, p.z);
00271 aabb.merge(v);
00272 float dist = v.length();
00273 if (dist > radius)
00274 {
00275 radius = dist;
00276 }
00277
00278 if (input_mesh->HasNormals())
00279 {
00280 aiVector3D n = inverse_transpose_rotation * input_mesh->mNormals[j];
00281 *vertices++ = n.x;
00282 *vertices++ = n.y;
00283 *vertices++ = n.z;
00284 }
00285
00286 if (input_mesh->HasTextureCoords(0))
00287 {
00288 *vertices++ = input_mesh->mTextureCoords[0][j].x;
00289 *vertices++ = input_mesh->mTextureCoords[0][j].y;
00290 }
00291 }
00292
00293
00294 submesh->indexData->indexCount = 0;
00295 for (uint32_t j = 0; j < input_mesh->mNumFaces; j++)
00296 {
00297 aiFace& face = input_mesh->mFaces[j];
00298 submesh->indexData->indexCount += face.mNumIndices;
00299 }
00300
00301
00302 if( vertex_data->vertexCount < (1<<16) )
00303 {
00304
00305 submesh->indexData->indexBuffer = Ogre::HardwareBufferManager::getSingleton().createIndexBuffer(
00306 Ogre::HardwareIndexBuffer::IT_16BIT,
00307 submesh->indexData->indexCount,
00308 Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY,
00309 false);
00310
00311 Ogre::HardwareIndexBufferSharedPtr ibuf = submesh->indexData->indexBuffer;
00312 uint16_t* indices = static_cast<uint16_t*>(ibuf->lock(Ogre::HardwareBuffer::HBL_DISCARD));
00313
00314
00315 for (uint32_t j = 0; j < input_mesh->mNumFaces; j++)
00316 {
00317 aiFace& face = input_mesh->mFaces[j];
00318 for (uint32_t k = 0; k < face.mNumIndices; ++k)
00319 {
00320 *indices++ = face.mIndices[k];
00321 }
00322 }
00323
00324 ibuf->unlock();
00325 }
00326 else
00327 {
00328
00329
00330
00331
00332
00333 submesh->indexData->indexBuffer = Ogre::HardwareBufferManager::getSingleton().createIndexBuffer(
00334 Ogre::HardwareIndexBuffer::IT_32BIT,
00335 submesh->indexData->indexCount,
00336 Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY,
00337 false);
00338
00339 Ogre::HardwareIndexBufferSharedPtr ibuf = submesh->indexData->indexBuffer;
00340 uint32_t* indices = static_cast<uint32_t*>(ibuf->lock(Ogre::HardwareBuffer::HBL_DISCARD));
00341
00342
00343 for (uint32_t j = 0; j < input_mesh->mNumFaces; j++)
00344 {
00345 aiFace& face = input_mesh->mFaces[j];
00346 for (uint32_t k = 0; k < face.mNumIndices; ++k)
00347 {
00348 *indices++ = face.mIndices[k];
00349 }
00350 }
00351
00352 ibuf->unlock();
00353 }
00354 vbuf->unlock();
00355 }
00356
00357 for (uint32_t i=0; i < node->mNumChildren; ++i)
00358 {
00359 buildMesh(scene, node->mChildren[i], mesh, aabb, radius);
00360 }
00361 }
00362
00363 void loadTexture(const std::string& resource_path)
00364 {
00365 if (!Ogre::TextureManager::getSingleton().resourceExists(resource_path))
00366 {
00367 resource_retriever::Retriever retriever;
00368 resource_retriever::MemoryResource res;
00369 try
00370 {
00371 res = retriever.get(resource_path);
00372 }
00373 catch (resource_retriever::Exception& e)
00374 {
00375 ROS_ERROR("%s", e.what());
00376 }
00377
00378 if (res.size != 0)
00379 {
00380 Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(res.data.get(), res.size));
00381 Ogre::Image image;
00382 std::string extension = fs::extension(fs::path(resource_path));
00383
00384 if (extension[0] == '.')
00385 {
00386 extension = extension.substr(1, extension.size() - 1);
00387 }
00388
00389 try
00390 {
00391 image.load(stream, extension);
00392 Ogre::TextureManager::getSingleton().loadImage(resource_path, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, image);
00393 }
00394 catch (Ogre::Exception& e)
00395 {
00396 ROS_ERROR("Could not load texture [%s]: %s", resource_path.c_str(), e.what());
00397 }
00398 }
00399 }
00400 }
00401
00402
00403 void loadMaterialsForMesh(const std::string& resource_path, const aiScene* scene, const Ogre::MeshPtr& mesh)
00404 {
00405 std::vector<Ogre::MaterialPtr> material_lookup;
00406
00407 for (uint32_t i = 0; i < scene->mNumMaterials; i++)
00408 {
00409 std::stringstream ss;
00410 ss << resource_path << "Material" << i;
00411 Ogre::MaterialPtr mat = Ogre::MaterialManager::getSingleton().create(ss.str(), ROS_PACKAGE_NAME, true);
00412 material_lookup.push_back(mat);
00413
00414 Ogre::Technique* tech = mat->getTechnique(0);
00415 Ogre::Pass* pass = tech->getPass(0);
00416
00417 aiMaterial *amat = scene->mMaterials[i];
00418
00419 Ogre::ColourValue diffuse(1.0, 1.0, 1.0, 1.0);
00420 Ogre::ColourValue specular(1.0, 1.0, 1.0, 1.0);
00421 Ogre::ColourValue ambient(0.5, 0.5, 0.5, 1.0);
00422
00423 for (uint32_t j=0; j < amat->mNumProperties; j++)
00424 {
00425 aiMaterialProperty *prop = amat->mProperties[j];
00426 std::string propKey = prop->mKey.data;
00427
00428 if (propKey == "$tex.file")
00429 {
00430 aiString texName;
00431 aiTextureMapping mapping;
00432 uint32_t uvIndex;
00433 amat->GetTexture(aiTextureType_DIFFUSE,0, &texName, &mapping, &uvIndex);
00434
00435
00436 std::string texture_path = fs::path(resource_path).parent_path().string() + "/" + texName.data;
00437 loadTexture(texture_path);
00438 Ogre::TextureUnitState* tu = pass->createTextureUnitState();
00439 tu->setTextureName(texture_path);
00440 }
00441 else if (propKey == "$clr.diffuse")
00442 {
00443 aiColor3D clr;
00444 amat->Get(AI_MATKEY_COLOR_DIFFUSE, clr);
00445 diffuse = Ogre::ColourValue(clr.r, clr.g, clr.b);
00446 }
00447 else if (propKey == "$clr.ambient")
00448 {
00449 aiColor3D clr;
00450 amat->Get(AI_MATKEY_COLOR_AMBIENT, clr);
00451
00452
00453 if (clr.r > 0 && clr.g > 0 && clr.b > 0)
00454 {
00455 ambient = Ogre::ColourValue(clr.r, clr.g, clr.b);
00456 }
00457 }
00458 else if (propKey == "$clr.specular")
00459 {
00460 aiColor3D clr;
00461 amat->Get(AI_MATKEY_COLOR_SPECULAR, clr);
00462 specular = Ogre::ColourValue(clr.r, clr.g, clr.b);
00463 }
00464 else if (propKey == "$clr.emissive")
00465 {
00466 aiColor3D clr;
00467 amat->Get(AI_MATKEY_COLOR_EMISSIVE, clr);
00468 mat->setSelfIllumination(clr.r, clr.g, clr.b);
00469 }
00470 else if (propKey == "$clr.opacity")
00471 {
00472 float o;
00473 amat->Get(AI_MATKEY_OPACITY, o);
00474 diffuse.a = o;
00475 }
00476 else if (propKey == "$mat.shininess")
00477 {
00478 float s;
00479 amat->Get(AI_MATKEY_SHININESS, s);
00480 mat->setShininess(s);
00481 }
00482 else if (propKey == "$mat.shadingm")
00483 {
00484 int model;
00485 amat->Get(AI_MATKEY_SHADING_MODEL, model);
00486 switch(model)
00487 {
00488 case aiShadingMode_Flat:
00489 mat->setShadingMode(Ogre::SO_FLAT);
00490 break;
00491 case aiShadingMode_Phong:
00492 mat->setShadingMode(Ogre::SO_PHONG);
00493 break;
00494 case aiShadingMode_Gouraud:
00495 default:
00496 mat->setShadingMode(Ogre::SO_GOURAUD);
00497 break;
00498 }
00499 }
00500 }
00501
00502 int mode = aiBlendMode_Default;
00503 amat->Get(AI_MATKEY_BLEND_FUNC, mode);
00504 switch(mode)
00505 {
00506 case aiBlendMode_Additive:
00507 mat->setSceneBlending(Ogre::SBT_ADD);
00508 break;
00509 case aiBlendMode_Default:
00510 default:
00511 {
00512 if (diffuse.a < 0.99)
00513 {
00514 pass->setSceneBlending(Ogre::SBT_TRANSPARENT_ALPHA);
00515 }
00516 else
00517 {
00518 pass->setSceneBlending(Ogre::SBT_REPLACE);
00519 }
00520 }
00521 break;
00522 }
00523
00524 mat->setAmbient(ambient);
00525 mat->setDiffuse(diffuse);
00526 specular.a = diffuse.a;
00527 mat->setSpecular(specular);
00528 }
00529
00530 for (uint32_t i = 0; i < mesh->getNumSubMeshes(); ++i)
00531 {
00532 mesh->getSubMesh(i)->setMaterialName(material_lookup[scene->mMeshes[i]->mMaterialIndex]->getName());
00533 }
00534 }
00535
00536 Ogre::MeshPtr meshFromAssimpScene(const std::string& name, const aiScene* scene)
00537 {
00538 if (!scene->HasMeshes())
00539 {
00540 ROS_ERROR("No meshes found in file [%s]", name.c_str());
00541 return Ogre::MeshPtr();
00542 }
00543
00544 Ogre::MeshPtr mesh = Ogre::MeshManager::getSingleton().createManual(name, ROS_PACKAGE_NAME);
00545
00546 Ogre::AxisAlignedBox aabb(Ogre::AxisAlignedBox::EXTENT_NULL);
00547 float radius = 0.0f;
00548 buildMesh(scene, scene->mRootNode, mesh, aabb, radius);
00549
00550 mesh->_setBounds(aabb);
00551 mesh->_setBoundingSphereRadius(radius);
00552 mesh->buildEdgeList();
00553
00554 loadMaterialsForMesh(name, scene, mesh);
00555
00556 mesh->load();
00557
00558 return mesh;
00559 }
00560
00561 Ogre::MeshPtr loadMeshFromResource(const std::string& resource_path)
00562 {
00563 if (Ogre::MeshManager::getSingleton().resourceExists(resource_path))
00564 {
00565 return Ogre::MeshManager::getSingleton().getByName(resource_path);
00566 }
00567 else
00568 {
00569 fs::path model_path(resource_path);
00570 #if BOOST_FILESYSTEM_VERSION == 3
00571 std::string ext = model_path.extension().string();
00572 #else
00573 std::string ext = model_path.extension();
00574 #endif
00575 if (ext == ".mesh" || ext == ".MESH")
00576 {
00577 resource_retriever::Retriever retriever;
00578 resource_retriever::MemoryResource res;
00579 try
00580 {
00581 res = retriever.get(resource_path);
00582 }
00583 catch (resource_retriever::Exception& e)
00584 {
00585 ROS_ERROR("%s", e.what());
00586 return Ogre::MeshPtr();
00587 }
00588
00589 if (res.size == 0)
00590 {
00591 return Ogre::MeshPtr();
00592 }
00593
00594 Ogre::MeshSerializer ser;
00595 Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(res.data.get(), res.size));
00596 Ogre::MeshPtr mesh = Ogre::MeshManager::getSingleton().createManual(resource_path, "rviz");
00597 ser.importMesh(stream, mesh.get());
00598
00599 return mesh;
00600 }
00601 else if (ext == ".stl" || ext == ".STL" || ext == ".stlb" || ext == ".STLB")
00602 {
00603 resource_retriever::Retriever retriever;
00604 resource_retriever::MemoryResource res;
00605 try
00606 {
00607 res = retriever.get(resource_path);
00608 }
00609 catch (resource_retriever::Exception& e)
00610 {
00611 ROS_ERROR("%s", e.what());
00612 return Ogre::MeshPtr();
00613 }
00614
00615 if (res.size == 0)
00616 {
00617 return Ogre::MeshPtr();
00618 }
00619
00620 ogre_tools::STLLoader loader;
00621 if (!loader.load(res.data.get()))
00622 {
00623 ROS_ERROR("Failed to load file [%s]", resource_path.c_str());
00624 return Ogre::MeshPtr();
00625 }
00626
00627 return loader.toMesh(resource_path);
00628 }
00629 else
00630 {
00631 Assimp::Importer importer;
00632 importer.SetIOHandler(new ResourceIOSystem());
00633 const aiScene* scene = importer.ReadFile(resource_path, aiProcess_SortByPType|aiProcess_GenNormals|aiProcess_Triangulate|aiProcess_GenUVCoords|aiProcess_FlipUVs);
00634 if (!scene)
00635 {
00636 ROS_ERROR("Could not load resource [%s]: %s", resource_path.c_str(), importer.GetErrorString());
00637 return Ogre::MeshPtr();
00638 }
00639
00640 return meshFromAssimpScene(resource_path, scene);
00641 }
00642 }
00643
00644 return Ogre::MeshPtr();
00645 }
00646
00647 }