vrshoot

view libs/assimp/DeboneProcess.cpp @ 0:b2f14e535253

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