2 * Copyright (C) 2021-2022 Mt.ZERO Software, Harry Godden - All Rights Reserved
36 mdl_keyframe
*anim_data
;
45 u32 lower
, upper
, target
, pole
;
56 VG_STATIC u32
skeleton_bone_id( struct skeleton
*skele
, const char *name
)
58 for( u32 i
=1; i
<skele
->bone_count
; i
++ )
60 if( !strcmp( skele
->bones
[i
].name
, name
))
64 vg_error( "skeleton_bone_id( *, \"%s\" );\n", name
);
65 vg_fatal_exit_loop( "Bone does not exist\n" );
70 VG_STATIC
void keyframe_copy_pose( mdl_keyframe
*kfa
, mdl_keyframe
*kfb
,
73 for( int i
=0; i
<num
; i
++ )
78 * Lerp between two sets of keyframes and store in dest. Rotations use Nlerp.
80 VG_STATIC
void keyframe_lerp_pose( mdl_keyframe
*kfa
, mdl_keyframe
*kfb
,
81 float t
, mdl_keyframe
*kfd
, int count
)
85 keyframe_copy_pose( kfa
, kfd
, count
);
90 keyframe_copy_pose( kfb
, kfd
, count
);
94 for( int i
=0; i
<count
; i
++ )
96 v3_lerp( kfa
[i
].co
, kfb
[i
].co
, t
, kfd
[i
].co
);
97 q_nlerp( kfa
[i
].q
, kfb
[i
].q
, t
, kfd
[i
].q
);
98 v3_lerp( kfa
[i
].s
, kfb
[i
].s
, t
, kfd
[i
].s
);
102 VG_STATIC
void skeleton_lerp_pose( struct skeleton
*skele
,
103 mdl_keyframe
*kfa
, mdl_keyframe
*kfb
, float t
,
106 keyframe_lerp_pose( kfa
, kfb
, t
, kfd
, skele
->bone_count
-1 );
109 VG_STATIC
void skeleton_copy_pose( struct skeleton
*skele
,
110 mdl_keyframe
*kfa
, mdl_keyframe
*kfd
)
112 keyframe_copy_pose( kfa
, kfd
, skele
->bone_count
-1 );
116 * Sample animation between 2 closest frames using time value. Output is a
117 * keyframe buffer that is allocated with an appropriate size
119 VG_STATIC
void skeleton_sample_anim( struct skeleton
*skele
,
120 struct skeleton_anim
*anim
,
122 mdl_keyframe
*output
)
124 float animtime
= time
*anim
->rate
;
126 u32 frame
= ((u32
)animtime
) % anim
->length
,
127 next
= (frame
+1) % anim
->length
;
129 float t
= vg_fractf( animtime
);
131 mdl_keyframe
*base
= anim
->anim_data
+ (skele
->bone_count
-1)*frame
,
132 *nbase
= anim
->anim_data
+ (skele
->bone_count
-1)*next
;
134 skeleton_lerp_pose( skele
, base
, nbase
, t
, output
);
137 VG_STATIC
int skeleton_sample_anim_clamped( struct skeleton
*skele
,
138 struct skeleton_anim
*anim
,
140 mdl_keyframe
*output
)
142 float end
= (float)(anim
->length
-1) / anim
->rate
;
143 skeleton_sample_anim( skele
, anim
, vg_minf( end
, time
), output
);
151 typedef enum anim_apply
154 k_anim_apply_defer_ik
,
155 k_anim_apply_deffered_only
159 VG_STATIC
int should_apply_bone( struct skeleton
*skele
, u32 id
, anim_apply type
)
161 struct skeleton_bone
*sb
= &skele
->bones
[ id
],
162 *sp
= &skele
->bones
[ sb
->parent
];
164 if( type
== k_anim_apply_defer_ik
)
166 if( ((sp
->flags
& k_bone_flag_ik
) && !(sb
->flags
& k_bone_flag_ik
))
178 else if( type
== k_anim_apply_deffered_only
)
190 * Apply block of keyframes to skeletons final pose
192 VG_STATIC
void skeleton_apply_pose( struct skeleton
*skele
, mdl_keyframe
*pose
,
193 anim_apply passtype
)
195 m4x3_identity( skele
->final_mtx
[0] );
196 skele
->bones
[0].defer
= 0;
197 skele
->bones
[0].flags
&= ~k_bone_flag_ik
;
199 for( int i
=1; i
<skele
->bone_count
; i
++ )
201 struct skeleton_bone
*sb
= &skele
->bones
[i
],
202 *sp
= &skele
->bones
[ sb
->parent
];
204 if( !should_apply_bone( skele
, i
, passtype
) )
213 v3_sub( skele
->bones
[i
].co
, skele
->bones
[sb
->parent
].co
, temp_delta
);
216 mdl_keyframe
*kf
= &pose
[i
-1];
217 q_m3x3( kf
->q
, posemtx
);
218 v3_copy( kf
->co
, posemtx
[3] );
219 v3_add( temp_delta
, posemtx
[3], posemtx
[3] );
222 m4x3_mul( skele
->final_mtx
[ sb
->parent
], posemtx
, skele
->final_mtx
[i
] );
227 * creates the reference inverse matrix for an IK bone, as it has an initial
228 * intrisic rotation based on the direction that the IK is setup..
230 VG_STATIC
void skeleton_inverse_for_ik( struct skeleton
*skele
,
232 u32 id
, m3x3f inverse
)
234 v3_copy( ivaxis
, inverse
[0] );
235 v3_copy( skele
->bones
[id
].end
, inverse
[1] );
236 v3_normalize( inverse
[1] );
237 v3_cross( inverse
[0], inverse
[1], inverse
[2] );
238 m3x3_transpose( inverse
, inverse
);
242 * Creates inverse rotation matrices which the IK system uses.
244 VG_STATIC
void skeleton_create_inverses( struct skeleton
*skele
)
246 /* IK: inverse 'plane-bone space' axis '(^axis,^bone,...)[base] */
247 for( int i
=0; i
<skele
->ik_count
; i
++ )
249 struct skeleton_ik
*ik
= &skele
->ik
[i
];
252 v3f iv0
, iv1
, ivaxis
;
253 v3_sub( skele
->bones
[ik
->target
].co
, skele
->bones
[ik
->lower
].co
, iv0
);
254 v3_sub( skele
->bones
[ik
->pole
].co
, skele
->bones
[ik
->lower
].co
, iv1
);
255 v3_cross( iv0
, iv1
, ivaxis
);
256 v3_normalize( ivaxis
);
258 skeleton_inverse_for_ik( skele
, ivaxis
, ik
->lower
, ik
->ia
);
259 skeleton_inverse_for_ik( skele
, ivaxis
, ik
->upper
, ik
->ib
);
264 * Apply a model matrix to all bones, should be done last
266 VG_STATIC
void skeleton_apply_transform( struct skeleton
*skele
, m4x3f transform
)
268 for( int i
=0; i
<skele
->bone_count
; i
++ )
270 struct skeleton_bone
*sb
= &skele
->bones
[i
];
271 m4x3_mul( transform
, skele
->final_mtx
[i
], skele
->final_mtx
[i
] );
276 * Apply an inverse matrix to all bones which maps vertices from bind space into
277 * bone relative positions
279 VG_STATIC
void skeleton_apply_inverses( struct skeleton
*skele
)
281 for( int i
=0; i
<skele
->bone_count
; i
++ )
283 struct skeleton_bone
*sb
= &skele
->bones
[i
];
285 m3x3_identity( inverse
);
286 v3_negate( sb
->co
, inverse
[3] );
288 m4x3_mul( skele
->final_mtx
[i
], inverse
, skele
->final_mtx
[i
] );
293 * Apply all IK modifiers (2 bone ik reference from blender is supported)
295 VG_STATIC
void skeleton_apply_ik_pass( struct skeleton
*skele
)
297 for( int i
=0; i
<skele
->ik_count
; i
++ )
299 struct skeleton_ik
*ik
= &skele
->ik
[i
];
301 v3f v0
, /* base -> target */
302 v1
, /* base -> pole */
309 v3_copy( skele
->final_mtx
[ik
->lower
][3], co_base
);
310 v3_copy( skele
->final_mtx
[ik
->target
][3], co_target
);
311 v3_copy( skele
->final_mtx
[ik
->pole
][3], co_pole
);
313 v3_sub( co_target
, co_base
, v0
);
314 v3_sub( co_pole
, co_base
, v1
);
315 v3_cross( v0
, v1
, vaxis
);
316 v3_normalize( vaxis
);
318 v3_cross( vaxis
, v0
, v1
);
320 /* localize problem into [x:v0,y:v1] 2d plane */
321 v2f base
= { v3_dot( v0
, co_base
), v3_dot( v1
, co_base
) },
322 end
= { v3_dot( v0
, co_target
), v3_dot( v1
, co_target
) },
325 /* Compute angles (basic trig)*/
327 v2_sub( end
, base
, delta
);
330 l1
= v3_length( skele
->bones
[ik
->lower
].end
),
331 l2
= v3_length( skele
->bones
[ik
->upper
].end
),
332 d
= vg_clampf( v2_length(delta
), fabsf(l1
- l2
), l1
+l2
-0.00001f
),
333 c
= acosf( (l1
*l1
+ d
*d
- l2
*l2
) / (2.0f
*l1
*d
) ),
334 rot
= atan2f( delta
[1], delta
[0] ) + c
- VG_PIf
/2.0f
;
336 knee
[0] = sinf(-rot
) * l1
;
337 knee
[1] = cosf(-rot
) * l1
;
339 m4x3_identity( skele
->final_mtx
[ik
->lower
] );
340 m4x3_identity( skele
->final_mtx
[ik
->upper
] );
342 /* create rotation matrix */
344 v3_muladds( co_base
, v0
, knee
[0], co_knee
);
345 v3_muladds( co_knee
, v1
, knee
[1], co_knee
);
346 vg_line( co_base
, co_knee
, 0xff00ff00 );
349 v3_copy( vaxis
, transform
[0] );
350 v3_muls( v0
, knee
[0], transform
[1] );
351 v3_muladds( transform
[1], v1
, knee
[1], transform
[1] );
352 v3_normalize( transform
[1] );
353 v3_cross( transform
[0], transform
[1], transform
[2] );
354 v3_copy( co_base
, transform
[3] );
356 m3x3_mul( transform
, ik
->ia
, transform
);
357 m4x3_copy( transform
, skele
->final_mtx
[ik
->lower
] );
359 /* upper/knee bone */
360 v3_copy( vaxis
, transform
[0] );
361 v3_sub( co_target
, co_knee
, transform
[1] );
362 v3_normalize( transform
[1] );
363 v3_cross( transform
[0], transform
[1], transform
[2] );
364 v3_copy( co_knee
, transform
[3] );
366 m3x3_mul( transform
, ik
->ib
, transform
);
367 m4x3_copy( transform
, skele
->final_mtx
[ik
->upper
] );
372 * Applies the typical operations that you want for an IK rig:
373 * Pose, IK, Pose(deferred), Inverses, Transform
375 VG_STATIC
void skeleton_apply_standard( struct skeleton
*skele
, mdl_keyframe
*pose
,
378 skeleton_apply_pose( skele
, pose
, k_anim_apply_defer_ik
);
379 skeleton_apply_ik_pass( skele
);
380 skeleton_apply_pose( skele
, pose
, k_anim_apply_deffered_only
);
381 skeleton_apply_inverses( skele
);
382 skeleton_apply_transform( skele
, transform
);
386 * Get an animation by name
388 VG_STATIC
struct skeleton_anim
*skeleton_get_anim( struct skeleton
*skele
,
391 for( int i
=0; i
<skele
->anim_count
; i
++ )
393 struct skeleton_anim
*anim
= &skele
->anims
[i
];
395 if( !strcmp( anim
->name
, name
) )
399 vg_error( "skeleton_get_anim( *, \"%s\" )\n", name
);
400 vg_fatal_exit_loop( "Invalid animation name\n" );
405 VG_STATIC
void skeleton_alloc_from( struct skeleton
*skele
,
407 struct classtype_skeleton
*inf
)
409 skele
->bone_count
= inf
->channels
;
410 skele
->ik_count
= inf
->ik_count
;
411 skele
->collider_count
= inf
->collider_count
;
412 skele
->anim_count
= inf
->anim_count
;
414 u32 bone_size
= sizeof(struct skeleton_bone
) * skele
->bone_count
,
415 ik_size
= sizeof(struct skeleton_ik
) * skele
->ik_count
,
416 mtx_size
= sizeof(m4x3f
) * skele
->bone_count
,
417 anim_size
= sizeof(struct skeleton_anim
) * skele
->anim_count
;
419 skele
->bones
= vg_linear_alloc( lin_alloc
, bone_size
);
420 skele
->ik
= vg_linear_alloc( lin_alloc
, ik_size
);
421 skele
->final_mtx
= vg_linear_alloc( lin_alloc
, mtx_size
);
422 skele
->anims
= vg_linear_alloc( lin_alloc
, anim_size
);
425 VG_STATIC
void skeleton_fatal_err(void)
427 vg_fatal_exit_loop( "Skeleton setup failed" );
430 /* Setup an animated skeleton from model. mdl's metadata should stick around */
431 VG_STATIC
void skeleton_setup( struct skeleton
*skele
,
432 void *lin_alloc
, mdl_context
*mdl
)
434 u32 bone_count
= 1, skeleton_root
= 0, ik_count
= 0, collider_count
= 0;
435 skele
->bone_count
= 0;
437 skele
->final_mtx
= NULL
;
440 struct classtype_skeleton
*inf
= NULL
;
442 for( u32 i
=0; i
<mdl
->info
.node_count
; i
++ )
444 mdl_node
*pnode
= mdl_node_from_id( mdl
, i
);
446 if( pnode
->classtype
== k_classtype_skeleton
)
448 inf
= mdl_get_entdata( mdl
, pnode
);
449 skeleton_alloc_from( skele
, lin_alloc
, inf
);
452 else if( skele
->bone_count
)
454 int is_bone
= pnode
->classtype
== k_classtype_bone
;
458 if( bone_count
== skele
->bone_count
)
460 vg_error( "too many bones (%u/%u) @%s!\n",
461 bone_count
, skele
->bone_count
,
462 mdl_pstr( mdl
, pnode
->pstr_name
));
464 skeleton_fatal_err();
467 struct skeleton_bone
*sb
= &skele
->bones
[bone_count
];
468 struct classtype_bone
*bone_inf
= mdl_get_entdata( mdl
, pnode
);
470 v3_copy( pnode
->co
, sb
->co
);
471 v3_copy( pnode
->s
, sb
->end
);
472 sb
->parent
= pnode
->parent
-skeleton_root
;
473 sb
->name
= mdl_pstr( mdl
, pnode
->pstr_name
);
474 sb
->flags
= bone_inf
->flags
;
476 if( sb
->flags
& k_bone_flag_ik
)
478 skele
->bones
[ sb
->parent
].flags
|= k_bone_flag_ik
;
480 if( ik_count
== skele
->ik_count
)
482 vg_error( "Too many ik bones, corrupt model file\n" );
483 skeleton_fatal_err();
486 struct skeleton_ik
*ik
= &skele
->ik
[ ik_count
++ ];
487 ik
->upper
= bone_count
;
488 ik
->lower
= sb
->parent
;
489 ik
->target
= bone_inf
->ik_target
;
490 ik
->pole
= bone_inf
->ik_pole
;
494 box_copy( bone_inf
->hitbox
, sb
->hitbox
);
496 if( bone_inf
->flags
& k_bone_flag_collider_any
)
498 if( collider_count
== skele
->collider_count
)
500 vg_error( "Too many collider bones\n" );
501 skeleton_fatal_err();
518 vg_error( "No skeleton in model\n" );
519 skeleton_fatal_err();
522 if( collider_count
!= skele
->collider_count
)
524 vg_error( "Loaded %u colliders out of %u\n", collider_count
,
525 skele
->collider_count
);
526 skeleton_fatal_err();
529 if( bone_count
!= skele
->bone_count
)
531 vg_error( "Loaded %u bones out of %u\n", bone_count
, skele
->bone_count
);
532 vg_fatal_exit_loop( "Skeleton setup failed" );
533 skeleton_fatal_err();
536 if( ik_count
!= skele
->ik_count
)
538 vg_error( "Loaded %u ik bones out of %u\n", ik_count
, skele
->ik_count
);
539 skeleton_fatal_err();
542 /* fill in implicit root bone */
543 v3_zero( skele
->bones
[0].co
);
544 v3_copy( (v3f
){0.0f
,1.0f
,0.0f
}, skele
->bones
[0].end
);
545 skele
->bones
[0].parent
= 0xffffffff;
546 skele
->bones
[0].flags
= 0;
547 skele
->bones
[0].name
= "[root]";
549 /* process animation quick refs */
550 for( int i
=0; i
<skele
->anim_count
; i
++ )
552 mdl_animation
*anim
= &mdl
->anim_buffer
[ inf
->anim_start
+ i
];
554 skele
->anims
[i
].rate
= anim
->rate
;
555 skele
->anims
[i
].length
= anim
->length
;
556 skele
->anims
[i
].name
= mdl_pstr(mdl
, anim
->pstr_name
);
557 skele
->anims
[i
].anim_data
= &mdl
->keyframe_buffer
[ anim
->offset
];
559 vg_info( "animation[ %f, %u ] '%s'\n", anim
->rate
,
561 skele
->anims
[i
].name
);
564 skeleton_create_inverses( skele
);
565 vg_success( "Loaded skeleton with %u bones\n", skele
->bone_count
);
566 vg_success( " %u colliders\n", skele
->collider_count
);
569 VG_STATIC
void skeleton_debug( struct skeleton
*skele
)
571 for( int i
=0; i
<skele
->bone_count
; i
++ )
573 struct skeleton_bone
*sb
= &skele
->bones
[i
];
576 v3_copy( sb
->co
, p0
);
577 v3_add( p0
, sb
->end
, p1
);
578 //vg_line( p0, p1, 0xffffffff );
580 m4x3_mulv( skele
->final_mtx
[i
], p0
, p0
);
581 m4x3_mulv( skele
->final_mtx
[i
], p1
, p1
);
583 if( sb
->flags
& k_bone_flag_deform
)
585 if( sb
->flags
& k_bone_flag_ik
)
587 vg_line( p0
, p1
, 0xff0000ff );
591 vg_line( p0
, p1
, 0xffcccccc );
595 vg_line( p0
, p1
, 0xff00ffff );
599 #endif /* SKELETON_H */