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

Last change on this file since 458 was 458, checked in by epyon, 10 years ago
  • starting work on stl/type_erasure
  • mesh_creator - fixed tangent generation!
  • skeletal_mesh - allow for empty meshes
File size: 8.4 KB
RevLine 
[395]1// Copyright (C) 2011-2015 ChaosForge Ltd
2// http://chaosforge.org/
3//
4// This file is part of Nova libraries.
5// For conditions of distribution and use, see copying.txt file in root folder.
[227]6
7#include "nv/gfx/skeletal_mesh.hh"
8
9#include "nv/interface/context.hh"
10#include "nv/interface/device.hh"
[392]11#include "nv/stl/unordered_map.hh"
[227]12
[430]13nv::skeletal_mesh_cpu::skeletal_mesh_cpu( context* a_context, const data_channel_set* a_mesh_data, const mesh_nodes_data* bones )
[302]14        : skeletal_mesh( a_context )
[227]15{
[412]16        const raw_data_channel* pnt_chan   = a_mesh_data->get_channel<md5_vtx_pnt>();
17        const raw_data_channel* pntiw_chan = a_mesh_data->get_channel<md5_vtx_pntiw>();
18
[415]19        m_pntdata.assign( pnt_chan->data_cast< md5_vtx_pnt >(), pnt_chan->size() );
[428]20        m_bone_offset.resize( bones->size() );
21        m_transform.resize( bones->size() );
[289]22
[428]23        for ( uint32 i = 0; i < bones->size(); ++i )
[287]24        {
[427]25                m_bone_offset[i] = transform( (*bones)[i]->get_transform() );
[287]26        }
[412]27
[287]28        m_vtx_data  = a_mesh_data->get_channel_data<md5_vtx_pntiw>();
[416]29        m_indices   = a_mesh_data->get_channel_size( slot::INDEX );
[412]30        m_va        = a_context->create_vertex_array();
31
[416]32        //array_view< raw_data_channel* > channels = a_mesh_data->get_raw_channels();
[418]33        for ( auto& channel : *a_mesh_data )
[412]34        {
[416]35                //const raw_data_channel* channel = channels[ch];
[418]36                if ( channel.size() > 0 && &channel != pntiw_chan )
[412]37                {
[418]38                        const data_descriptor& desc = channel.descriptor();
[412]39                        if ( desc[0].vslot == slot::INDEX )
40                        {
[418]41                                buffer b = a_context->get_device()->create_buffer( INDEX_BUFFER, STREAM_DRAW, channel.raw_size(), channel.raw_data() );
[412]42                                a_context->set_index_buffer( m_va, b, desc[0].etype, true );
43                        }
44                        else
45                        {
[418]46                                buffer b = a_context->get_device()->create_buffer( VERTEX_BUFFER, STREAM_DRAW, channel.raw_size(), channel.raw_data() );
[417]47                                a_context->add_vertex_buffers( m_va, b, desc );
[412]48                        }
49                }
50        }
51
[313]52        m_pbuffer   = a_context->find_buffer( m_va, slot::POSITION );
[239]53}
[227]54
[296]55void nv::skeletal_mesh_cpu::update_animation( animation_entry* a_anim, uint32 a_anim_time )
[227]56{
[283]57        if ( a_anim )
[241]58        {
[406]59                skeletal_animation_entry_cpu * anim = static_cast<skeletal_animation_entry_cpu*>( a_anim );
60                anim->update_skeleton( m_transform.data(), static_cast<float>( a_anim_time ) );
[287]61                {
62                        size_t skeleton_size = m_bone_offset.size();
63                        size_t vertex_count  = m_pntdata.size();
64                        m_pos_offset.resize( skeleton_size );
65                        for ( unsigned int i = 0; i < skeleton_size; ++i )
66                        {
67                                m_pos_offset[i] = m_transform[i] * m_bone_offset[i];
68                        }
69
[383]70                        fill( m_pntdata.raw_data(), m_pntdata.raw_data() + m_pntdata.raw_size(), 0 );
[287]71                        for ( unsigned int i = 0; i < vertex_count; ++i )
72                        {
73                                const md5_vtx_pntiw& vert = m_vtx_data[i];
74
[406]75                                for ( int j = 0; j < 4; ++j )
[287]76                                {
[406]77                                        unsigned index = unsigned( vert.boneindex[j] );
[323]78                                        float weight   = vert.boneweight[j];
[287]79                                        const quat& orient      = m_transform[index].get_orientation();
80                                        const transform& offset = m_pos_offset[index];
81                                        m_pntdata[i].position += offset.transformed( vert.position )        * weight;
82                                        m_pntdata[i].normal   += ( orient * vert.normal  ) * weight;
83                                        m_pntdata[i].tangent  += ( orient * vert.tangent ) * weight;
84                                }
85                        }
86                }
87
[302]88                m_context->update( m_pbuffer, m_pntdata.data(), 0, m_pntdata.raw_size() );
[227]89        }
90}
91
[289]92
[419]93void nv::skeletal_animation_entry_cpu::initialize()
94{
[427]95        for ( auto bone : *m_node_data )
[419]96        {
[427]97                if ( bone->size() > 0 )
[419]98                {
[427]99                        m_interpolation_key = bone->get_interpolation_key();
[419]100                        break;
101                }
102        }
103}
104
[296]105void nv::skeletal_animation_entry_cpu::update_skeleton( transform* skeleton, float time ) const
[289]106{
[406]107        float frame_duration = 1000.f / static_cast<float>( m_node_data->get_frame_rate() );
[289]108        float anim_duration = frame_duration * m_node_data->get_duration();
109        float new_time = fmodf( time, anim_duration ) * 0.001f;
110
111        float frame_num = new_time * m_node_data->get_frame_rate();
[428]112        for ( size_t i = 0; i < m_node_data->size(); ++i )
[289]113        {
[427]114                raw_channel_interpolator interpolator( (*m_node_data)[i], m_interpolation_key );
[419]115                skeleton[i] = interpolator.get< transform >( frame_num );
[289]116        }
117}
118
[288]119void nv::skeletal_animation_entry_gpu::initialize()
[283]120{
[287]121        m_prepared  = false;
122        m_children  = nullptr;
123        m_offsets   = nullptr;
[428]124        m_bone_ids  = new sint16[m_node_data->size()];
[287]125
[419]126        NV_ASSERT( m_node_data, "node data empty!" );
127
[287]128        if ( !m_node_data->is_flat() )
129        {
[428]130                m_children = new vector< uint32 >[m_node_data->size()];
131                for ( uint32 n = 0; n < m_node_data->size(); ++n )
[287]132                {
[427]133                        const data_channel_set* node = (*m_node_data)[n];
134                        if ( node->get_parent_id() != -1 )
[287]135                        {
[427]136                                m_children[ node->get_parent_id()].push_back( n );
[287]137                        }
138                }
139        }
[283]140}
141
[287]142void nv::skeletal_animation_entry_gpu::update_skeleton( mat4* data, uint32 time ) const
[283]143{
[290]144        float tick_time = ( time * 0.001f ) * m_frame_rate;
145        float anim_time = m_start;
146        if ( m_duration > 0.0f ) anim_time += fmodf( tick_time, m_duration );
[287]147
148        if ( !m_node_data->is_flat() )
149        {
150                animate_rec( data, anim_time, 0, mat4() );
151                return;
152        }
153
[428]154        for ( uint32 n = 0; n < m_node_data->size(); ++n )
[287]155                if ( m_bone_ids[n] >= 0 )
156                {
[428]157                        const data_channel_set* node = (*m_node_data)[n];
[427]158                        nv::mat4 node_mat( node->get_transform() );
[287]159
[427]160                        if ( node->size() > 0 )
[287]161                        {
[427]162                                raw_channel_interpolator interpolator( node, m_interpolation_key );
[419]163                                node_mat = interpolator.get< mat4 >( anim_time );
[287]164                        }
165
166                        sint16 bone_id = m_bone_ids[n];
167                        data[ bone_id ] = node_mat * m_offsets[ bone_id ];
168                }
[283]169}
170
[287]171void nv::skeletal_animation_entry_gpu::prepare( const mesh_nodes_data* bones )
[283]172{
[287]173        if ( m_prepared ) return;
[420]174        unordered_map< uint64, uint16 > bone_names;
[428]175        m_offsets = new mat4[ bones->size() ];
176        for ( nv::uint16 bi = 0; bi < bones->size(); ++bi )
[287]177        {
[428]178                const data_channel_set* bone = (*bones)[ bi ];
[431]179                bone_names[ bone->get_name().value() ] = bi;
[427]180                m_offsets[bi] = bone->get_transform();
[287]181        }
182
[428]183        for ( uint32 n = 0; n < m_node_data->size(); ++n )
[287]184        {
[428]185                const data_channel_set* node = (*m_node_data)[ n ];
[287]186                sint16 bone_id = -1;
187
[431]188                auto bi = bone_names.find( node->get_name().value() );
[287]189                if ( bi != bone_names.end() )
190                {
[406]191                        bone_id = sint16( bi->second );
[287]192                }
193                m_bone_ids[n] = bone_id;
[419]194
[427]195                if ( m_interpolation_key.size() == 0 && node->size() > 0 )
196                        m_interpolation_key = node->get_interpolation_key();
[419]197
[287]198        }
199        m_prepared = true;
[283]200}
201
[287]202void nv::skeletal_animation_entry_gpu::animate_rec( mat4* data, float time, uint32 node_id, const mat4& parent_mat ) const
203{
204        // TODO: fix transforms, which are now embedded,
205        //       see note in assimp_loader.cc:load_node
[428]206        const data_channel_set* node = ( *m_node_data )[ node_id ];
[427]207        mat4 node_mat( node->get_transform() );
[287]208
[427]209        if ( node->size() > 0 )
[287]210        {
[427]211                raw_channel_interpolator interpolator( node, m_interpolation_key );
[419]212                node_mat = interpolator.get< mat4 >( time );
[287]213        }
214
215        mat4 global_mat = parent_mat * node_mat;
216
217        sint16 bone_id = m_bone_ids[ node_id ];
218        if ( bone_id >= 0 )
219        {
220                data[ bone_id ] = global_mat * m_offsets[ bone_id ];
221        }
222
223        for ( auto child : m_children[ node_id ] )
224        {
225                animate_rec( data, time, child, global_mat );
226        }
227}
228
229nv::skeletal_animation_entry_gpu::~skeletal_animation_entry_gpu()
230{
231        delete[] m_offsets;
232        delete[] m_children;
233        delete[] m_bone_ids;
234}
235
[430]236nv::skeletal_mesh_gpu::skeletal_mesh_gpu( context* a_context, const data_channel_set* a_mesh, const mesh_nodes_data* a_bone_data )
[458]237        : skeletal_mesh( a_context ), m_bone_data( a_bone_data ), m_index_count( 0 ), m_transform( nullptr )
[287]238{
[458]239        if ( a_mesh )
240        {
241                m_va = a_context->create_vertex_array( a_mesh, nv::STATIC_DRAW );
242                m_index_count = a_mesh->get_channel_size( slot::INDEX );
243        }
[287]244        if ( m_bone_data )
245        {
[428]246                m_transform = new mat4[ m_bone_data->size() ];
[287]247        }
248}
249
[283]250void nv::skeletal_mesh_gpu::update_animation( animation_entry* a_anim, uint32 a_anim_time )
251{
[287]252        if ( m_bone_data && a_anim )
[283]253        {
[406]254                skeletal_animation_entry_gpu * anim = static_cast<skeletal_animation_entry_gpu*>( a_anim );
[296]255                anim->prepare( m_bone_data );
[287]256                anim->update_skeleton( m_transform, a_anim_time );
[283]257        }
258}
259
[303]260void nv::skeletal_mesh_gpu::update( program a_program )
[283]261{
[287]262        if ( m_bone_data )
[428]263                m_context->get_device()->set_opt_uniform_array( a_program, "nv_m_bones", m_transform, m_bone_data->size() );
[287]264}
265
266nv::transform nv::skeletal_mesh_gpu::get_node_transform( uint32 node_id ) const
267{
[290]268        if ( node_id == 0 ) return transform();
[458]269        if ( node_id == uint32(-1) ) return transform( m_transform[0] );
[287]270        return transform( m_transform[ node_id ] );
271}
272
273nv::mat4 nv::skeletal_mesh_gpu::get_node_matrix( uint32 node_id ) const
274{
275        return m_transform[ node_id ];
276}
Note: See TracBrowser for help on using the repository browser.