vrshoot
diff 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 diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/libs/assimp/DeboneProcess.cpp Sat Feb 01 19:58:19 2014 +0200 1.3 @@ -0,0 +1,464 @@ 1.4 + /* 1.5 +Open Asset Import Library (assimp) 1.6 +---------------------------------------------------------------------- 1.7 + 1.8 +Copyright (c) 2006-2012, assimp team 1.9 +All rights reserved. 1.10 + 1.11 +Redistribution and use of this software in source and binary forms, 1.12 +with or without modification, are permitted provided that the 1.13 +following conditions are met: 1.14 + 1.15 +* Redistributions of source code must retain the above 1.16 + copyright notice, this list of conditions and the 1.17 + following disclaimer. 1.18 + 1.19 +* Redistributions in binary form must reproduce the above 1.20 + copyright notice, this list of conditions and the 1.21 + following disclaimer in the documentation and/or other 1.22 + materials provided with the distribution. 1.23 + 1.24 +* Neither the name of the assimp team, nor the names of its 1.25 + contributors may be used to endorse or promote products 1.26 + derived from this software without specific prior 1.27 + written permission of the assimp team. 1.28 + 1.29 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.30 +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1.31 +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1.32 +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1.33 +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1.34 +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 1.35 +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.36 +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.37 +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.38 +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 1.39 +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.40 + 1.41 +---------------------------------------------------------------------- 1.42 +*/ 1.43 + 1.44 +/// @file DeboneProcess.cpp 1.45 +/** Implementation of the DeboneProcess post processing step */ 1.46 + 1.47 +#include "AssimpPCH.h" 1.48 + 1.49 +// internal headers of the post-processing framework 1.50 +#include "ProcessHelper.h" 1.51 +#include "DeboneProcess.h" 1.52 + 1.53 + 1.54 +using namespace Assimp; 1.55 + 1.56 +// ------------------------------------------------------------------------------------------------ 1.57 +// Constructor to be privately used by Importer 1.58 +DeboneProcess::DeboneProcess() 1.59 +{ 1.60 + mNumBones = 0; 1.61 + mNumBonesCanDoWithout = 0; 1.62 + 1.63 + mThreshold = AI_DEBONE_THRESHOLD; 1.64 + mAllOrNone = false; 1.65 +} 1.66 + 1.67 +// ------------------------------------------------------------------------------------------------ 1.68 +// Destructor, private as well 1.69 +DeboneProcess::~DeboneProcess() 1.70 +{ 1.71 + // nothing to do here 1.72 +} 1.73 + 1.74 +// ------------------------------------------------------------------------------------------------ 1.75 +// Returns whether the processing step is present in the given flag field. 1.76 +bool DeboneProcess::IsActive( unsigned int pFlags) const 1.77 +{ 1.78 + return (pFlags & aiProcess_Debone) != 0; 1.79 +} 1.80 + 1.81 +// ------------------------------------------------------------------------------------------------ 1.82 +// Executes the post processing step on the given imported data. 1.83 +void DeboneProcess::SetupProperties(const Importer* pImp) 1.84 +{ 1.85 + // get the current value of the property 1.86 + mAllOrNone = pImp->GetPropertyInteger(AI_CONFIG_PP_DB_ALL_OR_NONE,0)?true:false; 1.87 + mThreshold = pImp->GetPropertyFloat(AI_CONFIG_PP_DB_THRESHOLD,AI_DEBONE_THRESHOLD); 1.88 +} 1.89 + 1.90 +// ------------------------------------------------------------------------------------------------ 1.91 +// Executes the post processing step on the given imported data. 1.92 +void DeboneProcess::Execute( aiScene* pScene) 1.93 +{ 1.94 + DefaultLogger::get()->debug("DeboneProcess begin"); 1.95 + 1.96 + if(!pScene->mNumMeshes) { 1.97 + return; 1.98 + } 1.99 + 1.100 + std::vector<bool> splitList(pScene->mNumMeshes); 1.101 + for( unsigned int a = 0; a < pScene->mNumMeshes; a++) { 1.102 + splitList[a] = ConsiderMesh( pScene->mMeshes[a] ); 1.103 + } 1.104 + 1.105 + int numSplits = 0; 1.106 + 1.107 + if(!!mNumBonesCanDoWithout && (!mAllOrNone||mNumBonesCanDoWithout==mNumBones)) { 1.108 + for(unsigned int a = 0; a < pScene->mNumMeshes; a++) { 1.109 + if(splitList[a]) { 1.110 + numSplits++; 1.111 + } 1.112 + } 1.113 + } 1.114 + 1.115 + if(numSplits) { 1.116 + // we need to do something. Let's go. 1.117 + mSubMeshIndices.clear(); 1.118 + mSubMeshIndices.resize(pScene->mNumMeshes); 1.119 + 1.120 + // build a new array of meshes for the scene 1.121 + std::vector<aiMesh*> meshes; 1.122 + 1.123 + for(unsigned int a=0;a<pScene->mNumMeshes;a++) 1.124 + { 1.125 + aiMesh* srcMesh = pScene->mMeshes[a]; 1.126 + 1.127 + std::vector<std::pair<aiMesh*,const aiBone*> > newMeshes; 1.128 + 1.129 + if(splitList[a]) { 1.130 + SplitMesh(srcMesh,newMeshes); 1.131 + } 1.132 + 1.133 + // mesh was split 1.134 + if(!newMeshes.empty()) { 1.135 + unsigned int out = 0, in = srcMesh->mNumBones; 1.136 + 1.137 + // store new meshes and indices of the new meshes 1.138 + for(unsigned int b=0;b<newMeshes.size();b++) { 1.139 + const aiString *find = newMeshes[b].second?&newMeshes[b].second->mName:0; 1.140 + 1.141 + aiNode *theNode = find?pScene->mRootNode->FindNode(*find):0; 1.142 + std::pair<unsigned int,aiNode*> push_pair(meshes.size(),theNode); 1.143 + 1.144 + mSubMeshIndices[a].push_back(push_pair); 1.145 + meshes.push_back(newMeshes[b].first); 1.146 + 1.147 + out+=newMeshes[b].first->mNumBones; 1.148 + } 1.149 + 1.150 + if(!DefaultLogger::isNullLogger()) { 1.151 + char buffer[1024]; 1.152 + ::sprintf(buffer,"Removed %i bones. Input bones: %i. Output bones: %i",in-out,in,out); 1.153 + DefaultLogger::get()->info(buffer); 1.154 + } 1.155 + 1.156 + // and destroy the source mesh. It should be completely contained inside the new submeshes 1.157 + delete srcMesh; 1.158 + } 1.159 + else { 1.160 + // Mesh is kept unchanged - store it's new place in the mesh array 1.161 + mSubMeshIndices[a].push_back(std::pair<unsigned int,aiNode*>(meshes.size(),(aiNode*)0)); 1.162 + meshes.push_back(srcMesh); 1.163 + } 1.164 + } 1.165 + 1.166 + // rebuild the scene's mesh array 1.167 + pScene->mNumMeshes = meshes.size(); 1.168 + delete [] pScene->mMeshes; 1.169 + pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]; 1.170 + std::copy( meshes.begin(), meshes.end(), pScene->mMeshes); 1.171 + 1.172 + // recurse through all nodes and translate the node's mesh indices to fit the new mesh array 1.173 + UpdateNode( pScene->mRootNode); 1.174 + } 1.175 + 1.176 + DefaultLogger::get()->debug("DeboneProcess end"); 1.177 +} 1.178 + 1.179 +// ------------------------------------------------------------------------------------------------ 1.180 +// Counts bones total/removable in a given mesh. 1.181 +bool DeboneProcess::ConsiderMesh(const aiMesh* pMesh) 1.182 +{ 1.183 + if(!pMesh->HasBones()) { 1.184 + return false; 1.185 + } 1.186 + 1.187 + bool split = false; 1.188 + 1.189 + //interstitial faces not permitted 1.190 + bool isInterstitialRequired = false; 1.191 + 1.192 + std::vector<bool> isBoneNecessary(pMesh->mNumBones,false); 1.193 + std::vector<unsigned int> vertexBones(pMesh->mNumVertices,UINT_MAX); 1.194 + 1.195 + const unsigned int cUnowned = UINT_MAX; 1.196 + const unsigned int cCoowned = UINT_MAX-1; 1.197 + 1.198 + for(unsigned int i=0;i<pMesh->mNumBones;i++) { 1.199 + for(unsigned int j=0;j<pMesh->mBones[i]->mNumWeights;j++) { 1.200 + float w = pMesh->mBones[i]->mWeights[j].mWeight; 1.201 + 1.202 + if(w==0.0f) { 1.203 + continue; 1.204 + } 1.205 + 1.206 + unsigned int vid = pMesh->mBones[i]->mWeights[j].mVertexId; 1.207 + if(w>=mThreshold) { 1.208 + 1.209 + if(vertexBones[vid]!=cUnowned) { 1.210 + if(vertexBones[vid]==i) //double entry 1.211 + { 1.212 + DefaultLogger::get()->warn("Encountered double entry in bone weights"); 1.213 + } 1.214 + else //TODO: track attraction in order to break tie 1.215 + { 1.216 + vertexBones[vid] = cCoowned; 1.217 + } 1.218 + } 1.219 + else vertexBones[vid] = i; 1.220 + } 1.221 + 1.222 + if(!isBoneNecessary[i]) { 1.223 + isBoneNecessary[i] = w<mThreshold; 1.224 + } 1.225 + } 1.226 + 1.227 + if(!isBoneNecessary[i]) { 1.228 + isInterstitialRequired = true; 1.229 + } 1.230 + } 1.231 + 1.232 + if(isInterstitialRequired) { 1.233 + for(unsigned int i=0;i<pMesh->mNumFaces;i++) { 1.234 + unsigned int v = vertexBones[pMesh->mFaces[i].mIndices[0]]; 1.235 + 1.236 + for(unsigned int j=1;j<pMesh->mFaces[i].mNumIndices;j++) { 1.237 + unsigned int w = vertexBones[pMesh->mFaces[i].mIndices[j]]; 1.238 + 1.239 + if(v!=w) { 1.240 + if(v<pMesh->mNumBones) isBoneNecessary[v] = true; 1.241 + if(w<pMesh->mNumBones) isBoneNecessary[w] = true; 1.242 + } 1.243 + } 1.244 + } 1.245 + } 1.246 + 1.247 + for(unsigned int i=0;i<pMesh->mNumBones;i++) { 1.248 + if(!isBoneNecessary[i]) { 1.249 + mNumBonesCanDoWithout++; 1.250 + split = true; 1.251 + } 1.252 + 1.253 + mNumBones++; 1.254 + } 1.255 + return split; 1.256 +} 1.257 + 1.258 +// ------------------------------------------------------------------------------------------------ 1.259 +// Splits the given mesh by bone count. 1.260 +void DeboneProcess::SplitMesh( const aiMesh* pMesh, std::vector< std::pair< aiMesh*,const aiBone* > >& poNewMeshes) const 1.261 +{ 1.262 + // same deal here as ConsiderMesh basically 1.263 + 1.264 + std::vector<bool> isBoneNecessary(pMesh->mNumBones,false); 1.265 + std::vector<unsigned int> vertexBones(pMesh->mNumVertices,UINT_MAX); 1.266 + 1.267 + const unsigned int cUnowned = UINT_MAX; 1.268 + const unsigned int cCoowned = UINT_MAX-1; 1.269 + 1.270 + for(unsigned int i=0;i<pMesh->mNumBones;i++) { 1.271 + for(unsigned int j=0;j<pMesh->mBones[i]->mNumWeights;j++) { 1.272 + float w = pMesh->mBones[i]->mWeights[j].mWeight; 1.273 + 1.274 + if(w==0.0f) { 1.275 + continue; 1.276 + } 1.277 + 1.278 + unsigned int vid = pMesh->mBones[i]->mWeights[j].mVertexId; 1.279 + 1.280 + if(w>=mThreshold) { 1.281 + if(vertexBones[vid]!=cUnowned) { 1.282 + if(vertexBones[vid]==i) //double entry 1.283 + { 1.284 + //DefaultLogger::get()->warn("Encountered double entry in bone weights"); 1.285 + } 1.286 + else //TODO: track attraction in order to break tie 1.287 + { 1.288 + vertexBones[vid] = cCoowned; 1.289 + } 1.290 + } 1.291 + else vertexBones[vid] = i; 1.292 + } 1.293 + 1.294 + if(!isBoneNecessary[i]) { 1.295 + isBoneNecessary[i] = w<mThreshold; 1.296 + } 1.297 + } 1.298 + } 1.299 + 1.300 + unsigned int nFacesUnowned = 0; 1.301 + 1.302 + std::vector<unsigned int> faceBones(pMesh->mNumFaces,UINT_MAX); 1.303 + std::vector<unsigned int> facesPerBone(pMesh->mNumBones,0); 1.304 + 1.305 + for(unsigned int i=0;i<pMesh->mNumFaces;i++) { 1.306 + unsigned int nInterstitial = 1; 1.307 + 1.308 + unsigned int v = vertexBones[pMesh->mFaces[i].mIndices[0]]; 1.309 + 1.310 + for(unsigned int j=1;j<pMesh->mFaces[i].mNumIndices;j++) { 1.311 + unsigned int w = vertexBones[pMesh->mFaces[i].mIndices[j]]; 1.312 + 1.313 + if(v!=w) { 1.314 + if(v<pMesh->mNumBones) isBoneNecessary[v] = true; 1.315 + if(w<pMesh->mNumBones) isBoneNecessary[w] = true; 1.316 + } 1.317 + else nInterstitial++; 1.318 + } 1.319 + 1.320 + if(v<pMesh->mNumBones &&nInterstitial==pMesh->mFaces[i].mNumIndices) { 1.321 + faceBones[i] = v; //primitive belongs to bone #v 1.322 + facesPerBone[v]++; 1.323 + } 1.324 + else nFacesUnowned++; 1.325 + } 1.326 + 1.327 + // invalidate any "cojoined" faces 1.328 + for(unsigned int i=0;i<pMesh->mNumFaces;i++) { 1.329 + if(faceBones[i]<pMesh->mNumBones&&isBoneNecessary[faceBones[i]]) 1.330 + { 1.331 + ai_assert(facesPerBone[faceBones[i]]>0); 1.332 + facesPerBone[faceBones[i]]--; 1.333 + 1.334 + nFacesUnowned++; 1.335 + faceBones[i] = cUnowned; 1.336 + } 1.337 + } 1.338 + 1.339 + if(nFacesUnowned) { 1.340 + std::vector<unsigned int> subFaces; 1.341 + 1.342 + for(unsigned int i=0;i<pMesh->mNumFaces;i++) { 1.343 + if(faceBones[i]==cUnowned) { 1.344 + subFaces.push_back(i); 1.345 + } 1.346 + } 1.347 + 1.348 + aiMesh *baseMesh = MakeSubmesh(pMesh,subFaces,0); 1.349 + std::pair<aiMesh*,const aiBone*> push_pair(baseMesh,(const aiBone*)0); 1.350 + 1.351 + poNewMeshes.push_back(push_pair); 1.352 + } 1.353 + 1.354 + for(unsigned int i=0;i<pMesh->mNumBones;i++) { 1.355 + 1.356 + if(!isBoneNecessary[i]&&facesPerBone[i]>0) { 1.357 + std::vector<unsigned int> subFaces; 1.358 + 1.359 + for(unsigned int j=0;j<pMesh->mNumFaces;j++) { 1.360 + if(faceBones[j]==i) { 1.361 + subFaces.push_back(j); 1.362 + } 1.363 + } 1.364 + 1.365 + unsigned int f = AI_SUBMESH_FLAGS_SANS_BONES; 1.366 + aiMesh *subMesh =MakeSubmesh(pMesh,subFaces,f); 1.367 + 1.368 + //Lifted from PretransformVertices.cpp 1.369 + ApplyTransform(subMesh,pMesh->mBones[i]->mOffsetMatrix); 1.370 + std::pair<aiMesh*,const aiBone*> push_pair(subMesh,pMesh->mBones[i]); 1.371 + 1.372 + poNewMeshes.push_back(push_pair); 1.373 + } 1.374 + } 1.375 +} 1.376 + 1.377 +// ------------------------------------------------------------------------------------------------ 1.378 +// Recursively updates the node's mesh list to account for the changed mesh list 1.379 +void DeboneProcess::UpdateNode(aiNode* pNode) const 1.380 +{ 1.381 + // rebuild the node's mesh index list 1.382 + 1.383 + std::vector<unsigned int> newMeshList; 1.384 + 1.385 + // this will require two passes 1.386 + 1.387 + unsigned int m = pNode->mNumMeshes, n = mSubMeshIndices.size(); 1.388 + 1.389 + // first pass, look for meshes which have not moved 1.390 + 1.391 + for(unsigned int a=0;a<m;a++) { 1.392 + 1.393 + unsigned int srcIndex = pNode->mMeshes[a]; 1.394 + const std::vector< std::pair< unsigned int,aiNode* > > &subMeshes = mSubMeshIndices[srcIndex]; 1.395 + unsigned int nSubmeshes = subMeshes.size(); 1.396 + 1.397 + for(unsigned int b=0;b<nSubmeshes;b++) { 1.398 + if(!subMeshes[b].second) { 1.399 + newMeshList.push_back(subMeshes[b].first); 1.400 + } 1.401 + } 1.402 + } 1.403 + 1.404 + // second pass, collect deboned meshes 1.405 + 1.406 + for(unsigned int a=0;a<n;a++) 1.407 + { 1.408 + const std::vector< std::pair< unsigned int,aiNode* > > &subMeshes = mSubMeshIndices[a]; 1.409 + unsigned int nSubmeshes = subMeshes.size(); 1.410 + 1.411 + for(unsigned int b=0;b<nSubmeshes;b++) { 1.412 + if(subMeshes[b].second == pNode) { 1.413 + newMeshList.push_back(subMeshes[b].first); 1.414 + } 1.415 + } 1.416 + } 1.417 + 1.418 + if( pNode->mNumMeshes > 0 ) { 1.419 + delete [] pNode->mMeshes; pNode->mMeshes = NULL; 1.420 + } 1.421 + 1.422 + pNode->mNumMeshes = newMeshList.size(); 1.423 + 1.424 + if(pNode->mNumMeshes) { 1.425 + pNode->mMeshes = new unsigned int[pNode->mNumMeshes]; 1.426 + std::copy( newMeshList.begin(), newMeshList.end(), pNode->mMeshes); 1.427 + } 1.428 + 1.429 + // do that also recursively for all children 1.430 + for( unsigned int a = 0; a < pNode->mNumChildren; ++a ) { 1.431 + UpdateNode( pNode->mChildren[a]); 1.432 + } 1.433 +} 1.434 + 1.435 +// ------------------------------------------------------------------------------------------------ 1.436 +// Apply the node transformation to a mesh 1.437 +void DeboneProcess::ApplyTransform(aiMesh* mesh, const aiMatrix4x4& mat)const 1.438 +{ 1.439 + // Check whether we need to transform the coordinates at all 1.440 + if (!mat.IsIdentity()) { 1.441 + 1.442 + if (mesh->HasPositions()) { 1.443 + for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { 1.444 + mesh->mVertices[i] = mat * mesh->mVertices[i]; 1.445 + } 1.446 + } 1.447 + if (mesh->HasNormals() || mesh->HasTangentsAndBitangents()) { 1.448 + aiMatrix4x4 mWorldIT = mat; 1.449 + mWorldIT.Inverse().Transpose(); 1.450 + 1.451 + // TODO: implement Inverse() for aiMatrix3x3 1.452 + aiMatrix3x3 m = aiMatrix3x3(mWorldIT); 1.453 + 1.454 + if (mesh->HasNormals()) { 1.455 + for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { 1.456 + mesh->mNormals[i] = (m * mesh->mNormals[i]).Normalize(); 1.457 + } 1.458 + } 1.459 + if (mesh->HasTangentsAndBitangents()) { 1.460 + for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { 1.461 + mesh->mTangents[i] = (m * mesh->mTangents[i]).Normalize(); 1.462 + mesh->mBitangents[i] = (m * mesh->mBitangents[i]).Normalize(); 1.463 + } 1.464 + } 1.465 + } 1.466 + } 1.467 +}