vrshoot

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