vrshoot
view libs/assimp/PretransformVertices.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 ---------------------------------------------------------------------------
3 Open Asset Import Library (assimp)
4 ---------------------------------------------------------------------------
6 Copyright (c) 2006-2012, assimp team
8 All rights reserved.
10 Redistribution and use of this software in source and binary forms,
11 with or without modification, are permitted provided that the following
12 conditions are met:
14 * Redistributions of source code must retain the above
15 copyright notice, this list of conditions and the
16 following disclaimer.
18 * Redistributions in binary form must reproduce the above
19 copyright notice, this list of conditions and the
20 following disclaimer in the documentation and/or other
21 materials provided with the distribution.
23 * Neither the name of the assimp team, nor the names of its
24 contributors may be used to endorse or promote products
25 derived from this software without specific prior
26 written permission of the assimp team.
28 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 ---------------------------------------------------------------------------
40 */
42 /** @file PretransformVertices.cpp
43 * @brief Implementation of the "PretransformVertices" post processing step
44 */
46 #include "AssimpPCH.h"
47 #include "PretransformVertices.h"
48 #include "ProcessHelper.h"
49 #include "SceneCombiner.h"
51 using namespace Assimp;
53 // some array offsets
54 #define AI_PTVS_VERTEX 0x0
55 #define AI_PTVS_FACE 0x1
57 // ------------------------------------------------------------------------------------------------
58 // Constructor to be privately used by Importer
59 PretransformVertices::PretransformVertices()
60 : configKeepHierarchy (false)
61 {
62 }
64 // ------------------------------------------------------------------------------------------------
65 // Destructor, private as well
66 PretransformVertices::~PretransformVertices()
67 {
68 // nothing to do here
69 }
71 // ------------------------------------------------------------------------------------------------
72 // Returns whether the processing step is present in the given flag field.
73 bool PretransformVertices::IsActive( unsigned int pFlags) const
74 {
75 return (pFlags & aiProcess_PreTransformVertices) != 0;
76 }
78 // ------------------------------------------------------------------------------------------------
79 // Setup import configuration
80 void PretransformVertices::SetupProperties(const Importer* pImp)
81 {
82 // Get the current value of AI_CONFIG_PP_PTV_KEEP_HIERARCHY and AI_CONFIG_PP_PTV_NORMALIZE
83 configKeepHierarchy = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_KEEP_HIERARCHY,0));
84 configNormalize = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_NORMALIZE,0));
85 }
87 // ------------------------------------------------------------------------------------------------
88 // Count the number of nodes
89 unsigned int PretransformVertices::CountNodes( aiNode* pcNode )
90 {
91 unsigned int iRet = 1;
92 for (unsigned int i = 0;i < pcNode->mNumChildren;++i)
93 {
94 iRet += CountNodes(pcNode->mChildren[i]);
95 }
96 return iRet;
97 }
99 // ------------------------------------------------------------------------------------------------
100 // Get a bitwise combination identifying the vertex format of a mesh
101 unsigned int PretransformVertices::GetMeshVFormat(aiMesh* pcMesh)
102 {
103 // the vertex format is stored in aiMesh::mBones for later retrieval.
104 // there isn't a good reason to compute it a few hundred times
105 // from scratch. The pointer is unused as animations are lost
106 // during PretransformVertices.
107 if (pcMesh->mBones)
108 return (unsigned int)(uint64_t)pcMesh->mBones;
111 const unsigned int iRet = GetMeshVFormatUnique(pcMesh);
113 // store the value for later use
114 pcMesh->mBones = (aiBone**)(uint64_t)iRet;
115 return iRet;
116 }
118 // ------------------------------------------------------------------------------------------------
119 // Count the number of vertices in the whole scene and a given
120 // material index
121 void PretransformVertices::CountVerticesAndFaces( aiScene* pcScene, aiNode* pcNode, unsigned int iMat,
122 unsigned int iVFormat, unsigned int* piFaces, unsigned int* piVertices)
123 {
124 for (unsigned int i = 0; i < pcNode->mNumMeshes;++i)
125 {
126 aiMesh* pcMesh = pcScene->mMeshes[ pcNode->mMeshes[i] ];
127 if (iMat == pcMesh->mMaterialIndex && iVFormat == GetMeshVFormat(pcMesh))
128 {
129 *piVertices += pcMesh->mNumVertices;
130 *piFaces += pcMesh->mNumFaces;
131 }
132 }
133 for (unsigned int i = 0;i < pcNode->mNumChildren;++i)
134 {
135 CountVerticesAndFaces(pcScene,pcNode->mChildren[i],iMat,
136 iVFormat,piFaces,piVertices);
137 }
138 }
140 // ------------------------------------------------------------------------------------------------
141 // Collect vertex/face data
142 void PretransformVertices::CollectData( aiScene* pcScene, aiNode* pcNode, unsigned int iMat,
143 unsigned int iVFormat, aiMesh* pcMeshOut,
144 unsigned int aiCurrent[2], unsigned int* num_refs)
145 {
146 // No need to multiply if there's no transformation
147 const bool identity = pcNode->mTransformation.IsIdentity();
148 for (unsigned int i = 0; i < pcNode->mNumMeshes;++i)
149 {
150 aiMesh* pcMesh = pcScene->mMeshes[ pcNode->mMeshes[i] ];
151 if (iMat == pcMesh->mMaterialIndex && iVFormat == GetMeshVFormat(pcMesh))
152 {
153 // Decrement mesh reference counter
154 unsigned int& num_ref = num_refs[pcNode->mMeshes[i]];
155 ai_assert(0 != num_ref);
156 --num_ref;
158 if (identity) {
159 // copy positions without modifying them
160 ::memcpy(pcMeshOut->mVertices + aiCurrent[AI_PTVS_VERTEX],
161 pcMesh->mVertices,
162 pcMesh->mNumVertices * sizeof(aiVector3D));
164 if (iVFormat & 0x2) {
165 // copy normals without modifying them
166 ::memcpy(pcMeshOut->mNormals + aiCurrent[AI_PTVS_VERTEX],
167 pcMesh->mNormals,
168 pcMesh->mNumVertices * sizeof(aiVector3D));
169 }
170 if (iVFormat & 0x4)
171 {
172 // copy tangents without modifying them
173 ::memcpy(pcMeshOut->mTangents + aiCurrent[AI_PTVS_VERTEX],
174 pcMesh->mTangents,
175 pcMesh->mNumVertices * sizeof(aiVector3D));
176 // copy bitangents without modifying them
177 ::memcpy(pcMeshOut->mBitangents + aiCurrent[AI_PTVS_VERTEX],
178 pcMesh->mBitangents,
179 pcMesh->mNumVertices * sizeof(aiVector3D));
180 }
181 }
182 else
183 {
184 // copy positions, transform them to worldspace
185 for (unsigned int n = 0; n < pcMesh->mNumVertices;++n) {
186 pcMeshOut->mVertices[aiCurrent[AI_PTVS_VERTEX]+n] = pcNode->mTransformation * pcMesh->mVertices[n];
187 }
188 aiMatrix4x4 mWorldIT = pcNode->mTransformation;
189 mWorldIT.Inverse().Transpose();
191 // TODO: implement Inverse() for aiMatrix3x3
192 aiMatrix3x3 m = aiMatrix3x3(mWorldIT);
194 if (iVFormat & 0x2)
195 {
196 // copy normals, transform them to worldspace
197 for (unsigned int n = 0; n < pcMesh->mNumVertices;++n) {
198 pcMeshOut->mNormals[aiCurrent[AI_PTVS_VERTEX]+n] =
199 (m * pcMesh->mNormals[n]).Normalize();
200 }
201 }
202 if (iVFormat & 0x4)
203 {
204 // copy tangents and bitangents, transform them to worldspace
205 for (unsigned int n = 0; n < pcMesh->mNumVertices;++n) {
206 pcMeshOut->mTangents [aiCurrent[AI_PTVS_VERTEX]+n] = (m * pcMesh->mTangents[n]).Normalize();
207 pcMeshOut->mBitangents[aiCurrent[AI_PTVS_VERTEX]+n] = (m * pcMesh->mBitangents[n]).Normalize();
208 }
209 }
210 }
211 unsigned int p = 0;
212 while (iVFormat & (0x100 << p))
213 {
214 // copy texture coordinates
215 memcpy(pcMeshOut->mTextureCoords[p] + aiCurrent[AI_PTVS_VERTEX],
216 pcMesh->mTextureCoords[p],
217 pcMesh->mNumVertices * sizeof(aiVector3D));
218 ++p;
219 }
220 p = 0;
221 while (iVFormat & (0x1000000 << p))
222 {
223 // copy vertex colors
224 memcpy(pcMeshOut->mColors[p] + aiCurrent[AI_PTVS_VERTEX],
225 pcMesh->mColors[p],
226 pcMesh->mNumVertices * sizeof(aiColor4D));
227 ++p;
228 }
229 // now we need to copy all faces. since we will delete the source mesh afterwards,
230 // we don't need to reallocate the array of indices except if this mesh is
231 // referenced multiple times.
232 for (unsigned int planck = 0;planck < pcMesh->mNumFaces;++planck)
233 {
234 aiFace& f_src = pcMesh->mFaces[planck];
235 aiFace& f_dst = pcMeshOut->mFaces[aiCurrent[AI_PTVS_FACE]+planck];
237 const unsigned int num_idx = f_src.mNumIndices;
239 f_dst.mNumIndices = num_idx;
241 unsigned int* pi;
242 if (!num_ref) { /* if last time the mesh is referenced -> no reallocation */
243 pi = f_dst.mIndices = f_src.mIndices;
245 // offset all vertex indices
246 for (unsigned int hahn = 0; hahn < num_idx;++hahn){
247 pi[hahn] += aiCurrent[AI_PTVS_VERTEX];
248 }
249 }
250 else {
251 pi = f_dst.mIndices = new unsigned int[num_idx];
253 // copy and offset all vertex indices
254 for (unsigned int hahn = 0; hahn < num_idx;++hahn){
255 pi[hahn] = f_src.mIndices[hahn] + aiCurrent[AI_PTVS_VERTEX];
256 }
257 }
259 // Update the mPrimitiveTypes member of the mesh
260 switch (pcMesh->mFaces[planck].mNumIndices)
261 {
262 case 0x1:
263 pcMeshOut->mPrimitiveTypes |= aiPrimitiveType_POINT;
264 break;
265 case 0x2:
266 pcMeshOut->mPrimitiveTypes |= aiPrimitiveType_LINE;
267 break;
268 case 0x3:
269 pcMeshOut->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
270 break;
271 default:
272 pcMeshOut->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
273 break;
274 };
275 }
276 aiCurrent[AI_PTVS_VERTEX] += pcMesh->mNumVertices;
277 aiCurrent[AI_PTVS_FACE] += pcMesh->mNumFaces;
278 }
279 }
281 // append all children of us
282 for (unsigned int i = 0;i < pcNode->mNumChildren;++i) {
283 CollectData(pcScene,pcNode->mChildren[i],iMat,
284 iVFormat,pcMeshOut,aiCurrent,num_refs);
285 }
286 }
288 // ------------------------------------------------------------------------------------------------
289 // Get a list of all vertex formats that occur for a given material index
290 // The output list contains duplicate elements
291 void PretransformVertices::GetVFormatList( aiScene* pcScene, unsigned int iMat,
292 std::list<unsigned int>& aiOut)
293 {
294 for (unsigned int i = 0; i < pcScene->mNumMeshes;++i)
295 {
296 aiMesh* pcMesh = pcScene->mMeshes[ i ];
297 if (iMat == pcMesh->mMaterialIndex) {
298 aiOut.push_back(GetMeshVFormat(pcMesh));
299 }
300 }
301 }
303 // ------------------------------------------------------------------------------------------------
304 // Compute the absolute transformation matrices of each node
305 void PretransformVertices::ComputeAbsoluteTransform( aiNode* pcNode )
306 {
307 if (pcNode->mParent) {
308 pcNode->mTransformation = pcNode->mParent->mTransformation*pcNode->mTransformation;
309 }
311 for (unsigned int i = 0;i < pcNode->mNumChildren;++i) {
312 ComputeAbsoluteTransform(pcNode->mChildren[i]);
313 }
314 }
316 // ------------------------------------------------------------------------------------------------
317 // Apply the node transformation to a mesh
318 void PretransformVertices::ApplyTransform(aiMesh* mesh, const aiMatrix4x4& mat)
319 {
320 // Check whether we need to transform the coordinates at all
321 if (!mat.IsIdentity()) {
323 if (mesh->HasPositions()) {
324 for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
325 mesh->mVertices[i] = mat * mesh->mVertices[i];
326 }
327 }
328 if (mesh->HasNormals() || mesh->HasTangentsAndBitangents()) {
329 aiMatrix4x4 mWorldIT = mat;
330 mWorldIT.Inverse().Transpose();
332 // TODO: implement Inverse() for aiMatrix3x3
333 aiMatrix3x3 m = aiMatrix3x3(mWorldIT);
335 if (mesh->HasNormals()) {
336 for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
337 mesh->mNormals[i] = (m * mesh->mNormals[i]).Normalize();
338 }
339 }
340 if (mesh->HasTangentsAndBitangents()) {
341 for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
342 mesh->mTangents[i] = (m * mesh->mTangents[i]).Normalize();
343 mesh->mBitangents[i] = (m * mesh->mBitangents[i]).Normalize();
344 }
345 }
346 }
347 }
348 }
350 // ------------------------------------------------------------------------------------------------
351 // Simple routine to build meshes in worldspace, no further optimization
352 void PretransformVertices::BuildWCSMeshes(std::vector<aiMesh*>& out, aiMesh** in,
353 unsigned int numIn, aiNode* node)
354 {
355 // NOTE:
356 // aiMesh::mNumBones store original source mesh, or UINT_MAX if not a copy
357 // aiMesh::mBones store reference to abs. transform we multiplied with
359 // process meshes
360 for (unsigned int i = 0; i < node->mNumMeshes;++i) {
361 aiMesh* mesh = in[node->mMeshes[i]];
363 // check whether we can operate on this mesh
364 if (!mesh->mBones || *reinterpret_cast<aiMatrix4x4*>(mesh->mBones) == node->mTransformation) {
365 // yes, we can.
366 mesh->mBones = reinterpret_cast<aiBone**> (&node->mTransformation);
367 mesh->mNumBones = UINT_MAX;
368 }
369 else {
371 // try to find us in the list of newly created meshes
372 for (unsigned int n = 0; n < out.size(); ++n) {
373 aiMesh* ctz = out[n];
374 if (ctz->mNumBones == node->mMeshes[i] && *reinterpret_cast<aiMatrix4x4*>(ctz->mBones) == node->mTransformation) {
376 // ok, use this one. Update node mesh index
377 node->mMeshes[i] = numIn + n;
378 }
379 }
380 if (node->mMeshes[i] < numIn) {
381 // Worst case. Need to operate on a full copy of the mesh
382 DefaultLogger::get()->info("PretransformVertices: Copying mesh due to mismatching transforms");
383 aiMesh* ntz;
385 const unsigned int tmp = mesh->mNumBones; //
386 mesh->mNumBones = 0;
387 SceneCombiner::Copy(&ntz,mesh);
388 mesh->mNumBones = tmp;
390 ntz->mNumBones = node->mMeshes[i];
391 ntz->mBones = reinterpret_cast<aiBone**> (&node->mTransformation);
393 out.push_back(ntz);
394 }
395 }
396 }
398 // call children
399 for (unsigned int i = 0; i < node->mNumChildren;++i)
400 BuildWCSMeshes(out,in,numIn,node->mChildren[i]);
401 }
403 // ------------------------------------------------------------------------------------------------
404 // Reset transformation matrices to identity
405 void PretransformVertices::MakeIdentityTransform(aiNode* nd)
406 {
407 nd->mTransformation = aiMatrix4x4();
409 // call children
410 for (unsigned int i = 0; i < nd->mNumChildren;++i)
411 MakeIdentityTransform(nd->mChildren[i]);
412 }
414 // ------------------------------------------------------------------------------------------------
415 // Build reference counters for all meshes
416 void PretransformVertices::BuildMeshRefCountArray(aiNode* nd, unsigned int * refs)
417 {
418 for (unsigned int i = 0; i< nd->mNumMeshes;++i)
419 refs[nd->mMeshes[i]]++;
421 // call children
422 for (unsigned int i = 0; i < nd->mNumChildren;++i)
423 BuildMeshRefCountArray(nd->mChildren[i],refs);
424 }
426 // ------------------------------------------------------------------------------------------------
427 // Executes the post processing step on the given imported data.
428 void PretransformVertices::Execute( aiScene* pScene)
429 {
430 DefaultLogger::get()->debug("PretransformVerticesProcess begin");
432 // Return immediately if we have no meshes
433 if (!pScene->mNumMeshes)
434 return;
436 const unsigned int iOldMeshes = pScene->mNumMeshes;
437 const unsigned int iOldAnimationChannels = pScene->mNumAnimations;
438 const unsigned int iOldNodes = CountNodes(pScene->mRootNode);
440 // first compute absolute transformation matrices for all nodes
441 ComputeAbsoluteTransform(pScene->mRootNode);
443 // Delete aiMesh::mBones for all meshes. The bones are
444 // removed during this step and we need the pointer as
445 // temporary storage
446 for (unsigned int i = 0; i < pScene->mNumMeshes;++i) {
447 aiMesh* mesh = pScene->mMeshes[i];
449 for (unsigned int a = 0; a < mesh->mNumBones;++a)
450 delete mesh->mBones[a];
452 delete[] mesh->mBones;
453 mesh->mBones = NULL;
454 }
456 // now build a list of output meshes
457 std::vector<aiMesh*> apcOutMeshes;
459 // Keep scene hierarchy? It's an easy job in this case ...
460 // we go on and transform all meshes, if one is referenced by nodes
461 // with different absolute transformations a depth copy of the mesh
462 // is required.
463 if( configKeepHierarchy ) {
465 // Hack: store the matrix we're transforming a mesh with in aiMesh::mBones
466 BuildWCSMeshes(apcOutMeshes,pScene->mMeshes,pScene->mNumMeshes, pScene->mRootNode);
468 // ... if new meshes have been generated, append them to the end of the scene
469 if (apcOutMeshes.size() > 0) {
470 aiMesh** npp = new aiMesh*[pScene->mNumMeshes + apcOutMeshes.size()];
472 memcpy(npp,pScene->mMeshes,sizeof(aiMesh*)*pScene->mNumMeshes);
473 memcpy(npp+pScene->mNumMeshes,&apcOutMeshes[0],sizeof(aiMesh*)*apcOutMeshes.size());
475 pScene->mNumMeshes += apcOutMeshes.size();
476 delete[] pScene->mMeshes; pScene->mMeshes = npp;
477 }
479 // now iterate through all meshes and transform them to worldspace
480 for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
481 ApplyTransform(pScene->mMeshes[i],*reinterpret_cast<aiMatrix4x4*>( pScene->mMeshes[i]->mBones ));
483 // prevent improper destruction
484 pScene->mMeshes[i]->mBones = NULL;
485 pScene->mMeshes[i]->mNumBones = 0;
486 }
487 }
488 else {
490 apcOutMeshes.reserve(pScene->mNumMaterials<<1u);
491 std::list<unsigned int> aiVFormats;
493 std::vector<unsigned int> s(pScene->mNumMeshes,0);
494 BuildMeshRefCountArray(pScene->mRootNode,&s[0]);
496 for (unsigned int i = 0; i < pScene->mNumMaterials;++i) {
497 // get the list of all vertex formats for this material
498 aiVFormats.clear();
499 GetVFormatList(pScene,i,aiVFormats);
500 aiVFormats.sort();
501 aiVFormats.unique();
502 for (std::list<unsigned int>::const_iterator j = aiVFormats.begin();j != aiVFormats.end();++j) {
503 unsigned int iVertices = 0;
504 unsigned int iFaces = 0;
505 CountVerticesAndFaces(pScene,pScene->mRootNode,i,*j,&iFaces,&iVertices);
506 if (0 != iFaces && 0 != iVertices)
507 {
508 apcOutMeshes.push_back(new aiMesh());
509 aiMesh* pcMesh = apcOutMeshes.back();
510 pcMesh->mNumFaces = iFaces;
511 pcMesh->mNumVertices = iVertices;
512 pcMesh->mFaces = new aiFace[iFaces];
513 pcMesh->mVertices = new aiVector3D[iVertices];
514 pcMesh->mMaterialIndex = i;
515 if ((*j) & 0x2)pcMesh->mNormals = new aiVector3D[iVertices];
516 if ((*j) & 0x4)
517 {
518 pcMesh->mTangents = new aiVector3D[iVertices];
519 pcMesh->mBitangents = new aiVector3D[iVertices];
520 }
521 iFaces = 0;
522 while ((*j) & (0x100 << iFaces))
523 {
524 pcMesh->mTextureCoords[iFaces] = new aiVector3D[iVertices];
525 if ((*j) & (0x10000 << iFaces))pcMesh->mNumUVComponents[iFaces] = 3;
526 else pcMesh->mNumUVComponents[iFaces] = 2;
527 iFaces++;
528 }
529 iFaces = 0;
530 while ((*j) & (0x1000000 << iFaces))
531 pcMesh->mColors[iFaces++] = new aiColor4D[iVertices];
533 // fill the mesh ...
534 unsigned int aiTemp[2] = {0,0};
535 CollectData(pScene,pScene->mRootNode,i,*j,pcMesh,aiTemp,&s[0]);
536 }
537 }
538 }
540 // If no meshes are referenced in the node graph it is possible that we get no output meshes.
541 if (apcOutMeshes.empty()) {
542 throw DeadlyImportError("No output meshes: all meshes are orphaned and are not referenced by any nodes");
543 }
544 else
545 {
546 // now delete all meshes in the scene and build a new mesh list
547 for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
548 {
549 aiMesh* mesh = pScene->mMeshes[i];
550 mesh->mNumBones = 0;
551 mesh->mBones = NULL;
553 // we're reusing the face index arrays. avoid destruction
554 for (unsigned int a = 0; a < mesh->mNumFaces; ++a) {
555 mesh->mFaces[a].mNumIndices = 0;
556 mesh->mFaces[a].mIndices = NULL;
557 }
559 delete mesh;
561 // Invalidate the contents of the old mesh array. We will most
562 // likely have less output meshes now, so the last entries of
563 // the mesh array are not overridden. We set them to NULL to
564 // make sure the developer gets notified when his application
565 // attempts to access these fields ...
566 mesh = NULL;
567 }
569 // It is impossible that we have more output meshes than
570 // input meshes, so we can easily reuse the old mesh array
571 pScene->mNumMeshes = (unsigned int)apcOutMeshes.size();
572 for (unsigned int i = 0; i < pScene->mNumMeshes;++i) {
573 pScene->mMeshes[i] = apcOutMeshes[i];
574 }
575 }
576 }
578 // remove all animations from the scene
579 for (unsigned int i = 0; i < pScene->mNumAnimations;++i)
580 delete pScene->mAnimations[i];
581 delete[] pScene->mAnimations;
583 pScene->mAnimations = NULL;
584 pScene->mNumAnimations = 0;
586 // --- we need to keep all cameras and lights
587 for (unsigned int i = 0; i < pScene->mNumCameras;++i)
588 {
589 aiCamera* cam = pScene->mCameras[i];
590 const aiNode* nd = pScene->mRootNode->FindNode(cam->mName);
591 ai_assert(NULL != nd);
593 // multiply all properties of the camera with the absolute
594 // transformation of the corresponding node
595 cam->mPosition = nd->mTransformation * cam->mPosition;
596 cam->mLookAt = aiMatrix3x3( nd->mTransformation ) * cam->mLookAt;
597 cam->mUp = aiMatrix3x3( nd->mTransformation ) * cam->mUp;
598 }
600 for (unsigned int i = 0; i < pScene->mNumLights;++i)
601 {
602 aiLight* l = pScene->mLights[i];
603 const aiNode* nd = pScene->mRootNode->FindNode(l->mName);
604 ai_assert(NULL != nd);
606 // multiply all properties of the camera with the absolute
607 // transformation of the corresponding node
608 l->mPosition = nd->mTransformation * l->mPosition;
609 l->mDirection = aiMatrix3x3( nd->mTransformation ) * l->mDirection;
610 }
612 if( !configKeepHierarchy ) {
614 // now delete all nodes in the scene and build a new
615 // flat node graph with a root node and some level 1 children
616 delete pScene->mRootNode;
617 pScene->mRootNode = new aiNode();
618 pScene->mRootNode->mName.Set("<dummy_root>");
620 if (1 == pScene->mNumMeshes && !pScene->mNumLights && !pScene->mNumCameras)
621 {
622 pScene->mRootNode->mNumMeshes = 1;
623 pScene->mRootNode->mMeshes = new unsigned int[1];
624 pScene->mRootNode->mMeshes[0] = 0;
625 }
626 else
627 {
628 pScene->mRootNode->mNumChildren = pScene->mNumMeshes+pScene->mNumLights+pScene->mNumCameras;
629 aiNode** nodes = pScene->mRootNode->mChildren = new aiNode*[pScene->mRootNode->mNumChildren];
631 // generate mesh nodes
632 for (unsigned int i = 0; i < pScene->mNumMeshes;++i,++nodes)
633 {
634 aiNode* pcNode = *nodes = new aiNode();
635 pcNode->mParent = pScene->mRootNode;
636 pcNode->mName.length = ::sprintf(pcNode->mName.data,"mesh_%i",i);
638 // setup mesh indices
639 pcNode->mNumMeshes = 1;
640 pcNode->mMeshes = new unsigned int[1];
641 pcNode->mMeshes[0] = i;
642 }
643 // generate light nodes
644 for (unsigned int i = 0; i < pScene->mNumLights;++i,++nodes)
645 {
646 aiNode* pcNode = *nodes = new aiNode();
647 pcNode->mParent = pScene->mRootNode;
648 pcNode->mName.length = ::sprintf(pcNode->mName.data,"light_%i",i);
649 pScene->mLights[i]->mName = pcNode->mName;
650 }
651 // generate camera nodes
652 for (unsigned int i = 0; i < pScene->mNumCameras;++i,++nodes)
653 {
654 aiNode* pcNode = *nodes = new aiNode();
655 pcNode->mParent = pScene->mRootNode;
656 pcNode->mName.length = ::sprintf(pcNode->mName.data,"cam_%i",i);
657 pScene->mCameras[i]->mName = pcNode->mName;
658 }
659 }
660 }
661 else {
662 // ... and finally set the transformation matrix of all nodes to identity
663 MakeIdentityTransform(pScene->mRootNode);
664 }
666 if (configNormalize) {
667 // compute the boundary of all meshes
668 aiVector3D min,max;
669 MinMaxChooser<aiVector3D> ()(min,max);
671 for (unsigned int a = 0; a < pScene->mNumMeshes; ++a) {
672 aiMesh* m = pScene->mMeshes[a];
673 for (unsigned int i = 0; i < m->mNumVertices;++i) {
674 min = std::min(m->mVertices[i],min);
675 max = std::max(m->mVertices[i],max);
676 }
677 }
679 // find the dominant axis
680 aiVector3D d = max-min;
681 const float div = std::max(d.x,std::max(d.y,d.z))*0.5f;
683 d = min+d*0.5f;
684 for (unsigned int a = 0; a < pScene->mNumMeshes; ++a) {
685 aiMesh* m = pScene->mMeshes[a];
686 for (unsigned int i = 0; i < m->mNumVertices;++i) {
687 m->mVertices[i] = (m->mVertices[i]-d)/div;
688 }
689 }
690 }
692 // print statistics
693 if (!DefaultLogger::isNullLogger())
694 {
695 char buffer[4096];
697 DefaultLogger::get()->debug("PretransformVerticesProcess finished");
699 sprintf(buffer,"Removed %i nodes and %i animation channels (%i output nodes)",
700 iOldNodes,iOldAnimationChannels,CountNodes(pScene->mRootNode));
701 DefaultLogger::get()->info(buffer);
703 sprintf(buffer,"Kept %i lights and %i cameras",
704 pScene->mNumLights,pScene->mNumCameras);
705 DefaultLogger::get()->info(buffer);
707 sprintf(buffer,"Moved %i meshes to WCS (number of output meshes: %i)",
708 iOldMeshes,pScene->mNumMeshes);
709 DefaultLogger::get()->info(buffer);
710 }
711 }