31 #include <OgrePrerequisites.h>
34 #include <boost/filesystem.hpp>
35 #include <boost/algorithm/string.hpp>
37 #include <OgreSkeleton.h>
38 #include <OgreSkeletonManager.h>
39 #include <OgreSkeletonSerializer.h>
40 #include <OgreMeshManager.h>
41 #include <OgreTextureManager.h>
42 #include <OgreMaterialManager.h>
43 #include <OgreTexture.h>
45 #include <OgreTechnique.h>
46 #include <OgreMaterial.h>
47 #include <OgreTextureUnitState.h>
48 #include <OgreMeshSerializer.h>
49 #include <OgreSubMesh.h>
50 #include <OgreHardwareBufferManager.h>
51 #include <OgreSharedPtr.h>
52 #include <OgreTechnique.h>
58 #include <assimp/Importer.hpp>
59 #include <assimp/scene.h>
60 #include <assimp/postprocess.h>
61 #include <assimp/IOStream.hpp>
62 #include <assimp/IOSystem.hpp>
63 #include <boost/filesystem/operations.hpp>
65 namespace fs = boost::filesystem;
80 size_t Read(
void* buffer,
size_t size,
size_t count)
override
82 size_t to_read = size * count;
88 memcpy(buffer,
pos_, to_read);
94 size_t Write(
const void* ,
size_t ,
size_t )
override
100 aiReturn
Seek(
size_t offset, aiOrigin origin)
override
102 uint8_t* new_pos =
nullptr;
109 new_pos =
pos_ + offset;
120 return aiReturn_FAILURE;
124 return aiReturn_SUCCESS;
158 bool Exists(
const char* file)
const override
183 Assimp::IOStream*
Open(
const char* file,
const char* mode =
"rb")
override
185 ROS_ASSERT(mode == std::string(
"r") || mode == std::string(
"rb"));
203 void Close(Assimp::IOStream* stream)
override;
222 const Ogre::MeshPtr& mesh,
223 Ogre::AxisAlignedBox& aabb,
225 std::vector<Ogre::MaterialPtr>& material_table,
226 aiMatrix4x4 transform = aiMatrix4x4())
231 if (node->mParent ==
nullptr)
234 transform = node->mTransformation;
236 aiVector3D scaling, axis, pos;
238 transform.Decompose(scaling, axis,
angle, pos);
240 transform = aiMatrix4x4(scaling, aiQuaternion(), pos);
243 transform *= node->mTransformation;
246 aiMatrix3x3 rotation(transform);
248 for (uint32_t i = 0; i < node->mNumMeshes; i++)
250 aiMesh* input_mesh = scene->mMeshes[node->mMeshes[i]];
252 Ogre::SubMesh* submesh = mesh->createSubMesh();
253 submesh->useSharedVertices =
false;
254 submesh->vertexData =
new Ogre::VertexData();
255 Ogre::VertexData* vertex_data = submesh->vertexData;
256 Ogre::VertexDeclaration* vertex_decl = vertex_data->vertexDeclaration;
260 vertex_decl->addElement(0, offset, Ogre::VET_FLOAT3, Ogre::VES_POSITION);
261 offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
264 if (input_mesh->HasNormals())
266 vertex_decl->addElement(0, offset, Ogre::VET_FLOAT3, Ogre::VES_NORMAL);
267 offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
271 if (input_mesh->HasTextureCoords(0))
273 vertex_decl->addElement(0, offset, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, 0);
280 vertex_data->vertexCount = input_mesh->mNumVertices;
281 Ogre::HardwareVertexBufferSharedPtr vbuf =
282 Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(
283 vertex_decl->getVertexSize(0), vertex_data->vertexCount,
284 Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY,
false);
286 vertex_data->vertexBufferBinding->setBinding(0, vbuf);
287 float* vertices =
static_cast<float*
>(vbuf->lock(Ogre::HardwareBuffer::HBL_DISCARD));
290 for (uint32_t j = 0; j < input_mesh->mNumVertices; j++)
292 aiVector3D p = input_mesh->mVertices[j];
298 Ogre::Vector3 v(p.x, p.y, p.z);
300 float dist = v.length();
306 if (input_mesh->HasNormals())
308 aiVector3D n = input_mesh->mNormals[j];
316 if (input_mesh->HasTextureCoords(0))
318 *vertices++ = input_mesh->mTextureCoords[0][j].x;
319 *vertices++ = input_mesh->mTextureCoords[0][j].y;
324 submesh->indexData->indexCount = 0;
325 for (uint32_t j = 0; j < input_mesh->mNumFaces; j++)
327 aiFace& face = input_mesh->mFaces[j];
328 submesh->indexData->indexCount += face.mNumIndices;
332 if (vertex_data->vertexCount < (1 << 16))
335 submesh->indexData->indexBuffer = Ogre::HardwareBufferManager::getSingleton().createIndexBuffer(
336 Ogre::HardwareIndexBuffer::IT_16BIT, submesh->indexData->indexCount,
337 Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY,
false);
339 Ogre::HardwareIndexBufferSharedPtr ibuf = submesh->indexData->indexBuffer;
340 uint16_t* indices =
static_cast<uint16_t*
>(ibuf->lock(Ogre::HardwareBuffer::HBL_DISCARD));
343 for (uint32_t j = 0; j < input_mesh->mNumFaces; j++)
345 aiFace& face = input_mesh->mFaces[j];
346 for (uint32_t k = 0; k < face.mNumIndices; ++k)
348 *indices++ = face.mIndices[k];
361 submesh->indexData->indexBuffer = Ogre::HardwareBufferManager::getSingleton().createIndexBuffer(
362 Ogre::HardwareIndexBuffer::IT_32BIT, submesh->indexData->indexCount,
363 Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY,
false);
365 Ogre::HardwareIndexBufferSharedPtr ibuf = submesh->indexData->indexBuffer;
366 uint32_t* indices =
static_cast<uint32_t*
>(ibuf->lock(Ogre::HardwareBuffer::HBL_DISCARD));
369 for (uint32_t j = 0; j < input_mesh->mNumFaces; j++)
371 aiFace& face = input_mesh->mFaces[j];
372 for (uint32_t k = 0; k < face.mNumIndices; ++k)
374 *indices++ = face.mIndices[k];
382 Ogre::MaterialPtr
const& material = material_table[input_mesh->mMaterialIndex];
383 submesh->setMaterialName(material->getName(), material->getGroup());
386 for (uint32_t i = 0; i < node->mNumChildren; ++i)
388 buildMesh(scene, node->mChildren[i], mesh, aabb, radius, material_table, transform);
394 if (!Ogre::TextureManager::getSingleton().resourceExists(resource_path))
400 res = retriever.
get(resource_path);
409 Ogre::DataStreamPtr stream(
new Ogre::MemoryDataStream(res.
data.get(), res.
size));
411 std::string extension = fs::extension(fs::path(resource_path));
413 if (extension[0] ==
'.')
415 extension = extension.substr(1, extension.size() - 1);
420 image.load(stream, extension);
421 Ogre::TextureManager::getSingleton().loadImage(
422 resource_path, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, image);
424 catch (Ogre::Exception& e)
426 ROS_ERROR(
"Could not load texture [%s]: %s", resource_path.c_str(), e.what());
442 const aiScene* scene,
443 std::vector<Ogre::MaterialPtr>& material_table_out)
445 #if BOOST_FILESYSTEM_VERSION == 3
446 std::string ext = fs::path(resource_path).extension().string();
448 std::string ext = fs::path(resource_path).extension();
450 boost::algorithm::to_lower(ext);
454 material_table_out.push_back(Ogre::MaterialManager::getSingleton().getByName(
"BaseWhiteNoLighting"));
458 for (uint32_t i = 0; i < scene->mNumMaterials; i++)
460 std::stringstream ss;
461 ss << resource_path <<
"Material" << i;
462 Ogre::MaterialPtr mat = Ogre::MaterialManager::getSingleton().create(
463 ss.str(), Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
true);
464 material_table_out.push_back(mat);
466 Ogre::Technique* tech = mat->getTechnique(0);
467 Ogre::Pass* pass = tech->getPass(0);
469 aiMaterial* amat = scene->mMaterials[i];
471 Ogre::ColourValue diffuse(1.0, 1.0, 1.0, 1.0);
472 Ogre::ColourValue specular(1.0, 1.0, 1.0, 1.0);
473 Ogre::ColourValue ambient(0, 0, 0, 1.0);
475 for (uint32_t j = 0; j < amat->mNumProperties; j++)
477 aiMaterialProperty* prop = amat->mProperties[j];
478 std::string propKey = prop->mKey.data;
480 if (propKey ==
"$tex.file")
483 aiTextureMapping mapping;
485 amat->GetTexture(aiTextureType_DIFFUSE, 0, &texName, &mapping, &uvIndex);
488 std::string texture_path = fs::path(resource_path).parent_path().string() +
"/" + texName.data;
490 Ogre::TextureUnitState* tu = pass->createTextureUnitState();
491 tu->setTextureName(texture_path);
493 else if (propKey ==
"$clr.diffuse")
496 amat->Get(AI_MATKEY_COLOR_DIFFUSE, clr);
497 diffuse = Ogre::ColourValue(clr.r, clr.g, clr.b);
499 else if (propKey ==
"$clr.ambient")
502 amat->Get(AI_MATKEY_COLOR_AMBIENT, clr);
503 ambient = Ogre::ColourValue(clr.r, clr.g, clr.b);
505 else if (propKey ==
"$clr.specular")
508 amat->Get(AI_MATKEY_COLOR_SPECULAR, clr);
509 specular = Ogre::ColourValue(clr.r, clr.g, clr.b);
511 else if (propKey ==
"$clr.emissive")
514 amat->Get(AI_MATKEY_COLOR_EMISSIVE, clr);
515 mat->setSelfIllumination(clr.r, clr.g, clr.b);
517 else if (propKey ==
"$clr.opacity")
520 amat->Get(AI_MATKEY_OPACITY, o);
523 else if (propKey ==
"$mat.shininess")
526 amat->Get(AI_MATKEY_SHININESS,
s);
527 mat->setShininess(
s);
529 else if (propKey ==
"$mat.shadingm")
532 amat->Get(AI_MATKEY_SHADING_MODEL, model);
535 case aiShadingMode_Flat:
536 mat->setShadingMode(Ogre::SO_FLAT);
538 case aiShadingMode_Phong:
539 mat->setShadingMode(Ogre::SO_PHONG);
541 case aiShadingMode_Gouraud:
543 mat->setShadingMode(Ogre::SO_GOURAUD);
549 int mode = aiBlendMode_Default;
550 amat->Get(AI_MATKEY_BLEND_FUNC, mode);
553 case aiBlendMode_Additive:
554 mat->setSceneBlending(Ogre::SBT_ADD);
556 case aiBlendMode_Default:
559 if (diffuse.a < 0.99)
561 pass->setSceneBlending(Ogre::SBT_TRANSPARENT_ALPHA);
565 pass->setSceneBlending(Ogre::SBT_REPLACE);
571 mat->setAmbient(ambient * 0.5);
572 mat->setDiffuse(diffuse);
573 specular.a = diffuse.a;
574 mat->setSpecular(specular);
580 if (!scene->HasMeshes())
582 ROS_ERROR(
"No meshes found in file [%s]", name.c_str());
583 return Ogre::MeshPtr();
586 std::vector<Ogre::MaterialPtr> material_table;
589 Ogre::MeshPtr mesh = Ogre::MeshManager::getSingleton().createManual(
590 name, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
592 Ogre::AxisAlignedBox aabb(Ogre::AxisAlignedBox::EXTENT_NULL);
594 buildMesh(scene, scene->mRootNode, mesh, aabb, radius, material_table);
596 mesh->_setBounds(aabb);
597 mesh->_setBoundingSphereRadius(radius);
598 mesh->buildEdgeList();
607 if (Ogre::MeshManager::getSingleton().resourceExists(resource_path))
609 return Ogre::MeshManager::getSingleton().getByName(resource_path);
613 fs::path model_path(resource_path);
614 #if BOOST_FILESYSTEM_VERSION == 3
615 std::string ext = model_path.extension().string();
617 std::string ext = model_path.extension();
619 boost::algorithm::to_lower(ext);
626 res = retriever.
get(resource_path);
631 return Ogre::MeshPtr();
636 return Ogre::MeshPtr();
640 Ogre::MeshSerializer ser;
641 Ogre::DataStreamPtr stream(
new Ogre::MemoryDataStream(res.
data.get(), res.
size));
642 Ogre::MeshPtr mesh = Ogre::MeshManager::getSingleton().createManual(
643 resource_path, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
644 ser.importMesh(stream, mesh.get());
650 Assimp::Importer importer;
652 const aiScene* scene =
653 importer.ReadFile(resource_path, aiProcess_SortByPType | aiProcess_FindInvalidData |
654 aiProcess_GenNormals | aiProcess_Triangulate |
655 aiProcess_GenUVCoords | aiProcess_FlipUVs);
658 ROS_ERROR(
"Could not load resource [%s]: %s", resource_path.c_str(), importer.GetErrorString());
659 return Ogre::MeshPtr();
666 return Ogre::MeshPtr();
672 std::string skeleton_resource_path = resource_path.substr(0, resource_path.length() - 4);
673 skeleton_resource_path.append(
"skeleton");
675 if (Ogre::SkeletonManager::getSingleton().resourceExists(skeleton_resource_path))
677 return Ogre::SkeletonManager::getSingleton().getByName(skeleton_resource_path);
685 res = retriever.
get(skeleton_resource_path);
690 return Ogre::SkeletonPtr();
695 return Ogre::SkeletonPtr();
698 fs::path skeleton_path(skeleton_resource_path);
700 Ogre::SkeletonSerializer ser;
701 Ogre::DataStreamPtr stream(
new Ogre::MemoryDataStream(res.
data.get(), res.
size));
702 Ogre::SkeletonPtr skeleton = Ogre::SkeletonManager::getSingleton().create(
703 skeleton_path.filename().string(), Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
true);
704 ser.importSkeleton(stream, skeleton.get());
709 return Ogre::SkeletonPtr();