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 printf( "mesh_loader.cpp: using 16-bit index buffer.\n");
00305
00306 submesh->indexData->indexBuffer = Ogre::HardwareBufferManager::getSingleton().createIndexBuffer(
00307 Ogre::HardwareIndexBuffer::IT_16BIT,
00308 submesh->indexData->indexCount,
00309 Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY,
00310 false);
00311
00312 Ogre::HardwareIndexBufferSharedPtr ibuf = submesh->indexData->indexBuffer;
00313 uint16_t* indices = static_cast<uint16_t*>(ibuf->lock(Ogre::HardwareBuffer::HBL_DISCARD));
00314
00315
00316 for (uint32_t j = 0; j < input_mesh->mNumFaces; j++)
00317 {
00318 aiFace& face = input_mesh->mFaces[j];
00319 for (uint32_t k = 0; k < face.mNumIndices; ++k)
00320 {
00321 *indices++ = face.mIndices[k];
00322 }
00323 }
00324
00325 ibuf->unlock();
00326 }
00327 else
00328 {
00329
00330
00331
00332
00333
00334 submesh->indexData->indexBuffer = Ogre::HardwareBufferManager::getSingleton().createIndexBuffer(
00335 Ogre::HardwareIndexBuffer::IT_32BIT,
00336 submesh->indexData->indexCount,
00337 Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY,
00338 false);
00339
00340 Ogre::HardwareIndexBufferSharedPtr ibuf = submesh->indexData->indexBuffer;
00341 uint32_t* indices = static_cast<uint32_t*>(ibuf->lock(Ogre::HardwareBuffer::HBL_DISCARD));
00342
00343
00344 for (uint32_t j = 0; j < input_mesh->mNumFaces; j++)
00345 {
00346 aiFace& face = input_mesh->mFaces[j];
00347 for (uint32_t k = 0; k < face.mNumIndices; ++k)
00348 {
00349 *indices++ = face.mIndices[k];
00350 }
00351 }
00352
00353 ibuf->unlock();
00354 }
00355 vbuf->unlock();
00356 }
00357
00358 for (uint32_t i=0; i < node->mNumChildren; ++i)
00359 {
00360 buildMesh(scene, node->mChildren[i], mesh, aabb, radius);
00361 }
00362 }
00363
00364 void loadTexture(const std::string& resource_path)
00365 {
00366 if (!Ogre::TextureManager::getSingleton().resourceExists(resource_path))
00367 {
00368 resource_retriever::Retriever retriever;
00369 resource_retriever::MemoryResource res;
00370 try
00371 {
00372 res = retriever.get(resource_path);
00373 }
00374 catch (resource_retriever::Exception& e)
00375 {
00376 ROS_ERROR("%s", e.what());
00377 }
00378
00379 if (res.size != 0)
00380 {
00381 Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(res.data.get(), res.size));
00382 Ogre::Image image;
00383 std::string extension = fs::extension(fs::path(resource_path));
00384
00385 if (extension[0] == '.')
00386 {
00387 extension = extension.substr(1, extension.size() - 1);
00388 }
00389
00390 try
00391 {
00392 image.load(stream, extension);
00393 Ogre::TextureManager::getSingleton().loadImage(resource_path, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, image);
00394 }
00395 catch (Ogre::Exception& e)
00396 {
00397 ROS_ERROR("Could not load texture [%s]: %s", resource_path.c_str(), e.what());
00398 }
00399 }
00400 }
00401 }
00402
00403
00404 void loadMaterialsForMesh(const std::string& resource_path, const aiScene* scene, const Ogre::MeshPtr& mesh)
00405 {
00406 std::vector<Ogre::MaterialPtr> material_lookup;
00407
00408 for (uint32_t i = 0; i < scene->mNumMaterials; i++)
00409 {
00410 std::stringstream ss;
00411 ss << resource_path << "Material" << i;
00412 Ogre::MaterialPtr mat = Ogre::MaterialManager::getSingleton().create(ss.str(), ROS_PACKAGE_NAME, true);
00413 material_lookup.push_back(mat);
00414
00415 Ogre::Technique* tech = mat->getTechnique(0);
00416 Ogre::Pass* pass = tech->getPass(0);
00417
00418 aiMaterial *amat = scene->mMaterials[i];
00419
00420 Ogre::ColourValue diffuse(1.0, 1.0, 1.0, 1.0);
00421 Ogre::ColourValue specular(1.0, 1.0, 1.0, 1.0);
00422 Ogre::ColourValue ambient(0.5, 0.5, 0.5, 1.0);
00423
00424 for (uint32_t j=0; j < amat->mNumProperties; j++)
00425 {
00426 aiMaterialProperty *prop = amat->mProperties[j];
00427 std::string propKey = prop->mKey.data;
00428
00429 if (propKey == "$tex.file")
00430 {
00431 aiString texName;
00432 aiTextureMapping mapping;
00433 uint32_t uvIndex;
00434 amat->GetTexture(aiTextureType_DIFFUSE,0, &texName, &mapping, &uvIndex);
00435
00436
00437 std::string texture_path = fs::path(resource_path).parent_path().string() + "/" + texName.data;
00438 loadTexture(texture_path);
00439 Ogre::TextureUnitState* tu = pass->createTextureUnitState();
00440 tu->setTextureName(texture_path);
00441 }
00442 else if (propKey == "$clr.diffuse")
00443 {
00444 aiColor3D clr;
00445 amat->Get(AI_MATKEY_COLOR_DIFFUSE, clr);
00446 diffuse = Ogre::ColourValue(clr.r, clr.g, clr.b);
00447 }
00448 else if (propKey == "$clr.ambient")
00449 {
00450 aiColor3D clr;
00451 amat->Get(AI_MATKEY_COLOR_AMBIENT, clr);
00452
00453
00454 if (clr.r > 0 && clr.g > 0 && clr.b > 0)
00455 {
00456 ambient = Ogre::ColourValue(clr.r, clr.g, clr.b);
00457 }
00458 }
00459 else if (propKey == "$clr.specular")
00460 {
00461 aiColor3D clr;
00462 amat->Get(AI_MATKEY_COLOR_SPECULAR, clr);
00463 specular = Ogre::ColourValue(clr.r, clr.g, clr.b);
00464 }
00465 else if (propKey == "$clr.emissive")
00466 {
00467 aiColor3D clr;
00468 amat->Get(AI_MATKEY_COLOR_EMISSIVE, clr);
00469 mat->setSelfIllumination(clr.r, clr.g, clr.b);
00470 }
00471 else if (propKey == "$clr.opacity")
00472 {
00473 float o;
00474 amat->Get(AI_MATKEY_OPACITY, o);
00475 diffuse.a = o;
00476 }
00477 else if (propKey == "$mat.shininess")
00478 {
00479 float s;
00480 amat->Get(AI_MATKEY_SHININESS, s);
00481 mat->setShininess(s);
00482 }
00483 else if (propKey == "$mat.shadingm")
00484 {
00485 int model;
00486 amat->Get(AI_MATKEY_SHADING_MODEL, model);
00487 switch(model)
00488 {
00489 case aiShadingMode_Flat:
00490 mat->setShadingMode(Ogre::SO_FLAT);
00491 break;
00492 case aiShadingMode_Phong:
00493 mat->setShadingMode(Ogre::SO_PHONG);
00494 break;
00495 case aiShadingMode_Gouraud:
00496 default:
00497 mat->setShadingMode(Ogre::SO_GOURAUD);
00498 break;
00499 }
00500 }
00501 }
00502
00503 int mode = aiBlendMode_Default;
00504 amat->Get(AI_MATKEY_BLEND_FUNC, mode);
00505 switch(mode)
00506 {
00507 case aiBlendMode_Additive:
00508 mat->setSceneBlending(Ogre::SBT_ADD);
00509 break;
00510 case aiBlendMode_Default:
00511 default:
00512 {
00513 if (diffuse.a < 0.99)
00514 {
00515 pass->setSceneBlending(Ogre::SBT_TRANSPARENT_ALPHA);
00516 }
00517 else
00518 {
00519 pass->setSceneBlending(Ogre::SBT_REPLACE);
00520 }
00521 }
00522 break;
00523 }
00524
00525 mat->setAmbient(ambient);
00526 mat->setDiffuse(diffuse);
00527 specular.a = diffuse.a;
00528 mat->setSpecular(specular);
00529 }
00530
00531 for (uint32_t i = 0; i < mesh->getNumSubMeshes(); ++i)
00532 {
00533 mesh->getSubMesh(i)->setMaterialName(material_lookup[scene->mMeshes[i]->mMaterialIndex]->getName());
00534 }
00535 }
00536
00537 Ogre::MeshPtr meshFromAssimpScene(const std::string& name, const aiScene* scene)
00538 {
00539 if (!scene->HasMeshes())
00540 {
00541 ROS_ERROR("No meshes found in file [%s]", name.c_str());
00542 return Ogre::MeshPtr();
00543 }
00544
00545 Ogre::MeshPtr mesh = Ogre::MeshManager::getSingleton().createManual(name, ROS_PACKAGE_NAME);
00546
00547 Ogre::AxisAlignedBox aabb(Ogre::AxisAlignedBox::EXTENT_NULL);
00548 float radius = 0.0f;
00549 buildMesh(scene, scene->mRootNode, mesh, aabb, radius);
00550
00551 mesh->_setBounds(aabb);
00552 mesh->_setBoundingSphereRadius(radius);
00553 mesh->buildEdgeList();
00554
00555 loadMaterialsForMesh(name, scene, mesh);
00556
00557 mesh->load();
00558
00559 return mesh;
00560 }
00561
00562 Ogre::MeshPtr loadMeshFromResource(const std::string& resource_path)
00563 {
00564 if (Ogre::MeshManager::getSingleton().resourceExists(resource_path))
00565 {
00566 return Ogre::MeshManager::getSingleton().getByName(resource_path);
00567 }
00568 else
00569 {
00570 fs::path model_path(resource_path);
00571 #if BOOST_FILESYSTEM_VERSION == 3
00572 std::string ext = model_path.extension().string();
00573 #else
00574 std::string ext = model_path.extension();
00575 #endif
00576 if (ext == ".mesh" || ext == ".MESH")
00577 {
00578 resource_retriever::Retriever retriever;
00579 resource_retriever::MemoryResource res;
00580 try
00581 {
00582 res = retriever.get(resource_path);
00583 }
00584 catch (resource_retriever::Exception& e)
00585 {
00586 ROS_ERROR("%s", e.what());
00587 return Ogre::MeshPtr();
00588 }
00589
00590 if (res.size == 0)
00591 {
00592 return Ogre::MeshPtr();
00593 }
00594
00595 Ogre::MeshSerializer ser;
00596 Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(res.data.get(), res.size));
00597 Ogre::MeshPtr mesh = Ogre::MeshManager::getSingleton().createManual(resource_path, "rviz");
00598 ser.importMesh(stream, mesh.get());
00599
00600 return mesh;
00601 }
00602 else if (ext == ".stl" || ext == ".STL" || ext == ".stlb" || ext == ".STLB")
00603 {
00604 resource_retriever::Retriever retriever;
00605 resource_retriever::MemoryResource res;
00606 try
00607 {
00608 res = retriever.get(resource_path);
00609 }
00610 catch (resource_retriever::Exception& e)
00611 {
00612 ROS_ERROR("%s", e.what());
00613 return Ogre::MeshPtr();
00614 }
00615
00616 if (res.size == 0)
00617 {
00618 return Ogre::MeshPtr();
00619 }
00620
00621 ogre_tools::STLLoader loader;
00622 if (!loader.load(res.data.get()))
00623 {
00624 ROS_ERROR("Failed to load file [%s]", resource_path.c_str());
00625 return Ogre::MeshPtr();
00626 }
00627
00628 return loader.toMesh(resource_path);
00629 }
00630 else
00631 {
00632 Assimp::Importer importer;
00633 importer.SetIOHandler(new ResourceIOSystem());
00634 const aiScene* scene = importer.ReadFile(resource_path, aiProcess_SortByPType|aiProcess_GenNormals|aiProcess_Triangulate|aiProcess_GenUVCoords|aiProcess_FlipUVs);
00635 if (!scene)
00636 {
00637 ROS_ERROR("Could not load resource [%s]: %s", resource_path.c_str(), importer.GetErrorString());
00638 return Ogre::MeshPtr();
00639 }
00640
00641 return meshFromAssimpScene(resource_path, scene);
00642 }
00643 }
00644
00645 return Ogre::MeshPtr();
00646 }
00647
00648 }