1/*
2Open Asset Import Library (assimp)
3----------------------------------------------------------------------
4
5Copyright (c) 2006-2017, assimp team
6
7All rights reserved.
8
9Redistribution and use of this software in source and binary forms,
10with or without modification, are permitted provided that the
11following conditions are met:
12
13* Redistributions of source code must retain the above
14 copyright notice, this list of conditions and the
15 following disclaimer.
16
17* Redistributions in binary form must reproduce the above
18 copyright notice, this list of conditions and the
19 following disclaimer in the documentation and/or other
20 materials provided with the distribution.
21
22* Neither the name of the assimp team, nor the names of its
23 contributors may be used to endorse or promote products
24 derived from this software without specific prior
25 written permission of the assimp team.
26
27THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
33LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38
39----------------------------------------------------------------------
40*/
41
42/// @file DeboneProcess.cpp
43/** Implementation of the DeboneProcess post processing step */
44
45
46
47// internal headers of the post-processing framework
48#include "ProcessHelper.h"
49#include "DeboneProcess.h"
50#include <stdio.h>
51
52
53using namespace Assimp;
54
55// ------------------------------------------------------------------------------------------------
56// Constructor to be privately used by Importer
57DeboneProcess::DeboneProcess()
58{
59 mNumBones = 0;
60 mNumBonesCanDoWithout = 0;
61
62 mThreshold = AI_DEBONE_THRESHOLD;
63 mAllOrNone = false;
64}
65
66// ------------------------------------------------------------------------------------------------
67// Destructor, private as well
68DeboneProcess::~DeboneProcess()
69{
70 // nothing to do here
71}
72
73// ------------------------------------------------------------------------------------------------
74// Returns whether the processing step is present in the given flag field.
75bool DeboneProcess::IsActive( unsigned int pFlags) const
76{
77 return (pFlags & aiProcess_Debone) != 0;
78}
79
80// ------------------------------------------------------------------------------------------------
81// Executes the post processing step on the given imported data.
82void DeboneProcess::SetupProperties(const Importer* pImp)
83{
84 // get the current value of the property
85 mAllOrNone = pImp->GetPropertyInteger(AI_CONFIG_PP_DB_ALL_OR_NONE,0)?true:false;
86 mThreshold = pImp->GetPropertyFloat(AI_CONFIG_PP_DB_THRESHOLD,AI_DEBONE_THRESHOLD);
87}
88
89// ------------------------------------------------------------------------------------------------
90// Executes the post processing step on the given imported data.
91void DeboneProcess::Execute( aiScene* pScene)
92{
93 DefaultLogger::get()->debug("DeboneProcess begin");
94
95 if(!pScene->mNumMeshes) {
96 return;
97 }
98
99 std::vector<bool> splitList(pScene->mNumMeshes);
100 for( unsigned int a = 0; a < pScene->mNumMeshes; a++) {
101 splitList[a] = ConsiderMesh( pScene->mMeshes[a] );
102 }
103
104 int numSplits = 0;
105
106 if(!!mNumBonesCanDoWithout && (!mAllOrNone||mNumBonesCanDoWithout==mNumBones)) {
107 for(unsigned int a = 0; a < pScene->mNumMeshes; a++) {
108 if(splitList[a]) {
109 numSplits++;
110 }
111 }
112 }
113
114 if(numSplits) {
115 // we need to do something. Let's go.
116 //mSubMeshIndices.clear(); // really needed?
117 mSubMeshIndices.resize(pScene->mNumMeshes); // because we're doing it here anyway
118
119 // build a new array of meshes for the scene
120 std::vector<aiMesh*> meshes;
121
122 for(unsigned int a=0;a<pScene->mNumMeshes;a++)
123 {
124 aiMesh* srcMesh = pScene->mMeshes[a];
125
126 std::vector<std::pair<aiMesh*,const aiBone*> > newMeshes;
127
128 if(splitList[a]) {
129 SplitMesh(srcMesh,newMeshes);
130 }
131
132 // mesh was split
133 if(!newMeshes.empty()) {
134 unsigned int out = 0, in = srcMesh->mNumBones;
135
136 // store new meshes and indices of the new meshes
137 for(unsigned int b=0;b<newMeshes.size();b++) {
138 const aiString *find = newMeshes[b].second?&newMeshes[b].second->mName:0;
139
140 aiNode *theNode = find?pScene->mRootNode->FindNode(*find):0;
141 std::pair<unsigned int,aiNode*> push_pair(static_cast<unsigned int>(meshes.size()),theNode);
142
143 mSubMeshIndices[a].push_back(push_pair);
144 meshes.push_back(newMeshes[b].first);
145
146 out+=newMeshes[b].first->mNumBones;
147 }
148
149 if(!DefaultLogger::isNullLogger()) {
150 char buffer[1024];
151 ::ai_snprintf(buffer,1024,"Removed %u bones. Input bones: %u. Output bones: %u",in-out,in,out);
152 DefaultLogger::get()->info(buffer);
153 }
154
155 // and destroy the source mesh. It should be completely contained inside the new submeshes
156 delete srcMesh;
157 }
158 else {
159 // Mesh is kept unchanged - store it's new place in the mesh array
160 mSubMeshIndices[a].push_back(std::pair<unsigned int,aiNode*>(static_cast<unsigned int>(meshes.size()),(aiNode*)0));
161 meshes.push_back(srcMesh);
162 }
163 }
164
165 // rebuild the scene's mesh array
166 pScene->mNumMeshes = static_cast<unsigned int>(meshes.size());
167 delete [] pScene->mMeshes;
168 pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
169 std::copy( meshes.begin(), meshes.end(), pScene->mMeshes);
170
171 // recurse through all nodes and translate the node's mesh indices to fit the new mesh array
172 UpdateNode( pScene->mRootNode);
173 }
174
175 DefaultLogger::get()->debug("DeboneProcess end");
176}
177
178// ------------------------------------------------------------------------------------------------
179// Counts bones total/removable in a given mesh.
180bool DeboneProcess::ConsiderMesh(const aiMesh* pMesh)
181{
182 if(!pMesh->HasBones()) {
183 return false;
184 }
185
186 bool split = false;
187
188 //interstitial faces not permitted
189 bool isInterstitialRequired = false;
190
191 std::vector<bool> isBoneNecessary(pMesh->mNumBones,false);
192 std::vector<unsigned int> vertexBones(pMesh->mNumVertices,UINT_MAX);
193
194 const unsigned int cUnowned = UINT_MAX;
195 const unsigned int cCoowned = UINT_MAX-1;
196
197 for(unsigned int i=0;i<pMesh->mNumBones;i++) {
198 for(unsigned int j=0;j<pMesh->mBones[i]->mNumWeights;j++) {
199 float w = pMesh->mBones[i]->mWeights[j].mWeight;
200
201 if(w==0.0f) {
202 continue;
203 }
204
205 unsigned int vid = pMesh->mBones[i]->mWeights[j].mVertexId;
206 if(w>=mThreshold) {
207
208 if(vertexBones[vid]!=cUnowned) {
209 if(vertexBones[vid]==i) //double entry
210 {
211 DefaultLogger::get()->warn("Encountered double entry in bone weights");
212 }
213 else //TODO: track attraction in order to break tie
214 {
215 vertexBones[vid] = cCoowned;
216 }
217 }
218 else vertexBones[vid] = i;
219 }
220
221 if(!isBoneNecessary[i]) {
222 isBoneNecessary[i] = w<mThreshold;
223 }
224 }
225
226 if(!isBoneNecessary[i]) {
227 isInterstitialRequired = true;
228 }
229 }
230
231 if(isInterstitialRequired) {
232 for(unsigned int i=0;i<pMesh->mNumFaces;i++) {
233 unsigned int v = vertexBones[pMesh->mFaces[i].mIndices[0]];
234
235 for(unsigned int j=1;j<pMesh->mFaces[i].mNumIndices;j++) {
236 unsigned int w = vertexBones[pMesh->mFaces[i].mIndices[j]];
237
238 if(v!=w) {
239 if(v<pMesh->mNumBones) isBoneNecessary[v] = true;
240 if(w<pMesh->mNumBones) isBoneNecessary[w] = true;
241 }
242 }
243 }
244 }
245
246 for(unsigned int i=0;i<pMesh->mNumBones;i++) {
247 if(!isBoneNecessary[i]) {
248 mNumBonesCanDoWithout++;
249 split = true;
250 }
251
252 mNumBones++;
253 }
254 return split;
255}
256
257// ------------------------------------------------------------------------------------------------
258// Splits the given mesh by bone count.
259void DeboneProcess::SplitMesh( const aiMesh* pMesh, std::vector< std::pair< aiMesh*,const aiBone* > >& poNewMeshes) const
260{
261 // same deal here as ConsiderMesh basically
262
263 std::vector<bool> isBoneNecessary(pMesh->mNumBones,false);
264 std::vector<unsigned int> vertexBones(pMesh->mNumVertices,UINT_MAX);
265
266 const unsigned int cUnowned = UINT_MAX;
267 const unsigned int cCoowned = UINT_MAX-1;
268
269 for(unsigned int i=0;i<pMesh->mNumBones;i++) {
270 for(unsigned int j=0;j<pMesh->mBones[i]->mNumWeights;j++) {
271 float w = pMesh->mBones[i]->mWeights[j].mWeight;
272
273 if(w==0.0f) {
274 continue;
275 }
276
277 unsigned int vid = pMesh->mBones[i]->mWeights[j].mVertexId;
278
279 if(w>=mThreshold) {
280 if(vertexBones[vid]!=cUnowned) {
281 if(vertexBones[vid]==i) //double entry
282 {
283 //DefaultLogger::get()->warn("Encountered double entry in bone weights");
284 }
285 else //TODO: track attraction in order to break tie
286 {
287 vertexBones[vid] = cCoowned;
288 }
289 }
290 else vertexBones[vid] = i;
291 }
292
293 if(!isBoneNecessary[i]) {
294 isBoneNecessary[i] = w<mThreshold;
295 }
296 }
297 }
298
299 unsigned int nFacesUnowned = 0;
300
301 std::vector<unsigned int> faceBones(pMesh->mNumFaces,UINT_MAX);
302 std::vector<unsigned int> facesPerBone(pMesh->mNumBones,0);
303
304 for(unsigned int i=0;i<pMesh->mNumFaces;i++) {
305 unsigned int nInterstitial = 1;
306
307 unsigned int v = vertexBones[pMesh->mFaces[i].mIndices[0]];
308
309 for(unsigned int j=1;j<pMesh->mFaces[i].mNumIndices;j++) {
310 unsigned int w = vertexBones[pMesh->mFaces[i].mIndices[j]];
311
312 if(v!=w) {
313 if(v<pMesh->mNumBones) isBoneNecessary[v] = true;
314 if(w<pMesh->mNumBones) isBoneNecessary[w] = true;
315 }
316 else nInterstitial++;
317 }
318
319 if(v<pMesh->mNumBones &&nInterstitial==pMesh->mFaces[i].mNumIndices) {
320 faceBones[i] = v; //primitive belongs to bone #v
321 facesPerBone[v]++;
322 }
323 else nFacesUnowned++;
324 }
325
326 // invalidate any "cojoined" faces
327 for(unsigned int i=0;i<pMesh->mNumFaces;i++) {
328 if(faceBones[i]<pMesh->mNumBones&&isBoneNecessary[faceBones[i]])
329 {
330 ai_assert(facesPerBone[faceBones[i]]>0);
331 facesPerBone[faceBones[i]]--;
332
333 nFacesUnowned++;
334 faceBones[i] = cUnowned;
335 }
336 }
337
338 if(nFacesUnowned) {
339 std::vector<unsigned int> subFaces;
340
341 for(unsigned int i=0;i<pMesh->mNumFaces;i++) {
342 if(faceBones[i]==cUnowned) {
343 subFaces.push_back(i);
344 }
345 }
346
347 aiMesh *baseMesh = MakeSubmesh(pMesh,subFaces,0);
348 std::pair<aiMesh*,const aiBone*> push_pair(baseMesh,(const aiBone*)0);
349
350 poNewMeshes.push_back(push_pair);
351 }
352
353 for(unsigned int i=0;i<pMesh->mNumBones;i++) {
354
355 if(!isBoneNecessary[i]&&facesPerBone[i]>0) {
356 std::vector<unsigned int> subFaces;
357
358 for(unsigned int j=0;j<pMesh->mNumFaces;j++) {
359 if(faceBones[j]==i) {
360 subFaces.push_back(j);
361 }
362 }
363
364 unsigned int f = AI_SUBMESH_FLAGS_SANS_BONES;
365 aiMesh *subMesh =MakeSubmesh(pMesh,subFaces,f);
366
367 //Lifted from PretransformVertices.cpp
368 ApplyTransform(subMesh,pMesh->mBones[i]->mOffsetMatrix);
369 std::pair<aiMesh*,const aiBone*> push_pair(subMesh,pMesh->mBones[i]);
370
371 poNewMeshes.push_back(push_pair);
372 }
373 }
374}
375
376// ------------------------------------------------------------------------------------------------
377// Recursively updates the node's mesh list to account for the changed mesh list
378void DeboneProcess::UpdateNode(aiNode* pNode) const
379{
380 // rebuild the node's mesh index list
381
382 std::vector<unsigned int> newMeshList;
383
384 // this will require two passes
385
386 unsigned int m = static_cast<unsigned int>(pNode->mNumMeshes), n = static_cast<unsigned int>(mSubMeshIndices.size());
387
388 // first pass, look for meshes which have not moved
389
390 for(unsigned int a=0;a<m;a++) {
391
392 unsigned int srcIndex = pNode->mMeshes[a];
393 const std::vector< std::pair< unsigned int,aiNode* > > &subMeshes = mSubMeshIndices[srcIndex];
394 unsigned int nSubmeshes = static_cast<unsigned int>(subMeshes.size());
395
396 for(unsigned int b=0;b<nSubmeshes;b++) {
397 if(!subMeshes[b].second) {
398 newMeshList.push_back(subMeshes[b].first);
399 }
400 }
401 }
402
403 // second pass, collect deboned meshes
404
405 for(unsigned int a=0;a<n;a++)
406 {
407 const std::vector< std::pair< unsigned int,aiNode* > > &subMeshes = mSubMeshIndices[a];
408 unsigned int nSubmeshes = static_cast<unsigned int>(subMeshes.size());
409
410 for(unsigned int b=0;b<nSubmeshes;b++) {
411 if(subMeshes[b].second == pNode) {
412 newMeshList.push_back(subMeshes[b].first);
413 }
414 }
415 }
416
417 if( pNode->mNumMeshes > 0 ) {
418 delete [] pNode->mMeshes; pNode->mMeshes = NULL;
419 }
420
421 pNode->mNumMeshes = static_cast<unsigned int>(newMeshList.size());
422
423 if(pNode->mNumMeshes) {
424 pNode->mMeshes = new unsigned int[pNode->mNumMeshes];
425 std::copy( newMeshList.begin(), newMeshList.end(), pNode->mMeshes);
426 }
427
428 // do that also recursively for all children
429 for( unsigned int a = 0; a < pNode->mNumChildren; ++a ) {
430 UpdateNode( pNode->mChildren[a]);
431 }
432}
433
434// ------------------------------------------------------------------------------------------------
435// Apply the node transformation to a mesh
436void DeboneProcess::ApplyTransform(aiMesh* mesh, const aiMatrix4x4& mat)const
437{
438 // Check whether we need to transform the coordinates at all
439 if (!mat.IsIdentity()) {
440
441 if (mesh->HasPositions()) {
442 for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
443 mesh->mVertices[i] = mat * mesh->mVertices[i];
444 }
445 }
446 if (mesh->HasNormals() || mesh->HasTangentsAndBitangents()) {
447 aiMatrix4x4 mWorldIT = mat;
448 mWorldIT.Inverse().Transpose();
449
450 // TODO: implement Inverse() for aiMatrix3x3
451 aiMatrix3x3 m = aiMatrix3x3(mWorldIT);
452
453 if (mesh->HasNormals()) {
454 for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
455 mesh->mNormals[i] = (m * mesh->mNormals[i]).Normalize();
456 }
457 }
458 if (mesh->HasTangentsAndBitangents()) {
459 for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
460 mesh->mTangents[i] = (m * mesh->mTangents[i]).Normalize();
461 mesh->mBitangents[i] = (m * mesh->mBitangents[i]).Normalize();
462 }
463 }
464 }
465 }
466}
467