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

Last change on this file since 250 was 250, checked in by epyon, 11 years ago
  • assimp logging done automatically
  • assimp flags hidden
File size: 14.3 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
15
16nv::assimp_loader::assimp_loader( const string& a_ext, const mat4& a_rotate_transform, float a_scale, uint32 a_assimp_flags /*= 0 */ ) : m_ext( a_ext ), m_rotate_transform( a_rotate_transform ), m_scale( a_scale ), m_assimp_flags( a_assimp_flags ), m_mesh_count(0), m_scene( nullptr )
17{
18        if ( m_assimp_flags == 0 )
19        {
20                m_assimp_flags = (
21                        aiProcess_CalcTangentSpace                              | 
22                        aiProcess_GenSmoothNormals                              | 
23                        aiProcess_JoinIdenticalVertices                 |   
24                        aiProcess_ImproveCacheLocality                  | 
25                        aiProcess_LimitBoneWeights                              | 
26                        aiProcess_RemoveRedundantMaterials      | 
27                        aiProcess_SplitLargeMeshes                              | 
28                        aiProcess_Triangulate                                   | 
29                        aiProcess_GenUVCoords                   | 
30                        aiProcess_SortByPType                   | 
31                        aiProcess_FindDegenerates               | 
32                        aiProcess_FindInvalidData               | 
33                        0 );
34        }
35}
36
37
38bool nv::assimp_loader::load( stream& source )
39{
40        if ( m_scene != nullptr ) aiReleaseImport( (const aiScene*)m_scene );
41        m_scene = nullptr;
42        m_mesh_count = 0;
43        load_assimp_library();
44        NV_LOG( nv::LOG_NOTICE, "AssImp loading file..." );
45        int size = (int)source.size();
46        char* data  = new char[ size ];
47        source.read( data, size, 1 );
48        const aiScene* scene = aiImportFileFromMemory( data, size, m_assimp_flags, m_ext.c_str() );
49
50        if( !scene)
51        {
52                NV_LOG( nv::LOG_ERROR, aiGetErrorString() );
53                return false;
54        }
55        m_scene      = scene;
56        m_mesh_count = scene->mNumMeshes;
57        NV_LOG( nv::LOG_NOTICE, "Loading successfull" );
58        return true;
59}
60
61mesh_data* nv::assimp_loader::release_mesh_data( size_t index /*= 0 */ )
62{
63        if ( index >= m_mesh_count ) return nullptr;
64        mesh_data* result = new mesh_data();
65        const aiScene* scene = (const aiScene*)m_scene;
66        const aiMesh*  mesh  = scene->mMeshes[ index ];
67
68        mat3 scaled_rotatation = glm::mat3( glm::scale( m_scale, m_scale, m_scale ) * m_rotate_transform );
69        vec3 vertex_offset     = glm::vec3();
70        mat3 vertex_transform  = glm::mat3( glm::transpose( scaled_rotatation ) );
71        mat3 normal_transform  = glm::mat3( glm::transpose( glm::inverse( scaled_rotatation ) ) );
72        mat4 bone_transform    = glm::scale( 1.0f/m_scale, 1.0f/m_scale, 1.0f/m_scale ) * m_rotate_transform;
73
74        bool skinned = mesh->mNumBones > 0;
75        mesh_raw_channel* channel = nullptr;
76        if ( skinned )
77                channel = mesh_raw_channel::create< assimp_skinned_vtx >( mesh->mNumVertices );
78        else
79                channel = mesh_raw_channel::create< assimp_plain_vtx >( mesh->mNumVertices );
80
81        result->add_channel( channel );
82        for (unsigned int i=0; i<mesh->mNumVertices; i++)
83        {
84                vec3 v = vertex_transform * assimp_vec3_cast( mesh->mVertices[ i ] ) + vertex_offset;
85                vec3 n = glm::normalize( normal_transform * assimp_vec3_cast( mesh->mNormals[ i ] ) );
86                vec3 t = glm::normalize( normal_transform * assimp_vec3_cast( mesh->mTangents[ i ] ) );
87                vec3 b = glm::normalize( normal_transform * assimp_vec3_cast( mesh->mBitangents[ i ] ) );
88                vec2 s = assimp_st_cast( mesh->mTextureCoords[ 0 ][ i ] );
89
90                glm::vec3 t_i = glm::normalize (t - n * glm::dot (n, t));
91                float det = (glm::dot (glm::cross (n, t), b));
92                det = (det < 0.0f ? -1.0f : 1.0f );
93                nv::vec4 vt ( t_i[0], t_i[1], t_i[2], det );
94                if ( skinned )
95                        ((assimp_skinned_vtx*)channel->data)[i] = assimp_skinned_vtx( v, s, n, vt );
96                else
97                        ((assimp_plain_vtx*)channel->data)[i] = assimp_plain_vtx( v, s, n, vt );
98        }
99
100        if ( skinned )
101        {
102                assimp_skinned_vtx* vtx = (assimp_skinned_vtx*)channel->data;
103                for (unsigned int m=0; m<mesh->mNumBones; m++)
104                {
105                        aiBone* bone  = mesh->mBones[m];
106                        nv::mat4 offset = nv::assimp_mat4_cast( bone->mOffsetMatrix ) * bone_transform;
107                        for (unsigned int w=0; w<bone->mNumWeights; w++)
108                        {
109                                assimp_skinned_vtx& v = vtx[ bone->mWeights[w].mVertexId ];
110                                bool found = false;
111                                for (nv::uint32 i = 0 ; i < 4; ++i)
112                                {
113                                        if ( v.boneweight[i] <= 0.0f )
114                                        {
115                                                v.boneindex[i] = m;
116                                                v.boneweight[i] = bone->mWeights[w].mWeight;
117                                                found = true;
118                                                break;
119                                        }
120                                }
121                                NV_ASSERT( found, "Too many weights!" );
122                        }
123                }
124        }
125
126        mesh_raw_index_channel* ichannel = mesh_raw_index_channel::create( USHORT, mesh->mNumFaces * 3 );
127        result->set_index_channel( ichannel );
128        uint16* indices = (uint16*)ichannel->data;
129        for (unsigned int i=0; i<mesh->mNumFaces; i++)
130        {
131                const aiFace* face = &mesh->mFaces[i];
132                for (unsigned int j=0; j<face->mNumIndices; j++)
133                {
134                        indices[ i*3 + j ] = (uint16)face->mIndices[j];
135                }
136        }
137
138        return result;
139}
140
141nv::assimp_loader::~assimp_loader()
142{
143        if ( m_scene != nullptr ) aiReleaseImport( (const aiScene*)m_scene );
144}
145
146bool nv::assimp_loader::load_bones( size_t index, std::vector< assimp_bone >& bones )
147{
148        if ( m_scene == nullptr ) return false;
149        const aiScene* scene = (const aiScene*)m_scene;
150        const aiMesh*  mesh  = scene->mMeshes[ index ];
151        if ( mesh->mNumBones == 0 ) return false;
152
153        mat4 bone_transform    = glm::scale( 1.0f/m_scale, 1.0f/m_scale, 1.0f/m_scale ) * m_rotate_transform;
154
155        for (unsigned int m=0; m<mesh->mNumBones; m++)
156        {
157                aiBone* bone   = mesh->mBones[m];
158                mat4    offset = assimp_mat4_cast( bone->mOffsetMatrix ) * bone_transform;
159                bones.emplace_back( bone->mName.data, offset );
160        }
161        return true;
162}
163
164void nv::assimp_loader::scene_report() const
165{
166        const aiScene* scene = (const aiScene*)m_scene;
167        if ( scene == nullptr ) return;
168
169        NV_LOG( nv::LOG_NOTICE, "------------------------" );
170        NV_LOG( nv::LOG_NOTICE, "Texture   count - " << scene->mNumTextures );
171        NV_LOG( nv::LOG_NOTICE, "Animation count - " << scene->mNumAnimations );
172        NV_LOG( nv::LOG_NOTICE, "Material  count - " << scene->mNumMaterials );
173        NV_LOG( nv::LOG_NOTICE, "Meshes    count - " << scene->mNumMeshes );
174        NV_LOG( nv::LOG_NOTICE, "------------------------" );
175
176        aiNode* root = scene->mRootNode;
177        if (root)
178        {
179                NV_LOG( nv::LOG_NOTICE, "Root node  - " << root->mName.data );
180                NV_LOG( nv::LOG_NOTICE, "  meshes   - " << root->mNumMeshes );
181                NV_LOG( nv::LOG_NOTICE, "  children - " << root->mNumChildren );
182        }
183        else
184        {
185                NV_LOG( nv::LOG_NOTICE, "No root node!" );
186        }
187        NV_LOG( nv::LOG_NOTICE, "------------------------" );
188
189        if ( scene->mNumMeshes > 0 )
190        {
191                for ( nv::uint32 mc = 0; mc < scene->mNumMeshes; mc++ )
192                {
193                        aiMesh* mesh = scene->mMeshes[mc];
194
195                        NV_LOG( nv::LOG_NOTICE, "Mesh #"<<mc<<"   - " << mesh->mName.data );
196                        NV_LOG( nv::LOG_NOTICE, "  bones   - " << mesh->mNumBones );
197                        NV_LOG( nv::LOG_NOTICE, "  uvs     - " << mesh->mNumUVComponents[0] );
198                        NV_LOG( nv::LOG_NOTICE, "  verts   - " << mesh->mNumVertices );
199                        NV_LOG( nv::LOG_NOTICE, "  faces   - " << mesh->mNumFaces );
200
201                        //                      NV_LOG( nv::LOG_NOTICE, "Bones:" );
202                        //                      for (unsigned int m=0; m<mesh->mNumBones; m++)
203                        //                      {
204                        //                              aiBone* bone  = mesh->mBones[m];
205                        //                              NV_LOG( nv::LOG_DEBUG, bone->mName.C_Str() );
206                        //                      }
207                }
208        }
209        else
210        {
211                NV_LOG( nv::LOG_NOTICE, "No meshes!" );
212        }
213        NV_LOG( nv::LOG_NOTICE, "------------------------" );
214
215
216        //      if ( scene->mNumMaterials > 0 )
217        //      {
218        //              for (unsigned int m=0; m < scene->mNumMaterials; m++)
219        //              {
220        //                      int texIndex = 0;
221        //                      aiReturn texFound = aiReturn_SUCCESS;
222        //                      aiString path;  // filename
223        //                      while (texFound == aiReturn_SUCCESS)
224        //                      {
225        //                              texFound = scene->mMaterials[m]->GetTexture(aiTextureType_DIFFUSE, texIndex, &path);
226        //                              NV_LOG( nv::LOG_NOTICE, "  material - " << path.data );
227        //                              texIndex++;
228        //                      }
229        //              }
230        //      }
231        //      else
232        //      {
233        //              NV_LOG( nv::LOG_NOTICE, "No materials" );
234        //      }
235        //      NV_LOG( nv::LOG_NOTICE, "------------------------" );
236
237}
238
239assimp_model* nv::assimp_loader::release_merged_model()
240{
241        if ( m_scene == nullptr || m_mesh_count == 0 ) return nullptr;
242        assimp_model* model = new assimp_model;
243
244        for ( size_t m = 0; m < m_mesh_count; ++m )
245        {
246                model->meshes.push_back( release_mesh_data(m) );
247        }
248
249        std::unordered_map< std::string, uint16 > names;
250        for ( unsigned int m = 0; m < model->meshes.size(); ++m )
251        {
252                nv::sint16 translate[64];
253                std::vector< assimp_bone > bones;
254                load_bones( m, bones );
255                for ( unsigned int b = 0; b < bones.size(); ++b )
256                {
257
258                        nv::assimp_bone& bone = bones[b];
259                        auto iname = names.find( bone.name );
260                        if ( iname == names.end() )
261                        {
262                                NV_ASSERT( model->bones.size() < 64, "Too many bones to merge!" );
263                                nv::sint16 index = (nv::sint16)model->bones.size();
264                                model->bones.push_back( bone );
265                                names[ bone.name ] = index;
266                                translate[b] = index;
267                        }
268                        else
269                        {
270                                translate[b] = (nv::sint16)iname->second;
271                        }
272                }
273                if ( m > 0 )
274                {
275                        mesh_data* mesh = model->meshes[m];
276                        nv::mesh_raw_channel* channel = mesh->get_channel_data()[0];
277                        nv::assimp_skinned_vtx* va = (nv::assimp_skinned_vtx*)channel->data;
278                        for ( unsigned v = 0; v < channel->count; ++v )
279                        {
280                                nv::assimp_skinned_vtx& vertex = va[v];
281
282                                for (nv::uint32 i = 0 ; i < 4; ++i)
283                                {
284                                        if ( vertex.boneweight[i] > 0.0f )
285                                        {
286                                                vertex.boneindex[i] = translate[vertex.boneindex[i]];
287                                        }
288                                }
289                        }
290                }
291        }
292        return model;
293}
294
295assimp_animation* nv::assimp_loader::release_animation( size_t, bool pre_transform, const std::vector< assimp_bone >* bone_data )
296{
297        if ( m_scene == nullptr ) return nullptr;
298        const aiScene* scene = (const aiScene*)m_scene;
299        if ( scene->mRootNode == nullptr || scene->mAnimations[0] == nullptr ) return nullptr;
300        assimp_animation* result = new assimp_animation;
301
302        // need resize not to copy!
303        result->nodes.resize( count_nodes( scene->mRootNode ) );
304
305        const aiNode*      root = scene->mRootNode;
306        const aiAnimation* anim = scene->mAnimations[0]; // if implemented, change in load_node also
307
308        result->fps            = (float)anim->mTicksPerSecond;
309        result->duration       = (float)anim->mDuration;
310        result->pretransformed = pre_transform;
311
312        load_node( result, root, 0, -1 );
313        result->nodes[0].transform = glm::scale( m_scale, m_scale, m_scale ) * result->nodes[0].transform;
314
315        if ( bone_data )
316        {
317                std::unordered_map< std::string, uint16 > names;
318                for ( uint16 bi = 0; bi < bone_data->size(); ++bi )
319                {
320                        names[ (*bone_data)[bi].name ] = bi;
321                }
322
323                for ( unsigned i = 0; i < result->nodes.size(); ++i )
324                {
325                        assimp_animated_node_data& node = result->nodes[i];
326                        node.bone_id = -1;
327                        auto bi = names.find( node.name );
328                        if ( bi != names.end() )
329                        {
330                                node.bone_id = bi->second;
331                        }
332                        if ( node.parent_id != -1 )
333                        {
334                                result->nodes[ node.parent_id ].children.push_back( &node );
335                        }
336                }
337        }
338
339        return result;
340}
341
342nv::uint32 nv::assimp_loader::count_nodes( const void* node ) const
343{
344        const aiNode* ainode = (const aiNode*)node;
345        nv::uint32 count = 1;
346        for ( unsigned i = 0; i < ainode->mNumChildren; ++i )
347        {
348                count += count_nodes( ainode->mChildren[i] );
349        }
350        return count;
351}
352
353nv::uint32 nv::assimp_loader::load_node( assimp_animation* data, const void* vnode, sint32 this_id, sint32 parent_id )
354{
355        const aiScene* scene = (const aiScene*)m_scene;
356        const aiNode*  node  = (const aiNode*)vnode;
357        string name( node->mName.data );
358        const aiAnimation* anim  = scene->mAnimations[0];
359        const aiNodeAnim*  anode = nullptr;
360
361        for ( unsigned i = 0 ; i < anim->mNumChannels ; i++ )
362        {
363                anode = anim->mChannels[i];
364                if ( std::string( anode->mNodeName.data ) == name ) break;
365                anode = nullptr;
366        }
367
368        assimp_animated_node_data& a_data = data->nodes[ this_id ];
369
370        a_data.name      = name;
371        a_data.parent_id = parent_id;
372        a_data.bone_id = -1;
373        a_data.transform = nv::assimp_mat4_cast( node->mTransformation );
374
375        if (anode)
376        {
377                if ( data->pretransformed )
378                {
379                        a_data.keys = create_transformed_keys( anode, parent_id >= 0 ? data->nodes[ parent_id ].keys : nullptr );
380                }
381                else
382                {
383                        a_data.keys = create_direct_keys( anode );
384                }
385        }
386
387        nv::uint32 next = this_id + 1;
388        for ( unsigned i = 0; i < node->mNumChildren; ++i )
389        {
390                next = load_node( data, node->mChildren[i], next, this_id );
391        }
392        return next;
393}
394
395key_animation_data* nv::assimp_loader::create_transformed_keys( const void* vnode, const key_animation_data* parent_keys )
396{
397        const aiNodeAnim* node = (const aiNodeAnim*)vnode;
398        size_t max_keys = glm::max( node->mNumPositionKeys, node->mNumRotationKeys );
399        nv::transform_vector* keys = new nv::transform_vector;
400        for ( unsigned n = 0; n < max_keys; ++n )
401        {
402                size_t pn = glm::min( node->mNumPositionKeys - 1, n );
403                size_t rn = glm::min( node->mNumRotationKeys - 1, n );
404                nv::vec3 pos = nv::assimp_vec3_cast(node->mPositionKeys[pn].mValue);
405                nv::quat rot = nv::assimp_quat_cast(node->mRotationKeys[rn].mValue);
406                nv::transform ptr;
407                if ( parent_keys )
408                {
409                        const nv::transform_vector* pv = (const nv::transform_vector*)parent_keys;
410                        if ( pv && pv->size() > 0 ) ptr = pv->get( glm::min( n, pv->size()-1 ) );
411                }
412
413                nv::vec3 rot_pos = ptr.get_orientation() * pos;
414                pos = ptr.get_position() + rot_pos;
415                rot = glm::normalize( ptr.get_orientation() * rot );
416                keys->insert( nv::transform( pos, rot ) );
417        }
418        return keys;
419}
420
421key_animation_data* nv::assimp_loader::create_direct_keys( const void* vnode )
422{
423        const aiNodeAnim* node = (const aiNodeAnim*)vnode;
424        if ( node->mNumPositionKeys == 0 && node->mNumRotationKeys == 0 && node->mNumScalingKeys == 0 ) return nullptr;
425        key_vectors_prs* keys = new key_vectors_prs;
426
427        for ( unsigned np = 0; np < node->mNumPositionKeys; ++np )
428        {
429                keys->insert_position( (float)node->mPositionKeys[np].mTime, assimp_vec3_cast(node->mPositionKeys[np].mValue) );
430        }
431        for ( unsigned np = 0; np < node->mNumRotationKeys; ++np )
432        {
433                keys->insert_rotation( (float)node->mRotationKeys[np].mTime, assimp_quat_cast(node->mRotationKeys[np].mValue) );
434        }
435        if ( node->mNumScalingKeys > 0 )
436        {
437                nv::vec3 scale_vec0 = assimp_vec3_cast( node->mScalingKeys[0].mValue );
438                float scale_value   = glm::length( glm::abs( scale_vec0 - nv::vec3(1,1,1) ) );
439                if ( node->mNumScalingKeys > 1 || scale_value > 0.001 )
440                {
441                        NV_LOG( nv::LOG_WARNING, "scale key significant!" );
442                        for ( unsigned np = 0; np < node->mNumRotationKeys; ++np )
443                        {
444                                keys->insert_scale( (float)node->mScalingKeys[np].mTime, assimp_vec3_cast(node->mScalingKeys[np].mValue) );
445                        }
446                }
447        }
448        return keys;
449}
450
Note: See TracBrowser for help on using the repository browser.