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

Last change on this file since 248 was 248, checked in by epyon, 11 years ago
  • AssImp? loader implementation
  • full mesh_data support
  • initial skinning info support
  • support for merging bones for GPU skeletal animation
File size: 8.4 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
15bool nv::assimp_loader::load( stream& source )
16{
17        if ( m_scene != nullptr ) aiReleaseImport( (const aiScene*)m_scene );
18        m_scene = nullptr;
19        m_mesh_count = 0;
20        load_assimp_library();
21        NV_LOG( nv::LOG_NOTICE, "AssImp loading file..." );
22        int size = (int)source.size();
23        char* data  = new char[ size ];
24        source.read( data, size, 1 );
25        const aiScene* scene = aiImportFileFromMemory( data, size, m_assimp_flags, m_ext.c_str() );
26
27        if( !scene)
28        {
29                NV_LOG( nv::LOG_ERROR, aiGetErrorString() );
30                return false;
31        }
32        m_scene      = scene;
33        m_mesh_count = scene->mNumMeshes;
34        NV_LOG( nv::LOG_NOTICE, "Loading successfull" );
35        return true;
36}
37
38mesh_data* nv::assimp_loader::release_mesh_data( size_t index /*= 0 */ )
39{
40        if ( index >= m_mesh_count ) return nullptr;
41        mesh_data* result = new mesh_data();
42        const aiScene* scene = (const aiScene*)m_scene;
43        const aiMesh*  mesh  = scene->mMeshes[ index ];
44
45        mat3 scaled_rotatation = glm::mat3( glm::scale( m_scale, m_scale, m_scale ) * m_rotate_transform );
46        vec3 vertex_offset     = glm::vec3();
47        mat3 vertex_transform  = glm::mat3( glm::transpose( scaled_rotatation ) );
48        mat3 normal_transform  = glm::mat3( glm::transpose( glm::inverse( scaled_rotatation ) ) );
49        mat4 bone_transform    = glm::scale( 1.0f/m_scale, 1.0f/m_scale, 1.0f/m_scale ) * m_rotate_transform;
50
51        bool skinned = mesh->mNumBones > 0;
52        mesh_raw_channel* channel = nullptr;
53        if ( skinned )
54                channel = mesh_raw_channel::create< assimp_skinned_vtx >( mesh->mNumVertices );
55        else
56                channel = mesh_raw_channel::create< assimp_plain_vtx >( mesh->mNumVertices );
57
58        result->add_channel( channel );
59        for (unsigned int i=0; i<mesh->mNumVertices; i++)
60        {
61                vec3 v = vertex_transform * assimp_vec3_cast( mesh->mVertices[ i ] ) + vertex_offset;
62                vec3 n = glm::normalize( normal_transform * assimp_vec3_cast( mesh->mNormals[ i ] ) );
63                vec3 t = glm::normalize( normal_transform * assimp_vec3_cast( mesh->mTangents[ i ] ) );
64                vec3 b = glm::normalize( normal_transform * assimp_vec3_cast( mesh->mBitangents[ i ] ) );
65                vec2 s = assimp_st_cast( mesh->mTextureCoords[ 0 ][ i ] );
66
67                glm::vec3 t_i = glm::normalize (t - n * glm::dot (n, t));
68                float det = (glm::dot (glm::cross (n, t), b));
69                det = (det < 0.0f ? -1.0f : 1.0f );
70                nv::vec4 vt ( t_i[0], t_i[1], t_i[2], det );
71                if ( skinned )
72                        ((assimp_skinned_vtx*)channel->data)[i] = assimp_skinned_vtx( v, s, n, vt );
73                else
74                        ((assimp_plain_vtx*)channel->data)[i] = assimp_plain_vtx( v, s, n, vt );
75        }
76
77        if ( skinned )
78        {
79                assimp_skinned_vtx* vtx = (assimp_skinned_vtx*)channel->data;
80                for (unsigned int m=0; m<mesh->mNumBones; m++)
81                {
82                        aiBone* bone  = mesh->mBones[m];
83                        nv::mat4 offset = nv::assimp_mat4_cast( bone->mOffsetMatrix ) * bone_transform;
84                        for (unsigned int w=0; w<bone->mNumWeights; w++)
85                        {
86                                assimp_skinned_vtx& v = vtx[ bone->mWeights[w].mVertexId ];
87                                bool found = false;
88                                for (nv::uint32 i = 0 ; i < 4; ++i)
89                                {
90                                        if ( v.boneweight[i] <= 0.0f )
91                                        {
92                                                v.boneindex[i] = m;
93                                                v.boneweight[i] = bone->mWeights[w].mWeight;
94                                                found = true;
95                                                break;
96                                        }
97                                }
98                                NV_ASSERT( found, "Too many weights!" );
99                        }
100                }
101        }
102
103        mesh_raw_index_channel* ichannel = mesh_raw_index_channel::create( USHORT, mesh->mNumFaces * 3 );
104        result->set_index_channel( ichannel );
105        uint16* indices = (uint16*)ichannel->data;
106        for (unsigned int i=0; i<mesh->mNumFaces; i++)
107        {
108                const aiFace* face = &mesh->mFaces[i];
109                for (unsigned int j=0; j<face->mNumIndices; j++)
110                {
111                        indices[ i*3 + j ] = (uint16)face->mIndices[j];
112                }
113        }
114
115        return result;
116}
117
118nv::assimp_loader::~assimp_loader()
119{
120        if ( m_scene != nullptr ) aiReleaseImport( (const aiScene*)m_scene );
121}
122
123bool nv::assimp_loader::load_bones( size_t index, std::vector< assimp_bone >& bones )
124{
125        if ( m_scene == nullptr ) return false;
126        const aiScene* scene = (const aiScene*)m_scene;
127        const aiMesh*  mesh  = scene->mMeshes[ index ];
128        if ( mesh->mNumBones == 0 ) return false;
129
130        mat4 bone_transform    = glm::scale( 1.0f/m_scale, 1.0f/m_scale, 1.0f/m_scale ) * m_rotate_transform;
131
132        for (unsigned int m=0; m<mesh->mNumBones; m++)
133        {
134                aiBone* bone   = mesh->mBones[m];
135                mat4    offset = assimp_mat4_cast( bone->mOffsetMatrix ) * bone_transform;
136                bones.emplace_back( bone->mName.data, offset );
137        }
138        return true;
139}
140
141void nv::assimp_loader::scene_report() const
142{
143        const aiScene* scene = (const aiScene*)m_scene;
144        if ( scene == nullptr ) return;
145
146        NV_LOG( nv::LOG_NOTICE, "------------------------" );
147        NV_LOG( nv::LOG_NOTICE, "Texture   count - " << scene->mNumTextures );
148        NV_LOG( nv::LOG_NOTICE, "Animation count - " << scene->mNumAnimations );
149        NV_LOG( nv::LOG_NOTICE, "Material  count - " << scene->mNumMaterials );
150        NV_LOG( nv::LOG_NOTICE, "Meshes    count - " << scene->mNumMeshes );
151        NV_LOG( nv::LOG_NOTICE, "------------------------" );
152
153        aiNode* root = scene->mRootNode;
154        if (root)
155        {
156                NV_LOG( nv::LOG_NOTICE, "Root node  - " << root->mName.data );
157                NV_LOG( nv::LOG_NOTICE, "  meshes   - " << root->mNumMeshes );
158                NV_LOG( nv::LOG_NOTICE, "  children - " << root->mNumChildren );
159        }
160        else
161        {
162                NV_LOG( nv::LOG_NOTICE, "No root node!" );
163        }
164        NV_LOG( nv::LOG_NOTICE, "------------------------" );
165
166        if ( scene->mNumMeshes > 0 )
167        {
168                for ( nv::uint32 mc = 0; mc < scene->mNumMeshes; mc++ )
169                {
170                        aiMesh* mesh = scene->mMeshes[mc];
171
172                        NV_LOG( nv::LOG_NOTICE, "Mesh #"<<mc<<"   - " << mesh->mName.data );
173                        NV_LOG( nv::LOG_NOTICE, "  bones   - " << mesh->mNumBones );
174                        NV_LOG( nv::LOG_NOTICE, "  uvs     - " << mesh->mNumUVComponents[0] );
175                        NV_LOG( nv::LOG_NOTICE, "  verts   - " << mesh->mNumVertices );
176                        NV_LOG( nv::LOG_NOTICE, "  faces   - " << mesh->mNumFaces );
177
178                        //                      NV_LOG( nv::LOG_NOTICE, "Bones:" );
179                        //                      for (unsigned int m=0; m<mesh->mNumBones; m++)
180                        //                      {
181                        //                              aiBone* bone  = mesh->mBones[m];
182                        //                              NV_LOG( nv::LOG_DEBUG, bone->mName.C_Str() );
183                        //                      }
184                }
185        }
186        else
187        {
188                NV_LOG( nv::LOG_NOTICE, "No meshes!" );
189        }
190        NV_LOG( nv::LOG_NOTICE, "------------------------" );
191
192
193        //      if ( scene->mNumMaterials > 0 )
194        //      {
195        //              for (unsigned int m=0; m < scene->mNumMaterials; m++)
196        //              {
197        //                      int texIndex = 0;
198        //                      aiReturn texFound = aiReturn_SUCCESS;
199        //                      aiString path;  // filename
200        //                      while (texFound == aiReturn_SUCCESS)
201        //                      {
202        //                              texFound = scene->mMaterials[m]->GetTexture(aiTextureType_DIFFUSE, texIndex, &path);
203        //                              NV_LOG( nv::LOG_NOTICE, "  material - " << path.data );
204        //                              texIndex++;
205        //                      }
206        //              }
207        //      }
208        //      else
209        //      {
210        //              NV_LOG( nv::LOG_NOTICE, "No materials" );
211        //      }
212        //      NV_LOG( nv::LOG_NOTICE, "------------------------" );
213
214}
215
216assimp_model* nv::assimp_loader::release_merged_model()
217{
218        if ( m_scene == nullptr || m_mesh_count == 0 ) return nullptr;
219        assimp_model* model = new assimp_model;
220
221        for ( size_t m = 0; m < m_mesh_count; ++m )
222        {
223                model->meshes.push_back( release_mesh_data(m) );
224        }
225
226        std::unordered_map< std::string, uint16 > names;
227        for ( unsigned int m = 0; m < model->meshes.size(); ++m )
228        {
229                nv::sint16 translate[64];
230                std::vector< assimp_bone > bones;
231                load_bones( m, bones );
232                for ( unsigned int b = 0; b < bones.size(); ++b )
233                {
234
235                        nv::assimp_bone& bone = bones[b];
236                        auto iname = names.find( bone.name );
237                        if ( iname == names.end() )
238                        {
239                                NV_ASSERT( model->bones.size() < 64, "Too many bones to merge!" );
240                                nv::sint16 index = (nv::sint16)model->bones.size();
241                                model->bones.push_back( bone );
242                                names[ bone.name ] = index;
243                                translate[b] = index;
244                        }
245                        else
246                        {
247                                translate[b] = (nv::sint16)iname->second;
248                        }
249                }
250                if ( m > 0 )
251                {
252                        mesh_data* mesh = model->meshes[m];
253                        nv::mesh_raw_channel* channel = mesh->get_channel_data()[0];
254                        nv::assimp_skinned_vtx* va = (nv::assimp_skinned_vtx*)channel->data;
255                        for ( unsigned v = 0; v < channel->count; ++v )
256                        {
257                                nv::assimp_skinned_vtx& vertex = va[v];
258
259                                for (nv::uint32 i = 0 ; i < 4; ++i)
260                                {
261                                        if ( vertex.boneweight[i] > 0.0f )
262                                        {
263                                                vertex.boneindex[i] = translate[vertex.boneindex[i]];
264                                        }
265                                }
266                        }
267                }
268        }
269        return model;
270}
271
Note: See TracBrowser for help on using the repository browser.