[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] | 13 | nv::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() );
|
---|
[289] | 20 | m_transform.resize( bones->get_count() );
|
---|
| 21 |
|
---|
[287] | 22 | for ( uint32 i = 0; i < bones->get_count(); ++i )
|
---|
| 23 | {
|
---|
| 24 | m_bone_offset[i] = transform( bones->get_node(i)->transform );
|
---|
| 25 | }
|
---|
| 26 | m_vtx_data = a_mesh_data->get_channel_data<md5_vtx_pntiw>();
|
---|
| 27 | m_indices = a_mesh_data->get_count();
|
---|
[275] | 28 | m_va = a_device->create_vertex_array( a_mesh_data, nv::STREAM_DRAW );
|
---|
[239] | 29 | }
|
---|
[227] | 30 |
|
---|
[283] | 31 | void nv::skeletal_mesh::update_animation( animation_entry* a_anim, uint32 a_anim_time )
|
---|
[227] | 32 | {
|
---|
[283] | 33 | if ( a_anim )
|
---|
[241] | 34 | {
|
---|
[283] | 35 | skeletal_animation_entry * anim = (skeletal_animation_entry*)a_anim;
|
---|
[289] | 36 | anim->update_skeleton( m_transform.data(), (float)a_anim_time );
|
---|
[287] | 37 | {
|
---|
| 38 | size_t skeleton_size = m_bone_offset.size();
|
---|
| 39 | size_t vertex_count = m_pntdata.size();
|
---|
| 40 | m_pos_offset.resize( skeleton_size );
|
---|
| 41 | for ( unsigned int i = 0; i < skeleton_size; ++i )
|
---|
| 42 | {
|
---|
| 43 | m_pos_offset[i] = m_transform[i] * m_bone_offset[i];
|
---|
| 44 | }
|
---|
| 45 |
|
---|
| 46 | std::fill( m_pntdata.raw_data(), m_pntdata.raw_data() + m_pntdata.raw_size(), 0 );
|
---|
| 47 | for ( unsigned int i = 0; i < vertex_count; ++i )
|
---|
| 48 | {
|
---|
| 49 | const md5_vtx_pntiw& vert = m_vtx_data[i];
|
---|
| 50 |
|
---|
| 51 | for ( size_t j = 0; j < 4; ++j )
|
---|
| 52 | {
|
---|
| 53 | int index = vert.boneindex[j];
|
---|
| 54 | float weight = vert.boneweight[j];
|
---|
| 55 | const quat& orient = m_transform[index].get_orientation();
|
---|
| 56 | const transform& offset = m_pos_offset[index];
|
---|
| 57 | m_pntdata[i].position += offset.transformed( vert.position ) * weight;
|
---|
| 58 | m_pntdata[i].normal += ( orient * vert.normal ) * weight;
|
---|
| 59 | m_pntdata[i].tangent += ( orient * vert.tangent ) * weight;
|
---|
| 60 | }
|
---|
| 61 | }
|
---|
| 62 | }
|
---|
| 63 |
|
---|
[281] | 64 | vertex_buffer* vb = m_va->find_buffer( nv::slot::POSITION );
|
---|
[239] | 65 | vb->bind();
|
---|
[287] | 66 | vb->update( m_pntdata.data(), 0, m_pntdata.raw_size() );
|
---|
[239] | 67 | vb->unbind();
|
---|
[227] | 68 | }
|
---|
| 69 | }
|
---|
| 70 |
|
---|
[289] | 71 |
|
---|
| 72 | void nv::skeletal_animation_entry::update_skeleton( transform* skeleton, float time ) const
|
---|
| 73 | {
|
---|
| 74 | float frame_duration = 1000.f / (float)m_node_data->get_frame_rate();
|
---|
| 75 | float anim_duration = frame_duration * m_node_data->get_duration();
|
---|
| 76 | float new_time = fmodf( time, anim_duration ) * 0.001f;
|
---|
| 77 |
|
---|
| 78 | float frame_num = new_time * m_node_data->get_frame_rate();
|
---|
| 79 | for ( size_t i = 0; i < m_node_data->get_count(); ++i )
|
---|
| 80 | {
|
---|
| 81 | skeleton[i] = m_node_data->get_node(i)->data->get_transform( frame_num );
|
---|
| 82 | }
|
---|
| 83 | }
|
---|
| 84 |
|
---|
| 85 |
|
---|
| 86 |
|
---|
[230] | 87 | nv::skeletal_mesh::~skeletal_mesh()
|
---|
[227] | 88 | {
|
---|
[230] | 89 | delete m_va;
|
---|
[227] | 90 | }
|
---|
| 91 |
|
---|
[230] | 92 | void nv::skeletal_mesh::run_animation( animation_entry* a_anim )
|
---|
[227] | 93 | {
|
---|
[252] | 94 | if ( a_anim != nullptr )
|
---|
| 95 | {
|
---|
[283] | 96 | update_animation( a_anim, 0 );
|
---|
[252] | 97 | }
|
---|
[283] | 98 | }
|
---|
| 99 |
|
---|
[288] | 100 | void nv::skeletal_animation_entry_gpu::initialize()
|
---|
[283] | 101 | {
|
---|
[287] | 102 | m_prepared = false;
|
---|
| 103 | m_children = nullptr;
|
---|
| 104 | m_offsets = nullptr;
|
---|
[288] | 105 | uint32 node_count = m_node_data->get_count();
|
---|
[287] | 106 | m_bone_ids = new sint16[ node_count ];
|
---|
| 107 |
|
---|
| 108 | if ( !m_node_data->is_flat() )
|
---|
| 109 | {
|
---|
| 110 | m_children = new std::vector< uint32 >[ node_count ];
|
---|
| 111 | for ( uint32 n = 0; n < node_count; ++n )
|
---|
| 112 | {
|
---|
| 113 | const mesh_node_data* node = m_node_data->get_node(n);
|
---|
| 114 | if ( node->parent_id != -1 )
|
---|
| 115 | {
|
---|
| 116 | m_children[ node->parent_id ].push_back( n );
|
---|
| 117 | }
|
---|
| 118 | }
|
---|
| 119 | }
|
---|
[283] | 120 | }
|
---|
| 121 |
|
---|
[287] | 122 | void nv::skeletal_animation_entry_gpu::update_skeleton( mat4* data, uint32 time ) const
|
---|
[283] | 123 | {
|
---|
[290] | 124 | float tick_time = ( time * 0.001f ) * m_frame_rate;
|
---|
| 125 | float anim_time = m_start;
|
---|
| 126 | if ( m_duration > 0.0f ) anim_time += fmodf( tick_time, m_duration );
|
---|
[287] | 127 |
|
---|
| 128 | if ( !m_node_data->is_flat() )
|
---|
| 129 | {
|
---|
| 130 | animate_rec( data, anim_time, 0, mat4() );
|
---|
| 131 | return;
|
---|
| 132 | }
|
---|
| 133 |
|
---|
| 134 | for ( uint32 n = 0; n < m_node_data->get_count(); ++n )
|
---|
| 135 | if ( m_bone_ids[n] >= 0 )
|
---|
| 136 | {
|
---|
| 137 | const mesh_node_data* node = m_node_data->get_node(n);
|
---|
| 138 | nv::mat4 node_mat( node->transform );
|
---|
| 139 |
|
---|
| 140 | if ( node->data )
|
---|
| 141 | {
|
---|
| 142 | node_mat = node->data->get_matrix( anim_time );
|
---|
| 143 | }
|
---|
| 144 |
|
---|
| 145 | sint16 bone_id = m_bone_ids[n];
|
---|
| 146 | data[ bone_id ] = node_mat * m_offsets[ bone_id ];
|
---|
| 147 | }
|
---|
[283] | 148 | }
|
---|
| 149 |
|
---|
[287] | 150 | void nv::skeletal_animation_entry_gpu::prepare( const mesh_nodes_data* bones )
|
---|
[283] | 151 | {
|
---|
[287] | 152 | if ( m_prepared ) return;
|
---|
| 153 | std::unordered_map< std::string, nv::uint16 > bone_names;
|
---|
| 154 | m_offsets = new mat4[ bones->get_count() ];
|
---|
| 155 | for ( nv::uint16 bi = 0; bi < bones->get_count(); ++bi )
|
---|
| 156 | {
|
---|
| 157 | const mesh_node_data* bone = bones->get_node(bi);
|
---|
| 158 | bone_names[ bone->name ] = bi;
|
---|
| 159 | m_offsets[bi] = bone->transform;
|
---|
| 160 | }
|
---|
| 161 |
|
---|
| 162 | for ( uint32 n = 0; n < m_node_data->get_count(); ++n )
|
---|
| 163 | {
|
---|
| 164 | const mesh_node_data* node = m_node_data->get_node(n);
|
---|
| 165 | sint16 bone_id = -1;
|
---|
| 166 |
|
---|
| 167 | auto bi = bone_names.find( node->name );
|
---|
| 168 | if ( bi != bone_names.end() )
|
---|
| 169 | {
|
---|
| 170 | bone_id = bi->second;
|
---|
| 171 | }
|
---|
| 172 | m_bone_ids[n] = bone_id;
|
---|
| 173 | }
|
---|
| 174 | m_prepared = true;
|
---|
[283] | 175 | }
|
---|
| 176 |
|
---|
[287] | 177 | void nv::skeletal_animation_entry_gpu::animate_rec( mat4* data, float time, uint32 node_id, const mat4& parent_mat ) const
|
---|
| 178 | {
|
---|
| 179 | // TODO: fix transforms, which are now embedded,
|
---|
| 180 | // see note in assimp_loader.cc:load_node
|
---|
| 181 | const mesh_node_data* node = m_node_data->get_node( node_id );
|
---|
| 182 | mat4 node_mat( node->transform );
|
---|
| 183 |
|
---|
| 184 | if ( node->data )
|
---|
| 185 | {
|
---|
| 186 | node_mat = node->data->get_matrix( time );
|
---|
| 187 | }
|
---|
| 188 |
|
---|
| 189 | mat4 global_mat = parent_mat * node_mat;
|
---|
| 190 |
|
---|
| 191 | sint16 bone_id = m_bone_ids[ node_id ];
|
---|
| 192 | if ( bone_id >= 0 )
|
---|
| 193 | {
|
---|
| 194 | data[ bone_id ] = global_mat * m_offsets[ bone_id ];
|
---|
| 195 | }
|
---|
| 196 |
|
---|
| 197 | for ( auto child : m_children[ node_id ] )
|
---|
| 198 | {
|
---|
| 199 | animate_rec( data, time, child, global_mat );
|
---|
| 200 | }
|
---|
| 201 | }
|
---|
| 202 |
|
---|
| 203 | nv::skeletal_animation_entry_gpu::~skeletal_animation_entry_gpu()
|
---|
| 204 | {
|
---|
| 205 | delete[] m_offsets;
|
---|
| 206 | delete[] m_children;
|
---|
| 207 | delete[] m_bone_ids;
|
---|
| 208 | }
|
---|
| 209 |
|
---|
| 210 | nv::skeletal_mesh_gpu::skeletal_mesh_gpu( device* a_device, const mesh_data* a_mesh, const mesh_nodes_data* a_bone_data )
|
---|
| 211 | : animated_mesh(), m_bone_data( a_bone_data ), m_transform( nullptr )
|
---|
| 212 | {
|
---|
| 213 | m_va = a_device->create_vertex_array( a_mesh, nv::STATIC_DRAW );
|
---|
| 214 | m_index_count = a_mesh->get_count();
|
---|
| 215 | if ( m_bone_data )
|
---|
| 216 | {
|
---|
| 217 | m_transform = new mat4[ m_bone_data->get_count() ];
|
---|
| 218 | }
|
---|
| 219 | }
|
---|
| 220 |
|
---|
[283] | 221 | void nv::skeletal_mesh_gpu::run_animation( animation_entry* a_anim )
|
---|
| 222 | {
|
---|
[287] | 223 | if ( m_bone_data && a_anim != nullptr )
|
---|
[252] | 224 | {
|
---|
[283] | 225 | skeletal_animation_entry_gpu * anim = (skeletal_animation_entry_gpu*)(a_anim);
|
---|
[287] | 226 | anim->prepare( m_bone_data );
|
---|
[290] | 227 | update_animation( a_anim, uint32( anim->get_start() * 1000.f * anim->get_frame_rate() * 1000 ) );
|
---|
[252] | 228 | }
|
---|
[227] | 229 | }
|
---|
[283] | 230 |
|
---|
| 231 | void nv::skeletal_mesh_gpu::update_animation( animation_entry* a_anim, uint32 a_anim_time )
|
---|
| 232 | {
|
---|
[287] | 233 | if ( m_bone_data && a_anim )
|
---|
[283] | 234 | {
|
---|
| 235 | skeletal_animation_entry_gpu * anim = (skeletal_animation_entry_gpu*)a_anim;
|
---|
[287] | 236 | anim->update_skeleton( m_transform, a_anim_time );
|
---|
[283] | 237 | }
|
---|
| 238 | }
|
---|
| 239 |
|
---|
| 240 | void nv::skeletal_mesh_gpu::update( program* a_program ) const
|
---|
| 241 | {
|
---|
[287] | 242 | if ( m_bone_data )
|
---|
[290] | 243 | a_program->set_opt_uniform_array( "nv_m_bones", m_transform, m_bone_data->get_count() );
|
---|
[287] | 244 | }
|
---|
| 245 |
|
---|
| 246 | nv::transform nv::skeletal_mesh_gpu::get_node_transform( uint32 node_id ) const
|
---|
| 247 | {
|
---|
[290] | 248 | if ( node_id == 0 ) return transform();
|
---|
[287] | 249 | return transform( m_transform[ node_id ] );
|
---|
| 250 | }
|
---|
| 251 |
|
---|
| 252 | nv::mat4 nv::skeletal_mesh_gpu::get_node_matrix( uint32 node_id ) const
|
---|
| 253 | {
|
---|
| 254 | return m_transform[ node_id ];
|
---|
| 255 | }
|
---|