Loading [MathJax]/extensions/TeX/AMSmath.js
Radium Engine  1.5.0
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Modules Pages
AssimpHandleDataLoader.cpp
1 #include <IO/AssimpLoader/AssimpHandleDataLoader.hpp>
2 
3 #include <assimp/mesh.h>
4 #include <assimp/scene.h>
5 #include <queue>
6 #include <set>
7 
8 #include <Core/Asset/HandleData.hpp>
9 #include <Core/Utils/Log.hpp>
10 
11 #include <IO/AssimpLoader/AssimpWrapper.hpp>
12 
13 namespace Ra {
14 namespace IO {
15 
16 using namespace Core::Utils; // log
17 using namespace Core::Asset;
18 
20 AssimpHandleDataLoader::AssimpHandleDataLoader( const bool VERBOSE_MODE ) :
21  DataLoader<HandleData>( VERBOSE_MODE ) {}
22 
24 AssimpHandleDataLoader::~AssimpHandleDataLoader() = default;
25 
27 
28 void AssimpHandleDataLoader::loadData( const aiScene* scene,
29  std::vector<std::unique_ptr<HandleData>>& data ) {
30  data.clear();
31 
32  if ( scene == nullptr ) {
33  LOG( logDEBUG ) << "AssimpHandleDataLoader : scene is nullptr.";
34  return;
35  }
36 
37  if ( m_verbose ) {
38  LOG( logDEBUG ) << "File contains handle.";
39  LOG( logDEBUG ) << "Handle Loading begin...";
40  }
41 
42  loadHandleData( scene, data );
43 
44  if ( m_verbose ) { LOG( logDEBUG ) << "Handle Loading end.\n"; }
45 }
46 
48 
49 namespace {
50 
51 aiNode* findMeshNode( aiNode* node, const aiScene* scene, const aiString& meshName ) {
52  // look inside the node
53  for ( uint i = 0; i < node->mNumMeshes; ++i ) {
54  if ( scene->mMeshes[node->mMeshes[i]]->mName == meshName ) { return node; }
55  }
56  // repeat on children
57  for ( uint i = 0; i < node->mNumChildren; ++i ) {
58  aiNode* n = findMeshNode( node->mChildren[i], scene, meshName );
59  if ( n != nullptr ) { return n; }
60  }
61  return nullptr;
62 }
63 
64 void initMarks( const aiNode* node, std::map<std::string, bool>& flags, bool flag = false ) {
65  flags[assimpToCore( node->mName )] = flag;
66  for ( uint i = 0; i < node->mNumChildren; ++i ) {
67  initMarks( node->mChildren[i], flags, flag );
68  }
69 }
70 
71 void markParents( aiNode* node,
72  const aiScene* scene,
73  const std::vector<aiNode*>& meshParents,
74  std::map<std::string, bool>& flag ) {
75  const std::string nodeName = assimpToCore( node->mName );
76  if ( flag[nodeName] ) {
77  // skip already visited up-tree.
78  return;
79  }
80  flag[nodeName] = true;
81  // check if node is in the mesh hierarchy
82  auto it = std::find_if(
83  meshParents.begin(), meshParents.end(), [node]( const auto& n ) { return n == node; } );
84  if ( it != meshParents.end() ) {
85  flag[nodeName] = false;
86  return;
87  }
88  // otherwise mark parents
89  if ( node->mParent != nullptr ) { markParents( node->mParent, scene, meshParents, flag ); }
90 }
91 
92 } // namespace
93 
95 void AssimpHandleDataLoader::loadHandleData(
96  const aiScene* scene,
97  std::vector<std::unique_ptr<HandleData>>& data ) const {
98  // list mesh names according to GeometryLoader naming
99  std::set<std::string> meshNames;
100 
101  // initialize need flag on all scene nodes
102  std::map<std::string, bool> needNode;
103  initMarks( scene->mRootNode, needNode );
104 
105  std::vector<std::vector<aiNode*>> meshParents( scene->mNumMeshes );
106 
107  // load the HandleComponentData for all meshes
108  std::map<std::string, HandleComponentData> mapBone2Data;
109  for ( uint n = 0; n < scene->mNumMeshes; ++n ) {
110  const aiMesh* mesh = scene->mMeshes[n];
111  // fetch mesh name as registered by the GeometryLoader
112  std::string meshName = assimpToCore( mesh->mName );
113  while ( meshNames.find( meshName ) != meshNames.end() ) {
114  meshName.append( "_" );
115  }
116  meshNames.insert( meshName );
117 
118  // if bound to no skeleton, skip
119  if ( !mesh->HasBones() ) { continue; }
120 
121  // get mesh node parents
122  aiNode* meshNode = findMeshNode( scene->mRootNode, scene, mesh->mName );
123  while ( meshNode != nullptr ) {
124  meshParents[n].push_back( meshNode );
125  meshNode = meshNode->mParent;
126  }
127 
128  // deal with skeleton
129  for ( uint j = 0; j < mesh->mNumBones; ++j ) {
130  const aiBone* bone = mesh->mBones[j];
131  // fetch bone data
132  const std::string boneName = assimpToCore( bone->mName );
133  // if data doesn't exist yet, create it
134  mapBone2Data[boneName].m_name = boneName;
135  // fill skinning weights and offset matrix for this mesh
136  loadHandleComponentDataWeights( bone, meshName, mapBone2Data[boneName] );
137  // deal with hierarchy
138  aiNode* node = scene->mRootNode->FindNode( bone->mName );
139  if ( node == nullptr ) { continue; }
140  // mark parents as needed up to mesh node relative
141  markParents( node, scene, meshParents[n], needNode );
142  // check children since end bones may not have weights
143  if ( node->mNumChildren == 1 ) {
144  const aiNode* child = node->mChildren[0];
145  const std::string childName = assimpToCore( child->mName );
146  // mark as needed
147  needNode[childName] = true;
148  // if data doesn't exist yet, create it
149  mapBone2Data[childName].m_name = childName;
150  }
151  }
152  }
153 
154  // also add bone nodes for skeletons not attached to a mesh
155  auto rootNode = scene->mRootNode;
156  for ( uint i = 0; i < rootNode->mNumChildren; ++i ) {
157  auto node = rootNode->mChildren[i];
158  if ( needNode[assimpToCore( node->mName )] ) { continue; }
159  // check not up from a mesh
160  auto res =
161  std::find_if( meshParents.begin(), meshParents.end(), [node]( const auto& nodes ) {
162  return std::find_if( nodes.begin(), nodes.end(), [node]( const auto& n ) {
163  return n == node;
164  } ) != nodes.end();
165  } );
166  if ( res != meshParents.end() ) { continue; }
167  // mark subtree
168  initMarks( node, needNode, true );
169  }
170 
171  // load hierarchy for needed bones
172  std::vector<std::pair<std::string, std::string>> edgeList;
173  for ( const auto& n : needNode ) {
174  if ( !n.second ) { continue; }
175  // if data doesn't exist, create it (bone with no weight)
176  mapBone2Data[n.first].m_name = n.first;
177  // link to children
178  const aiNode* node = scene->mRootNode->FindNode( aiString( n.first ) );
179  for ( uint j = 0; j < node->mNumChildren; ++j ) {
180  const std::string childName = assimpToCore( node->mChildren[j]->mName );
181  if ( needNode.at( childName ) ) {
182  // if data doesn't exist, create it (bone with no weight)
183  mapBone2Data[childName].m_name = childName;
184  // register parenthood
185  edgeList.push_back( { n.first, childName } );
186  }
187  }
188  }
189 
190  // load bone frame once all are registered
191  for ( auto& bone : mapBone2Data ) {
192  loadHandleComponentDataFrame( scene, aiString( bone.first ), bone.second );
193  }
194 
195  // find roots and leaves
196  std::set<std::string> roots;
197  for ( const auto& node : needNode ) {
198  if ( node.second ) { roots.insert( node.first ); }
199  }
200  std::set<std::string> leaves = roots;
201  for ( auto edge : edgeList ) {
202  roots.erase( edge.second );
203  leaves.erase( edge.first );
204  }
205 
206  // build one HandleData per root
207  for ( auto root : roots ) {
208  HandleData* handle = new HandleData();
209  handle->setType( HandleData::SKELETON );
210  handle->setName( root );
211 
212  Ra::Core::Transform frame = Ra::Core::Transform::Identity();
213  aiNode* node = scene->mRootNode->FindNode( aiString( root ) );
214  while ( node->mParent != nullptr ) {
215  node = node->mParent;
216  frame = assimpToCore( node->mTransformation ) * frame;
217  }
218  handle->setFrame( frame );
219 
220  // get list of bones and edges for this skeleton
221  std::map<std::string, uint> nameTable;
222  fillHandleData( root, edgeList, mapBone2Data, nameTable, handle );
223  handle->setNameTable( nameTable );
224 
225  // check if need additional end bones
226  bool needEndBone = false;
227  for ( const std::string& leaf : leaves ) {
228  if ( nameTable.find( leaf ) != nameTable.end() ) {
229  const auto& handleComponentData = mapBone2Data[leaf];
230  for ( const auto& mesh : handleComponentData.m_weights ) {
231  if ( mesh.second.size() != 0 ) {
232  needEndBone = true;
233  break;
234  }
235  }
236  if ( needEndBone ) { break; }
237  }
238  }
239  handle->needEndNodes( needEndBone );
240 
241  if ( handle->isSkeleton() && !handle->hasEdges() ) {
242  // Do not load empty skeleton
243  delete handle;
244  }
245  else {
246  // register the HandleData
247  data.emplace_back( handle );
248  if ( m_verbose ) { handle->displayInfo(); }
249  }
250  }
251 }
252 
253 void AssimpHandleDataLoader::loadHandleComponentDataFrame( const aiScene* scene,
254  const aiString& boneName,
255  HandleComponentData& data ) const {
256  // fetch global transform
257  data.m_frame.setIdentity();
258  aiNode* node = scene->mRootNode->FindNode( boneName );
259  while ( node != nullptr ) {
260  data.m_frame = assimpToCore( node->mTransformation ) * data.m_frame;
261  node = node->mParent;
262  }
263 }
264 
265 void AssimpHandleDataLoader::loadHandleComponentDataWeights( const aiBone* bone,
266  const std::string& meshName,
267  HandleComponentData& data ) const {
268  // fetch skinning weigthts
269  for ( uint j = 0; j < bone->mNumWeights; ++j ) {
270  std::pair<uint, Scalar> weight( bone->mWeights[j].mVertexId, bone->mWeights[j].mWeight );
271  data.m_weights[meshName].push_back( weight );
272  }
273  data.m_bindMatrices[meshName] = assimpToCore( bone->mOffsetMatrix );
274 }
275 
276 void AssimpHandleDataLoader::fillHandleData(
277  const std::string& node,
278  const std::vector<std::pair<std::string, std::string>>& edgeList,
279  const std::map<std::string, HandleComponentData>& mapBone2Data,
280  std::map<std::string, uint>& nameTable,
281  HandleData* data ) const {
282  // register the HandleComponentData for the bone
283  nameTable[node] = uint( data->getComponentData().size() );
284  data->getComponentData().push_back( mapBone2Data.at( node ) );
285  // bind meshes bound to the bone
286  for ( const auto& mesh : mapBone2Data.at( node ).m_weights ) {
287  data->addBindMesh( mesh.first );
288  }
289  // go through children
290  for ( const auto& edge : edgeList ) {
291  if ( edge.first == node ) {
292  fillHandleData( edge.second, edgeList, mapBone2Data, nameTable, data );
293  data->getEdgeData().push_back(
294  { nameTable.at( edge.first ), nameTable.at( edge.second ) } );
295  }
296  }
297 }
298 
299 } // namespace IO
300 } // namespace Ra
Definition: Cage.cpp:3