source: trunk/src/gfx/skeletal_mesh.cc @ 287

Last change on this file since 287 was 287, checked in by epyon, 11 years ago
  • mesh_data_pack's in every format
  • md5_mesh_data removed, uses standard mesh_data
  • BONE_ARRAY in NMD is now a simple set of animation nodes
  • bone and animation node concepts merged
  • several minor changes
File size: 7.2 KB
RevLine 
[227]1// Copyright (C) 2011 Kornel Kisielewicz
2// This file is part of NV Libraries.
3// For conditions of distribution and use, see copyright notice in nv.hh
4
5#include "nv/gfx/skeletal_mesh.hh"
6
7#include <glm/gtc/matrix_access.hpp>
8#include <glm/gtx/matrix_interpolation.hpp>
9#include "nv/interface/context.hh"
10#include "nv/interface/device.hh"
11
12
[287]13nv::skeletal_mesh::skeletal_mesh( device* a_device, const mesh_data* a_mesh_data, const mesh_nodes_data* bones )
[231]14        : animated_mesh()
[287]15        , m_data( a_mesh_data )
[227]16{
[287]17        const mesh_raw_channel* pnt_chan = a_mesh_data->get_channel<md5_vtx_pnt>();
18        m_pntdata.assign( (const md5_vtx_pnt*)pnt_chan->data, pnt_chan->count );
19        m_bone_offset.resize( bones->get_count() );
20        for ( uint32 i = 0; i < bones->get_count(); ++i )
21        {
22                m_bone_offset[i] = transform( bones->get_node(i)->transform );
23        }
24        m_vtx_data  = a_mesh_data->get_channel_data<md5_vtx_pntiw>();
25        m_indices   = a_mesh_data->get_count();
[275]26        m_va        = a_device->create_vertex_array( a_mesh_data, nv::STREAM_DRAW );
[239]27}
[227]28
[283]29void nv::skeletal_mesh::update_animation( animation_entry* a_anim, uint32 a_anim_time )
[227]30{
[283]31        if ( a_anim )
[241]32        {
[283]33                skeletal_animation_entry * anim = (skeletal_animation_entry*)a_anim;
34                float frame_duration = 1000.f / (float)anim->get_frame_rate();
35                uint32 anim_duration = uint32( frame_duration * (float)anim->get_frame_count() );
36                uint32 new_time = a_anim_time % anim_duration;
37                anim->update_skeleton( m_transform.data(), (float)new_time * 0.001f );
[287]38
39                //m_mesh_data->apply( m_transform.data() );
40                {
41                        size_t skeleton_size = m_bone_offset.size();
42                        size_t vertex_count  = m_pntdata.size();
43                        m_pos_offset.resize( skeleton_size );
44                        for ( unsigned int i = 0; i < skeleton_size; ++i )
45                        {
46                                m_pos_offset[i] = m_transform[i] * m_bone_offset[i];
47                        }
48
49                        std::fill( m_pntdata.raw_data(), m_pntdata.raw_data() + m_pntdata.raw_size(), 0 );
50                        for ( unsigned int i = 0; i < vertex_count; ++i )
51                        {
52                                const md5_vtx_pntiw& vert = m_vtx_data[i];
53
54                                for ( size_t j = 0; j < 4; ++j )
55                                {
56                                        int   index  = vert.boneindex[j];
57                                        float weight = vert.boneweight[j];
58                                        const quat& orient      = m_transform[index].get_orientation();
59                                        const transform& offset = m_pos_offset[index];
60                                        m_pntdata[i].position += offset.transformed( vert.position )        * weight;
61                                        m_pntdata[i].normal   += ( orient * vert.normal  ) * weight;
62                                        m_pntdata[i].tangent  += ( orient * vert.tangent ) * weight;
63                                }
64                        }
65                }
66
[281]67                vertex_buffer* vb = m_va->find_buffer( nv::slot::POSITION );
[239]68                vb->bind();
[287]69                vb->update( m_pntdata.data(), 0, m_pntdata.raw_size() );
[239]70                vb->unbind();
[227]71        }
72}
73
[230]74nv::skeletal_mesh::~skeletal_mesh()
[227]75{
[230]76        delete m_va;
[227]77}
78
[230]79void nv::skeletal_mesh::run_animation( animation_entry* a_anim )
[227]80{
[252]81        if ( a_anim != nullptr )
82        {
[283]83                skeletal_animation_entry * anim = (skeletal_animation_entry*)(a_anim);
84                m_transform.resize( anim->get_num_joints() );
85                update_animation( a_anim, 0 );
[252]86        }
[283]87}
88
[287]89
90nv::skeletal_animation_entry_gpu::skeletal_animation_entry_gpu( const std::string& name, const mesh_nodes_data* anim, bool a_looping )
91        : animation_entry( name )
92        , m_node_data( anim )
[283]93{
[287]94        uint32 node_count = m_node_data->get_count();
95
96        m_prepared  = false;
97        m_looping   = a_looping;
98        m_children  = nullptr;
99        m_offsets   = nullptr;
100        m_bone_ids  = new sint16[ node_count ];
101
102        if ( !m_node_data->is_flat() )
103        {
104                m_children = new std::vector< uint32 >[ node_count ];
105                for ( uint32 n = 0; n < node_count; ++n )
106                {
107                        const mesh_node_data* node = m_node_data->get_node(n);
108                        if ( node->parent_id != -1 )
109                        {
110                                m_children[ node->parent_id ].push_back( n );
111                        }
112                }
113        }
[283]114}
115
[287]116void nv::skeletal_animation_entry_gpu::update_skeleton( mat4* data, uint32 time ) const
[283]117{
[287]118        float tick_time = ( time * 0.001f ) * m_node_data->get_frame_rate();
119        float anim_time = fmodf( tick_time, m_node_data->get_duration() );
120
121        if ( !m_node_data->is_flat() )
122        {
123                animate_rec( data, anim_time, 0, mat4() );
124                return;
125        }
126
127        for ( uint32 n = 0; n < m_node_data->get_count(); ++n )
128                if ( m_bone_ids[n] >= 0 )
129                {
130                        const mesh_node_data* node = m_node_data->get_node(n);
131                        nv::mat4 node_mat( node->transform );
132
133                        if ( node->data )
134                        {
135                                node_mat = node->data->get_matrix( anim_time );
136                        }
137
138                        sint16 bone_id = m_bone_ids[n];
139                        data[ bone_id ] = node_mat * m_offsets[ bone_id ];
140                }
[283]141}
142
[287]143void nv::skeletal_animation_entry_gpu::prepare( const mesh_nodes_data* bones )
[283]144{
[287]145        if ( m_prepared ) return;
146        std::unordered_map< std::string, nv::uint16 > bone_names;
147        m_offsets = new mat4[ bones->get_count() ];
148        for ( nv::uint16 bi = 0; bi < bones->get_count(); ++bi )
149        {
150                const mesh_node_data* bone = bones->get_node(bi);
151                bone_names[ bone->name ] = bi;
152                m_offsets[bi] = bone->transform;
153        }
154
155        for ( uint32 n = 0; n < m_node_data->get_count(); ++n )
156        {
157                const mesh_node_data* node = m_node_data->get_node(n);
158                sint16 bone_id = -1;
159
160                auto bi = bone_names.find( node->name );
161                if ( bi != bone_names.end() )
162                {
163                        bone_id = bi->second;
164                }
165                m_bone_ids[n] = bone_id;
166        }
167        m_prepared = true;
[283]168}
169
[287]170void nv::skeletal_animation_entry_gpu::animate_rec( mat4* data, float time, uint32 node_id, const mat4& parent_mat ) const
171{
172        // TODO: fix transforms, which are now embedded,
173        //       see note in assimp_loader.cc:load_node
174        const mesh_node_data* node = m_node_data->get_node( node_id );
175        mat4 node_mat( node->transform );
176
177        if ( node->data )
178        {
179                node_mat = node->data->get_matrix( time );
180        }
181
182        mat4 global_mat = parent_mat * node_mat;
183
184        sint16 bone_id = m_bone_ids[ node_id ];
185        if ( bone_id >= 0 )
186        {
187                data[ bone_id ] = global_mat * m_offsets[ bone_id ];
188        }
189
190        for ( auto child : m_children[ node_id ] )
191        {
192                animate_rec( data, time, child, global_mat );
193        }
194}
195
196nv::skeletal_animation_entry_gpu::~skeletal_animation_entry_gpu()
197{
198        delete[] m_offsets;
199        delete[] m_children;
200        delete[] m_bone_ids;
201}
202
203nv::skeletal_mesh_gpu::skeletal_mesh_gpu( device* a_device, const mesh_data* a_mesh, const mesh_nodes_data* a_bone_data )
204        : animated_mesh(), m_bone_data( a_bone_data ), m_transform( nullptr )
205{
206        m_va          = a_device->create_vertex_array( a_mesh, nv::STATIC_DRAW );
207        m_index_count = a_mesh->get_count();
208        if ( m_bone_data )
209        {
210                m_transform = new mat4[ m_bone_data->get_count() ];
211        }
212}
213
[283]214void nv::skeletal_mesh_gpu::run_animation( animation_entry* a_anim )
215{
[287]216        if ( m_bone_data && a_anim != nullptr )
[252]217        {
[283]218                skeletal_animation_entry_gpu * anim = (skeletal_animation_entry_gpu*)(a_anim);
[287]219                anim->prepare( m_bone_data );
[283]220                update_animation( a_anim, 0 );
[252]221        }
[227]222}
[283]223
224void nv::skeletal_mesh_gpu::update_animation( animation_entry* a_anim, uint32 a_anim_time )
225{
[287]226        if ( m_bone_data && a_anim )
[283]227        {
228                skeletal_animation_entry_gpu * anim = (skeletal_animation_entry_gpu*)a_anim;
[287]229                anim->update_skeleton( m_transform, a_anim_time );
[283]230        }
231}
232
233void nv::skeletal_mesh_gpu::update( program* a_program ) const
234{
[287]235        if ( m_bone_data )
236                a_program->set_uniform_array( "nv_m_bones", m_transform, m_bone_data->get_count() );
237}
238
239nv::transform nv::skeletal_mesh_gpu::get_node_transform( uint32 node_id ) const
240{
241        return transform( m_transform[ node_id ] );
242}
243
244nv::mat4 nv::skeletal_mesh_gpu::get_node_matrix( uint32 node_id ) const
245{
246        return m_transform[ node_id ];
247}
Note: See TracBrowser for help on using the repository browser.