source: trunk/src/formats/assimp_loader.cc @ 292

Last change on this file since 292 was 292, checked in by epyon, 11 years ago
  • nmd_loader now (temporarily) holds nmd dump code
  • image_data now holds pixel format information
  • minor cleanups
File size: 17.2 KB
Line 
1// Copyright (C) 2014 ChaosForge Ltd
2// http://chaosforge.org/
3//
4// This file is part of NV Libraries.
5// For conditions of distribution and use, see copyright notice in nv.hh
6
7#include "nv/formats/assimp_loader.hh"
8#include <unordered_map>
9#include <glm/gtx/transform.hpp>
10#include "nv/io/std_stream.hh"
11#include "nv/lib/assimp.hh"
12
13using namespace nv;
14
15const int MAX_BONES = 64;
16
17struct assimp_key_p  { float time; vec3 position; };
18struct assimp_key_r  { float time; quat rotation; };
19struct assimp_key_s  { float time; vec3 scale; };
20struct assimp_key_tr { transform tform; };
21
22
23nv::assimp_loader::assimp_loader( const string& a_ext, const mat3& a_rotate_transform, float a_scale, bool pre_transform, uint32 a_assimp_flags /*= 0 */ )
24        : m_scene( nullptr ), m_flat( pre_transform ), m_mesh_count(0)
25{
26        initialize( a_ext, a_rotate_transform, a_scale, a_assimp_flags );
27}
28
29nv::assimp_loader::assimp_loader( const string& a_ext, bool pre_transform, uint32 a_assimp_flags /*= 0 */ )
30        : m_scene( nullptr ), m_flat( pre_transform ), m_mesh_count(0)
31{
32        initialize( a_ext, mat3(), 1.0f, a_assimp_flags );
33}
34
35
36void nv::assimp_loader::initialize( const string& a_ext, const mat3& a_rotate_transform, float a_scale, uint32 a_assimp_flags )
37{
38        m_ext   = a_ext;
39        m_r33   = a_rotate_transform;
40        m_ri33  = glm::transpose( m_r33 );
41        m_scale = a_scale;
42        m_assimp_flags = a_assimp_flags;
43        if ( m_assimp_flags == 0 )
44        {
45                m_assimp_flags = (
46                        aiProcess_CalcTangentSpace                              | 
47                        aiProcess_GenSmoothNormals                              | 
48                        aiProcess_JoinIdenticalVertices                 |   
49                        aiProcess_ImproveCacheLocality                  | 
50                        aiProcess_LimitBoneWeights                              | 
51                        aiProcess_RemoveRedundantMaterials      | 
52                        aiProcess_SplitLargeMeshes                              | 
53                        aiProcess_Triangulate                                   | 
54                        aiProcess_GenUVCoords                   | 
55                        aiProcess_SortByPType                   | 
56                        aiProcess_FindDegenerates               | 
57                        aiProcess_FindInvalidData               | 
58                        0 );
59        }
60}
61
62
63bool nv::assimp_loader::load( stream& source )
64{
65        load_assimp_library();
66        if ( m_scene != nullptr ) aiReleaseImport( (const aiScene*)m_scene );
67        m_scene = nullptr;
68        m_mesh_count = 0;
69        NV_LOG( nv::LOG_NOTICE, "AssImp loading file..." );
70        int size = (int)source.size();
71        char* data  = new char[ size ];
72        source.read( data, size, 1 );
73        const aiScene* scene = aiImportFileFromMemory( data, size, m_assimp_flags, m_ext.c_str() );
74
75        if( !scene)
76        {
77                NV_LOG( nv::LOG_ERROR, aiGetErrorString() );
78                return false;
79        }
80        m_scene      = scene;
81        m_mesh_count = scene->mNumMeshes;
82        NV_LOG( nv::LOG_NOTICE, "Loading successfull" );
83        return true;
84}
85
86mesh_data* nv::assimp_loader::release_mesh_data( size_t index /*= 0 */ )
87{
88        if ( index >= m_mesh_count ) return nullptr;
89        mesh_data* result = new mesh_data;
90        load_mesh_data( result, index );
91        return result;
92}
93void nv::assimp_loader::load_mesh_data( mesh_data* data, size_t index )
94{
95        const aiScene* scene = (const aiScene*)m_scene;
96        const aiMesh*  mesh  = scene->mMeshes[ index ];
97        data->set_name( mesh->mName.data );
98
99        vec3 vertex_offset     = glm::vec3();
100        mat3 vertex_transform  = m_scale * m_r33;
101        mat3 normal_transform  = m_r33;
102
103        bool skinned = mesh->mNumBones > 0;
104        mesh_raw_channel* channel = nullptr;
105        if ( skinned )
106                channel = mesh_raw_channel::create< assimp_skinned_vtx >( mesh->mNumVertices );
107        else
108                channel = mesh_raw_channel::create< assimp_plain_vtx >( mesh->mNumVertices );
109
110        data->add_channel( channel );
111        for (unsigned int i=0; i<mesh->mNumVertices; i++)
112        {
113                vec3 v = vertex_transform * assimp_vec3_cast( mesh->mVertices[ i ] ) + vertex_offset;
114                vec3 n = glm::normalize( normal_transform * assimp_vec3_cast( mesh->mNormals[ i ] ) );
115                vec3 t = glm::normalize( normal_transform * assimp_vec3_cast( mesh->mTangents[ i ] ) );
116                vec3 b = glm::normalize( normal_transform * assimp_vec3_cast( mesh->mBitangents[ i ] ) );
117                vec2 s = assimp_st_cast( mesh->mTextureCoords[ 0 ][ i ] );
118
119                glm::vec3 t_i = glm::normalize (t - n * glm::dot (n, t));
120                float det = (glm::dot (glm::cross (n, t), b));
121                det = (det < 0.0f ? -1.0f : 1.0f );
122                nv::vec4 vt ( t_i[0], t_i[1], t_i[2], det );
123                if ( skinned )
124                        ((assimp_skinned_vtx*)channel->data)[i] = assimp_skinned_vtx( v, s, n, vt );
125                else
126                        ((assimp_plain_vtx*)channel->data)[i] = assimp_plain_vtx( v, s, n, vt );
127        }
128
129        if ( skinned )
130        {
131                assimp_skinned_vtx* vtx = (assimp_skinned_vtx*)channel->data;
132                for (unsigned int m=0; m<mesh->mNumBones; m++)
133                {
134                        aiBone* bone  = mesh->mBones[m];
135                        for (unsigned int w=0; w<bone->mNumWeights; w++)
136                        {
137                                assimp_skinned_vtx& v = vtx[ bone->mWeights[w].mVertexId ];
138                                bool found = false;
139                                for (nv::uint32 i = 0 ; i < 4; ++i)
140                                {
141                                        if ( v.boneweight[i] <= 0.0f )
142                                        {
143                                                v.boneindex[i] = m;
144                                                v.boneweight[i] = bone->mWeights[w].mWeight;
145                                                found = true;
146                                                break;
147                                        }
148                                }
149                                NV_ASSERT( found, "Too many weights!" );
150                        }
151                }
152        }
153
154        mesh_raw_channel* ichannel = mesh_raw_channel::create_index( USHORT, mesh->mNumFaces * 3 );
155        data->add_channel( ichannel );
156        uint16* indices = (uint16*)ichannel->data;
157        for (unsigned int i=0; i<mesh->mNumFaces; i++)
158        {
159                const aiFace* face = &mesh->mFaces[i];
160                for (unsigned int j=0; j<face->mNumIndices; j++)
161                {
162                        indices[ i*3 + j ] = (uint16)face->mIndices[j];
163                }
164        }
165}
166
167nv::assimp_loader::~assimp_loader()
168{
169        if ( m_scene != nullptr ) aiReleaseImport( (const aiScene*)m_scene );
170}
171
172bool nv::assimp_loader::load_bones( size_t index, std::vector< mesh_node_data >& bones )
173{
174        if ( m_scene == nullptr ) return false;
175        const aiScene* scene = (const aiScene*)m_scene;
176        const aiMesh*  mesh  = scene->mMeshes[ index ];
177
178        mat4 bone_transform     = mat4( ( 1.f/m_scale * m_ri33 ) );
179        mat4 bone_pre_transform = mat4( m_scale * m_r33 );
180
181        for (unsigned int m=0; m<mesh->mNumBones; m++)
182        {
183                aiBone* bone   = mesh->mBones[m];
184                mat4    offset = bone_pre_transform * assimp_mat4_cast( bone->mOffsetMatrix ) * bone_transform;
185                bones[m].name = bone->mName.data;
186                bones[m].data = nullptr;
187                bones[m].parent_id = -1;
188                bones[m].target_id = -1;
189                bones[m].transform = offset;
190        }
191        return true;
192}
193
194void nv::assimp_loader::scene_report() const
195{
196        const aiScene* scene = (const aiScene*)m_scene;
197        if ( scene == nullptr ) return;
198
199        NV_LOG( nv::LOG_NOTICE, "------------------------" );
200        NV_LOG( nv::LOG_NOTICE, "Texture   count - " << scene->mNumTextures );
201        NV_LOG( nv::LOG_NOTICE, "Animation count - " << scene->mNumAnimations );
202        NV_LOG( nv::LOG_NOTICE, "Material  count - " << scene->mNumMaterials );
203        NV_LOG( nv::LOG_NOTICE, "Meshes    count - " << scene->mNumMeshes );
204        NV_LOG( nv::LOG_NOTICE, "------------------------" );
205
206        aiNode* root = scene->mRootNode;
207        if (root)
208        {
209                NV_LOG( nv::LOG_NOTICE, "Root node  - " << root->mName.data );
210                NV_LOG( nv::LOG_NOTICE, "  meshes   - " << root->mNumMeshes );
211                NV_LOG( nv::LOG_NOTICE, "  children - " << root->mNumChildren );
212        }
213        else
214        {
215                NV_LOG( nv::LOG_NOTICE, "No root node!" );
216        }
217        NV_LOG( nv::LOG_NOTICE, "------------------------" );
218
219        if ( scene->mNumMeshes > 0 )
220        {
221                for ( nv::uint32 mc = 0; mc < scene->mNumMeshes; mc++ )
222                {
223                        aiMesh* mesh = scene->mMeshes[mc];
224
225                        NV_LOG( nv::LOG_NOTICE, "Mesh #"<<mc<<"   - " << std::string( mesh->mName.data ) );
226                        NV_LOG( nv::LOG_NOTICE, "  bones   - " << mesh->mNumBones );
227                        NV_LOG( nv::LOG_NOTICE, "  uvs     - " << mesh->mNumUVComponents[0] );
228                        NV_LOG( nv::LOG_NOTICE, "  verts   - " << mesh->mNumVertices );
229                        NV_LOG( nv::LOG_NOTICE, "  faces   - " << mesh->mNumFaces );
230
231                        //                      NV_LOG( nv::LOG_NOTICE, "Bones:" );
232                        //                      for (unsigned int m=0; m<mesh->mNumBones; m++)
233                        //                      {
234                        //                              aiBone* bone  = mesh->mBones[m];
235                        //                              NV_LOG( nv::LOG_DEBUG, bone->mName.C_Str() );
236                        //                      }
237                }
238        }
239        else
240        {
241                NV_LOG( nv::LOG_NOTICE, "No meshes!" );
242        }
243        NV_LOG( nv::LOG_NOTICE, "------------------------" );
244
245
246        //      if ( scene->mNumMaterials > 0 )
247        //      {
248        //              for (unsigned int m=0; m < scene->mNumMaterials; m++)
249        //              {
250        //                      int texIndex = 0;
251        //                      aiReturn texFound = aiReturn_SUCCESS;
252        //                      aiString path;  // filename
253        //                      while (texFound == aiReturn_SUCCESS)
254        //                      {
255        //                              texFound = scene->mMaterials[m]->GetTexture(aiTextureType_DIFFUSE, texIndex, &path);
256        //                              NV_LOG( nv::LOG_NOTICE, "  material - " << path.data );
257        //                              texIndex++;
258        //                      }
259        //              }
260        //      }
261        //      else
262        //      {
263        //              NV_LOG( nv::LOG_NOTICE, "No materials" );
264        //      }
265        //      NV_LOG( nv::LOG_NOTICE, "------------------------" );
266
267}
268
269mesh_nodes_data* nv::assimp_loader::release_merged_bones( mesh_data* meshes )
270{
271        const aiScene* scene = (const aiScene*)m_scene;
272        std::vector< mesh_node_data > final_bones;
273        std::unordered_map< std::string, uint16 > names;
274        for ( unsigned int m = 0; m < m_mesh_count; ++m )
275        {
276                sint16 translate[MAX_BONES];
277                std::vector< mesh_node_data > bones;
278                const aiMesh*  mesh  = scene->mMeshes[ m ];
279                if ( mesh->mNumBones != 0 )
280                {
281                        bones.resize( mesh->mNumBones );
282                        load_bones( m, bones );
283                        for ( unsigned int b = 0; b < mesh->mNumBones; ++b )
284                        {
285
286                                mesh_node_data& bone = bones[b];
287                                auto iname = names.find( bone.name );
288                                if ( iname == names.end() )
289                                {
290                                        NV_ASSERT( final_bones.size() < MAX_BONES, "Too many bones to merge!" );
291                                        sint16 index = (sint16)final_bones.size();
292                                        final_bones.push_back( bone );
293                                        names[ bone.name ] = index;
294                                        translate[b] = index;
295                                }
296                                else
297                                {
298                                        translate[b] = (sint16)iname->second;
299                                }
300                        }
301                        if ( m > 0 && bones.size() > 0 )
302                        {
303                                mesh_raw_channel* channel = meshes[m].get_raw_channels()[0];
304                                NV_ASSERT( !channel->is_index(), "index channel in release_merged!" );
305                                assimp_skinned_vtx* va = (assimp_skinned_vtx*)channel->data;
306                                for ( unsigned v = 0; v < channel->count; ++v )
307                                {
308                                        assimp_skinned_vtx& vertex = va[v];
309
310                                        for (uint32 i = 0 ; i < 4; ++i)
311                                        {
312                                                if ( vertex.boneweight[i] > 0.0f )
313                                                {
314                                                        vertex.boneindex[i] = translate[vertex.boneindex[i]];
315                                                }
316                                        }
317                                }
318                        }
319                }       
320        }
321        mesh_node_data* bones = new mesh_node_data[ final_bones.size() ];
322        std::copy( final_bones.begin(), final_bones.end(), bones );
323        return new mesh_nodes_data( "bones", final_bones.size(), bones );
324}
325
326mesh_nodes_data* nv::assimp_loader::release_animation( size_t index )
327{
328        if ( m_scene == nullptr ) return nullptr;
329        const aiScene* scene = (const aiScene*)m_scene;
330        if ( scene->mRootNode == nullptr || scene->mAnimations == nullptr || scene->mAnimations[index] == nullptr) return nullptr;
331
332        const aiNode*      root = scene->mRootNode;
333        const aiAnimation* anim = scene->mAnimations[index];
334
335        uint32 count = count_nodes( scene->mRootNode );
336        mesh_node_data* data    = new mesh_node_data[count];
337
338        uint16 frame_rate     = (uint16)anim->mTicksPerSecond;
339        float  duration       = (float)anim->mDuration;
340        bool   flat           = m_flat;
341        uint32 max_frames     = 0;
342
343        load_node( index, data, root, 0, -1, max_frames );
344
345        // DAE pre_transform hack
346        if ( m_flat && frame_rate == 1 )
347        {
348                frame_rate = 32;
349                duration   = (float)max_frames;
350        }
351
352        return new mesh_nodes_data( anim->mName.data, count, data, frame_rate, duration, flat ) ;
353}
354
355nv::uint32 nv::assimp_loader::count_nodes( const void* node ) const
356{
357        const aiNode* ainode = (const aiNode*)node;
358        nv::uint32 count = 1;
359        for ( unsigned i = 0; i < ainode->mNumChildren; ++i )
360        {
361                count += count_nodes( ainode->mChildren[i] );
362        }
363        return count;
364}
365
366nv::sint16 nv::assimp_loader::load_node( uint32 anim_id, mesh_node_data* nodes, const void* vnode, sint16 this_id, sint16 parent_id, uint32& max_frames )
367{
368        const aiScene* scene = (const aiScene*)m_scene;
369        const aiNode*  node  = (const aiNode*)vnode;
370        string name( node->mName.data );
371        const aiAnimation* anim  = scene->mAnimations[anim_id];
372        const aiNodeAnim*  anode = nullptr;
373
374        for ( unsigned i = 0 ; i < anim->mNumChannels ; i++ )
375        {
376                anode = anim->mChannels[i];
377                if ( std::string( anode->mNodeName.data ) == name ) break;
378                anode = nullptr;
379        }
380
381        mesh_node_data& a_data = nodes[ this_id ];
382
383        a_data.name      = name;
384        a_data.target_id = -1;
385        a_data.parent_id = parent_id;
386        // This value is ignored by the create_transformed_keys, but needed by create_direct_keys!
387        // TODO: find a common solution!
388        //       This is bad because create_transformed_keys never uses node-transformations for
389        //       node's without keys
390        a_data.transform = nv::assimp_mat4_cast( node->mTransformation );
391        if (this_id == 0)
392                a_data.transform = mat4();
393        a_data.data = nullptr;
394
395        if (anode)
396        {
397                if ( m_flat )
398                {
399                        create_transformed_keys( &a_data, anode, parent_id >= 0 ? &(nodes[ parent_id ]) : nullptr );
400                }
401                else
402                {
403                        create_direct_keys( &a_data, anode );
404                }
405                max_frames = glm::max<uint32>( a_data.data->get_channel(0)->count, max_frames );
406        }
407
408        nv::sint16 next = this_id + 1;
409        for ( unsigned i = 0; i < node->mNumChildren; ++i )
410        {
411                next = load_node( anim_id, nodes, node->mChildren[i], next, this_id, max_frames );
412        }
413
414        return next;
415}
416
417void nv::assimp_loader::create_transformed_keys( mesh_node_data* data, const void* vnode, const mesh_node_data* parent )
418{
419        const aiNodeAnim* node = (const aiNodeAnim*)vnode;
420        size_t max_keys = glm::max( node->mNumPositionKeys, node->mNumRotationKeys );
421
422        key_raw_channel* raw_channel = key_raw_channel::create<assimp_key_tr>( max_keys );
423        data->data = new key_data;
424        data->data->add_channel( raw_channel );
425        assimp_key_tr* channel = ((assimp_key_tr*)(raw_channel->data));
426
427        for ( unsigned n = 0; n < max_keys; ++n )
428        {
429                size_t pn = glm::min( node->mNumPositionKeys - 1, n );
430                size_t rn = glm::min( node->mNumRotationKeys - 1, n );
431                nv::vec3 pos = m_r33 * nv::assimp_vec3_cast(node->mPositionKeys[pn].mValue) * m_scale;
432                nv::quat rot = glm::quat_cast( m_r33 * glm::mat3_cast( assimp_quat_cast(node->mRotationKeys[rn].mValue ) ) * m_ri33 );
433                // TODO: only do the calculation when a rotate transform is present!
434                nv::transform ptr;
435                if ( parent && parent->data )
436                {
437                        const key_raw_channel* pchannel = parent->data->get_channel(0);
438                        if ( pchannel && pchannel->count > 0 )
439                        {
440                                ptr = ((assimp_key_tr*)pchannel->data)[ glm::min( n, pchannel->count-1 ) ].tform;
441                        }
442                }
443
444                nv::transform key( ptr * nv::transform( pos, rot ) );
445                channel[n].tform = key;
446        }
447}
448
449void nv::assimp_loader::create_direct_keys( mesh_node_data* data, const void* vnode )
450{
451        const aiNodeAnim* node = (const aiNodeAnim*)vnode;
452        if ( node->mNumPositionKeys == 0 && node->mNumRotationKeys == 0 && node->mNumScalingKeys == 0 )
453        {
454                return;
455        }
456
457        data->data = new key_data;
458        key_raw_channel* raw_pchannel = key_raw_channel::create<assimp_key_p>( node->mNumPositionKeys );
459        key_raw_channel* raw_rchannel = key_raw_channel::create<assimp_key_r>( node->mNumRotationKeys );
460        //key_raw_channel* raw_schannel = key_raw_channel::create<assimp_key_s>( node->mNumScalingKeys );
461        data->data->add_channel( raw_pchannel );
462        data->data->add_channel( raw_rchannel );
463        //data->data->add_channel( raw_schannel );
464        assimp_key_p* pchannel = ((assimp_key_p*)(raw_pchannel->data));
465        assimp_key_r* rchannel = ((assimp_key_r*)(raw_rchannel->data));
466        //assimp_key_s* schannel = ((assimp_key_s*)(raw_schannel->data));
467
468        for ( unsigned np = 0; np < node->mNumPositionKeys; ++np )
469        {
470                pchannel[np].time     = (float)node->mPositionKeys[np].mTime;
471                pchannel[np].position = m_r33 * assimp_vec3_cast(node->mPositionKeys[np].mValue) * m_scale;
472        }
473        for ( unsigned np = 0; np < node->mNumRotationKeys; ++np )
474        {
475                rchannel[np].time     = (float)node->mRotationKeys[np].mTime;
476                rchannel[np].rotation = glm::quat_cast( m_r33 * glm::mat3_cast( assimp_quat_cast(node->mRotationKeys[np].mValue ) ) * m_ri33 );
477        }
478//      if ( node->mNumScalingKeys > 0 )
479//      {
480//              nv::vec3 scale_vec0 = assimp_vec3_cast( node->mScalingKeys[0].mValue );
481//              float scale_value   = glm::length( glm::abs( scale_vec0 - nv::vec3(1,1,1) ) );
482//              if ( node->mNumScalingKeys > 1 || scale_value > 0.001 )
483//              {
484//                      NV_LOG( nv::LOG_WARNING, "scale key significant!" );
485//                      for ( unsigned np = 0; np < node->mNumRotationKeys; ++np )
486//                      {
487//                              schannel[np].time  = (float)node->mScalingKeys[np].mTime;
488//                              schannel[np].scale = assimp_vec3_cast(node->mScalingKeys[np].mValue);
489//                      }
490//              }
491//              else
492//              {
493//                      schannel[0].time  = (float)node->mScalingKeys[0].mTime;
494//                      schannel[0].scale = assimp_vec3_cast(node->mScalingKeys[0].mValue);
495//              }
496//      }
497
498}
499
500mesh_data_pack* nv::assimp_loader::release_mesh_data_pack()
501{
502        if ( m_scene == nullptr || m_mesh_count == 0 ) return nullptr;
503        const aiScene* scene = (const aiScene*)m_scene;
504        bool has_bones = false;
505        mesh_data* meshes = new mesh_data[ m_mesh_count ];
506        for ( size_t m = 0; m < m_mesh_count; ++m )
507        {
508                const aiMesh* mesh = scene->mMeshes[ m ];
509                meshes[m].set_name( mesh->mName.data );
510                if ( mesh->mNumBones > 0 ) has_bones = true;
511                load_mesh_data(&meshes[m],m);
512        }
513
514        mesh_nodes_data* nodes = ( has_bones ? release_merged_bones( meshes ) : release_animation(0) );
515        return new mesh_data_pack( m_mesh_count, meshes, nodes );
516}
517
518size_t nv::assimp_loader::get_nodes_data_count() const
519{
520        if ( m_scene == nullptr ) return 0;
521        const aiScene* scene = (const aiScene*)m_scene;
522        return scene->mNumAnimations;   
523}
524
525mesh_nodes_data* nv::assimp_loader::release_mesh_nodes_data( size_t index /*= 0 */ )
526{
527        return release_animation( index );
528}
529
Note: See TracBrowser for help on using the repository browser.