Go to the documentation of this file.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 <rve_mesh_loader/assimp_parser.h>
00031 #include <rve_mesh_loader/exception.h>
00032
00033 #include <rve_msgs/Mesh.h>
00034
00035 #include <rve_common/uuid.h>
00036
00037 #include <resource_retriever/retriever.h>
00038
00039 #include <boost/filesystem.hpp>
00040
00041 #include <assimp/assimp.hpp>
00042 #include <assimp/aiScene.h>
00043 #include <assimp/aiPostProcess.h>
00044 #include <assimp/IOStream.h>
00045 #include <assimp/IOSystem.h>
00046
00047 #include <ros/assert.h>
00048
00049 namespace fs = boost::filesystem;
00050
00051 namespace rve_mesh_loader
00052 {
00053
00054 class ResourceIOStream : public Assimp::IOStream
00055 {
00056 public:
00057 ResourceIOStream(const resource_retriever::MemoryResource& res)
00058 : res_(res)
00059 , pos_(res.data.get())
00060 {}
00061
00062 ~ResourceIOStream()
00063 {}
00064
00065 size_t Read(void* buffer, size_t size, size_t count)
00066 {
00067 size_t to_read = size * count;
00068 if (pos_ + to_read > res_.data.get() + res_.size)
00069 {
00070 to_read = res_.size - (pos_ - res_.data.get());
00071 }
00072
00073 memcpy(buffer, pos_, to_read);
00074 pos_ += to_read;
00075
00076 return to_read;
00077 }
00078
00079 size_t Write( const void* buffer, size_t size, size_t count) { ROS_BREAK(); return 0; }
00080
00081 aiReturn Seek( size_t offset, aiOrigin origin)
00082 {
00083 uint8_t* new_pos = 0;
00084 switch (origin)
00085 {
00086 case aiOrigin_SET:
00087 new_pos = res_.data.get() + offset;
00088 break;
00089 case aiOrigin_CUR:
00090 new_pos = pos_ + offset;
00091 break;
00092 case aiOrigin_END:
00093 new_pos = res_.data.get() + res_.size - offset;
00094 break;
00095 default:
00096 ROS_BREAK();
00097 }
00098
00099 if (new_pos < res_.data.get() || new_pos > res_.data.get() + res_.size)
00100 {
00101 return aiReturn_FAILURE;
00102 }
00103
00104 pos_ = new_pos;
00105 return aiReturn_SUCCESS;
00106 }
00107
00108 size_t Tell() const
00109 {
00110 return pos_ - res_.data.get();
00111 }
00112
00113 size_t FileSize() const
00114 {
00115 return res_.size;
00116 }
00117
00118 void Flush() {}
00119
00120 private:
00121 resource_retriever::MemoryResource res_;
00122 uint8_t* pos_;
00123 };
00124
00125 class ResourceIOSystem : public Assimp::IOSystem
00126 {
00127 public:
00128 ResourceIOSystem()
00129 {
00130 }
00131
00132 ~ResourceIOSystem()
00133 {
00134 }
00135
00136
00137 bool Exists(const char* file) const
00138 {
00139
00140
00141
00142 resource_retriever::MemoryResource res;
00143 try
00144 {
00145 res = retriever_.get(file);
00146 }
00147 catch (resource_retriever::Exception& e)
00148 {
00149 return false;
00150 }
00151
00152 return true;
00153 }
00154
00155
00156 char getOsSeparator() const
00157 {
00158 return '/';
00159 }
00160
00161
00162 Assimp::IOStream* Open(const char* file, const char* mode)
00163 {
00164 ROS_ASSERT(mode == std::string("r") || mode == std::string("rb"));
00165
00166
00167
00168 resource_retriever::MemoryResource res;
00169 try
00170 {
00171 res = retriever_.get(file);
00172 }
00173 catch (resource_retriever::Exception& e)
00174 {
00175 return 0;
00176 }
00177
00178 return new ResourceIOStream(res);
00179 }
00180
00181 void Close(Assimp::IOStream* stream) { delete stream; }
00182
00183 private:
00184 mutable resource_retriever::Retriever retriever_;
00185 };
00186
00187 rve_msgs::Vector3 assimpToMsg(const aiVector3D& vec)
00188 {
00189 rve_msgs::Vector3 out;
00190 out.x = vec.x;
00191 out.y = vec.y;
00192 out.z = vec.z;
00193 return out;
00194 }
00195
00196
00197 void buildMesh(const aiScene* scene, const aiNode* node, rve_msgs::Mesh& out_mesh)
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 {
00212 transform = pnode->mTransformation * transform;
00213 }
00214
00215 pnode = pnode->mParent;
00216 }
00217
00218 aiMatrix3x3 rotation(transform);
00219 aiMatrix3x3 inverse_transpose_rotation(rotation);
00220 inverse_transpose_rotation.Inverse();
00221 inverse_transpose_rotation.Transpose();
00222
00223 for (uint32_t i = 0; i < node->mNumMeshes; i++)
00224 {
00225 aiMesh* input_mesh = scene->mMeshes[node->mMeshes[i]];
00226 out_mesh.submeshes.resize(out_mesh.submeshes.size() + 1);
00227 rve_msgs::SubMesh& submesh = out_mesh.submeshes.back();
00228 submesh.tex_coords.resize(input_mesh->GetNumUVChannels());
00229 submesh.colors.resize(input_mesh->GetNumColorChannels());
00230
00231
00232 for (uint32_t j = 0; j < input_mesh->mNumVertices; j++)
00233 {
00234 aiVector3D p = input_mesh->mVertices[j];
00235 p *= transform;
00236 rve_msgs::Vector3 pos;
00237 pos.x = p.x;
00238 pos.y = p.y;
00239 pos.z = p.z;
00240 submesh.positions.push_back(pos);
00241
00242 if (input_mesh->HasNormals())
00243 {
00244 submesh.normals.push_back(assimpToMsg(inverse_transpose_rotation * input_mesh->mNormals[j]));
00245 }
00246
00247 if (input_mesh->HasTangentsAndBitangents())
00248 {
00249 submesh.tangents.push_back(assimpToMsg(input_mesh->mTangents[j]));
00250 submesh.binormals.push_back(assimpToMsg(input_mesh->mBitangents[j]));
00251 }
00252
00253 for (uint32_t k = 0; input_mesh->HasTextureCoords(k); ++k)
00254 {
00255 rve_msgs::TexCoordChannel& channel = submesh.tex_coords[k];
00256 rve_msgs::TexCoord coord;
00257 coord.uvw[0] = input_mesh->mTextureCoords[k][j].x;
00258 coord.uvw[1] = input_mesh->mTextureCoords[k][j].y;
00259 channel.dims = 2;
00260 channel.array.push_back(coord);
00261 }
00262
00263 for (uint32_t k = 0; input_mesh->HasVertexColors(k); ++k)
00264 {
00265 rve_msgs::ColorChannel& channel = submesh.colors[k];
00266 std_msgs::ColorRGBA color;
00267 color.r = input_mesh->mColors[k][j].r;
00268 color.g = input_mesh->mColors[k][j].g;
00269 color.b = input_mesh->mColors[k][j].b;
00270 color.a = input_mesh->mColors[k][j].a;
00271 channel.array.push_back(color);
00272 }
00273 }
00274
00275
00276 for (uint32_t j = 0; j < input_mesh->mNumFaces; j++)
00277 {
00278 aiFace& face = input_mesh->mFaces[j];
00279 for (uint32_t k = 0; k < face.mNumIndices; ++k)
00280 {
00281 submesh.indices.push_back(face.mIndices[k]);
00282 }
00283 }
00284 }
00285
00286 for (uint32_t i=0; i < node->mNumChildren; ++i)
00287 {
00288 buildMesh(scene, node->mChildren[i], out_mesh);
00289 }
00290 }
00291
00292 void loadMaterialsForMesh(const std::string& resource_path, const aiScene* scene, rve_msgs::Mesh& mesh)
00293 {
00294 for (uint32_t i = 0; i < scene->mNumMaterials; i++)
00295 {
00296 rve_msgs::Material mat;
00297 mat.id = rve_common::UUID::generate();
00298
00299 aiMaterial *amat = scene->mMaterials[i];
00300
00301
00302
00303 aiString tex_name;
00304 if (amat->GetTexture(aiTextureType_DIFFUSE, 0, &tex_name) == aiReturn_SUCCESS)
00305 {
00306
00307 std::string texture_path = fs::path(resource_path).parent_path().string() + "/" + tex_name.data;
00308 mat.texture = texture_path;
00309 mat.has_texture = true;
00310 }
00311
00312 if (amat->GetTexture(aiTextureType_HEIGHT, 0, &tex_name) == aiReturn_SUCCESS)
00313 {
00314 std::string texture_path = fs::path(resource_path).parent_path().string() + "/" + tex_name.data;
00315 mat.normal_map = texture_path;
00316 mat.has_normal_map = true;
00317 }
00318
00319 float opacity = 1.0;
00320
00321
00322 if (amat->Get(AI_MATKEY_OPACITY, opacity) != aiReturn_SUCCESS)
00323 {
00324 opacity = 1.0;
00325 }
00326
00327 mat.opacity = opacity;
00328
00329 aiColor3D clr;
00330 if (amat->Get(AI_MATKEY_COLOR_DIFFUSE, clr) == aiReturn_SUCCESS)
00331 {
00332 mat.color.r = clr.r;
00333 mat.color.b = clr.g;
00334 mat.color.g = clr.b;
00335 mat.has_color = true;
00336 }
00337
00338 mesh.materials.push_back(mat);
00339 }
00340
00341 for (size_t i = 0; i < mesh.submeshes.size(); ++i)
00342 {
00343 mesh.submeshes[i].material_index = scene->mMeshes[i]->mMaterialIndex;
00344 }
00345 }
00346
00347 void meshFromAssimpScene(const std::string& filename, const aiScene* scene, rve_msgs::Mesh& out_mesh)
00348 {
00349 if (!scene->HasMeshes())
00350 {
00351 throw ParseException("No meshes found in file");
00352 }
00353
00354 buildMesh(scene, scene->mRootNode, out_mesh);
00355 loadMaterialsForMesh(filename, scene, out_mesh);
00356 }
00357
00358 void parseWithAssimp(uint8_t* buffer, size_t buffer_size, const std::string& filename, rve_msgs::Mesh& out_mesh)
00359 {
00360 Assimp::Importer importer;
00361 importer.SetIOHandler(new ResourceIOSystem());
00362 std::string extension = fs::extension(fs::path(filename)).substr(1);
00363 const aiScene* scene = importer.ReadFileFromMemory(buffer, buffer_size, aiProcess_SortByPType|aiProcess_GenNormals|aiProcess_Triangulate|aiProcess_GenUVCoords|aiProcess_FlipUVs|aiProcess_CalcTangentSpace, extension.c_str());
00364 if (!scene)
00365 {
00366 throw ParseException(importer.GetErrorString());
00367 }
00368
00369 meshFromAssimpScene(filename, scene, out_mesh);
00370 }
00371
00372 }