X-Git-Url: https://harrygodden.com/git/?a=blobdiff_plain;f=skeleton.h;h=ce71283b42d9e8c8878edb97285aeb547d450717;hb=46643f969b12c2144a5f15ac5509610f18b467e4;hp=ace80e6131e2dc201572631a8cc7413179e83521;hpb=3d5597be2fd4b5d9ea3bf8863e15cc9bc8123755;p=carveJwlIkooP6JGAAIwe30JlM.git diff --git a/skeleton.h b/skeleton.h index ace80e6..ce71283 100644 --- a/skeleton.h +++ b/skeleton.h @@ -1,3 +1,7 @@ +/* + * Copyright (C) Mount0 Software, Harry Godden - All Rights Reserved + */ + #ifndef SKELETON_H #define SKELETON_H @@ -10,17 +14,20 @@ struct skeleton v3f co, end; u32 parent; - /* info, not real */ int deform, ik; + int defer; mdl_keyframe kf; + + char name[16]; } *bones; - m4x3f *final_transforms; + m4x3f *final_mtx; struct skeleton_ik { u32 lower, upper, target, pole; + m3x3f ia, ib; } *ik; @@ -41,10 +48,62 @@ struct skeleton useless cpu IK bones. */ }; -static void skeleton_apply_frame( m4x3f transform, - struct skeleton *skele, - struct skeleton_anim *anim, - float time ) +static u32 skeleton_bone_id( struct skeleton *skele, const char *name ) +{ + for( u32 i=0; ibone_count; i++ ) + { + if( !strcmp( skele->bones[i].name, name )) + return i; + } + return 0; +} + +static void keyframe_copy_pose( mdl_keyframe *kfa, mdl_keyframe *kfb, int num ) +{ + for( int i=0; i= 0.99f ) + { + keyframe_copy_pose( kfb, kfd, count ); + return; + } + + for( int i=0; ibone_count-1 ); +} + +/* + * Sample animation between 2 closest frames using time value. Output is a + * keyframe buffer that is allocated with an appropriate size + */ +static void skeleton_sample_anim( struct skeleton *skele, + struct skeleton_anim *anim, + float time, + mdl_keyframe *output ) { float animtime = time*anim->rate; @@ -56,11 +115,79 @@ static void skeleton_apply_frame( m4x3f transform, mdl_keyframe *base = anim->anim_data + (skele->bone_count-1)*frame, *nbase = anim->anim_data + (skele->bone_count-1)*next; - m4x3_copy( transform, skele->final_transforms[0] ); + skeleton_lerp_pose( skele, base, nbase, t, output ); +} + +static int skeleton_sample_anim_clamped( struct skeleton *skele, + struct skeleton_anim *anim, + float time, + mdl_keyframe *output ) +{ + float end = (float)(anim->length-1) / anim->rate; + skeleton_sample_anim( skele, anim, vg_minf( end, time ), output ); + + if( time > end ) + return 0; + else + return 1; +} + +typedef enum anim_apply +{ + k_anim_apply_always, + k_anim_apply_defer_ik, + k_anim_apply_deffered_only +} +anim_apply; + +static int should_apply_bone( struct skeleton *skele, u32 id, anim_apply type ) +{ + struct skeleton_bone *sb = &skele->bones[ id ], + *sp = &skele->bones[ sb->parent ]; + + if( type == k_anim_apply_defer_ik ) + { + if( (sp->ik && !sb->ik) || sp->defer ) + { + sb->defer = 1; + return 0; + } + else + { + sb->defer = 0; + return 1; + } + } + else if( type == k_anim_apply_deffered_only ) + { + if( sb->defer ) + return 1; + else + return 0; + } + + return 1; +} + +/* + * Apply block of keyframes to skeletons final pose + */ +static void skeleton_apply_pose( struct skeleton *skele, mdl_keyframe *pose, + anim_apply passtype ) +{ + m4x3_identity( skele->final_mtx[0] ); + skele->bones[0].defer = 0; + skele->bones[0].ik = 0; for( int i=1; ibone_count; i++ ) { - struct skeleton_bone *sb = &skele->bones[i]; + struct skeleton_bone *sb = &skele->bones[i], + *sp = &skele->bones[ sb->parent ]; + + if( !should_apply_bone( skele, i, passtype ) ) + continue; + + sb->defer = 0; /* process pose */ m4x3f posemtx; @@ -69,59 +196,80 @@ static void skeleton_apply_frame( m4x3f transform, v3_sub( skele->bones[i].co, skele->bones[sb->parent].co, temp_delta ); /* pose matrix */ - mdl_keyframe *kf = base+i-1, - *nkf = nbase+i-1; - - v3f co; - v4f q; - v3f s; - - v3_lerp( kf->co, nkf->co, t, co ); - q_nlerp( kf->q, nkf->q, t, q ); - v3_lerp( kf->s, nkf->s, t, s ); - - q_m3x3( q, posemtx ); - v3_copy( co, posemtx[3] ); + mdl_keyframe *kf = &pose[i-1]; + q_m3x3( kf->q, posemtx ); + v3_copy( kf->co, posemtx[3] ); v3_add( temp_delta, posemtx[3], posemtx[3] ); /* final matrix */ - m4x3_mul( skele->final_transforms[ sb->parent ], posemtx, - skele->final_transforms[i] ); - } - - /* armature space -> bone space matrix ( for verts ) */ - for( int i=1; ibone_count; i++ ) - { - m4x3f abmtx; - m3x3_identity( abmtx ); - v3_negate( skele->bones[i].co, abmtx[3] ); - m4x3_mul( skele->final_transforms[i], abmtx, - skele->final_transforms[i] ); + m4x3_mul( skele->final_mtx[ sb->parent ], posemtx, skele->final_mtx[i] ); } } -/* - * Get transformed position of bone - */ -static void skeleton_bone_posepos( struct skeleton *skele, u32 id, v3f co ) -{ - m4x3_mulv( skele->final_transforms[id], skele->bones[id].co, co ); -} - /* * creates the reference inverse matrix for an IK bone, as it has an initial * intrisic rotation based on the direction that the IK is setup.. */ static void skeleton_inverse_for_ik( struct skeleton *skele, v3f ivaxis, - u32 id, m4x3f inverse ) + u32 id, m3x3f inverse ) { v3_copy( ivaxis, inverse[0] ); v3_copy( skele->bones[id].end, inverse[1] ); v3_normalize( inverse[1] ); v3_cross( inverse[0], inverse[1], inverse[2] ); - v3_copy( skele->bones[id].co, inverse[3] ); - m4x3_invert_affine( inverse, inverse ); + m3x3_transpose( inverse, inverse ); +} + +/* + * Creates inverse rotation matrices which the IK system uses. + */ +static void skeleton_create_inverses( struct skeleton *skele ) +{ + /* IK: inverse 'plane-bone space' axis '(^axis,^bone,...)[base] */ + for( int i=0; iik_count; i++ ) + { + struct skeleton_ik *ik = &skele->ik[i]; + + m4x3f inverse; + v3f iv0, iv1, ivaxis; + v3_sub( skele->bones[ik->target].co, skele->bones[ik->lower].co, iv0 ); + v3_sub( skele->bones[ik->pole].co, skele->bones[ik->lower].co, iv1 ); + v3_cross( iv0, iv1, ivaxis ); + v3_normalize( ivaxis ); + + skeleton_inverse_for_ik( skele, ivaxis, ik->lower, ik->ia ); + skeleton_inverse_for_ik( skele, ivaxis, ik->upper, ik->ib ); + } +} + +/* + * Apply a model matrix to all bones, should be done last + */ +static void skeleton_apply_transform( struct skeleton *skele, m4x3f transform ) +{ + for( int i=0; ibone_count; i++ ) + { + struct skeleton_bone *sb = &skele->bones[i]; + m4x3_mul( transform, skele->final_mtx[i], skele->final_mtx[i] ); + } +} + +/* + * Apply an inverse matrix to all bones which maps vertices from bind space into + * bone relative positions + */ +static void skeleton_apply_inverses( struct skeleton *skele ) +{ + for( int i=0; ibone_count; i++ ) + { + struct skeleton_bone *sb = &skele->bones[i]; + m4x3f inverse; + m3x3_identity( inverse ); + v3_negate( sb->co, inverse[3] ); + + m4x3_mul( skele->final_mtx[i], inverse, skele->final_mtx[i] ); + } } /* @@ -141,9 +289,9 @@ static void skeleton_apply_ik_pass( struct skeleton *skele ) co_target, co_pole; - skeleton_bone_posepos( skele, ik->lower, co_base ); - skeleton_bone_posepos( skele, ik->target, co_target ); - skeleton_bone_posepos( skele, ik->pole, co_pole ); + v3_copy( skele->final_mtx[ik->lower][3], co_base ); + v3_copy( skele->final_mtx[ik->target][3], co_target ); + v3_copy( skele->final_mtx[ik->pole][3], co_pole ); v3_sub( co_target, co_base, v0 ); v3_sub( co_pole, co_base, v1 ); @@ -171,18 +319,8 @@ static void skeleton_apply_ik_pass( struct skeleton *skele ) knee[0] = sinf(-rot) * l1; knee[1] = cosf(-rot) * l1; - m4x3_identity( skele->final_transforms[ik->lower] ); - m4x3_identity( skele->final_transforms[ik->upper] ); - - /* inverse matrix axis '(^axis,^bone,...)[base] */ - m4x3f inverse; - v3f iv0, iv1, ivaxis; - v3_sub( skele->bones[ik->target].co, skele->bones[ik->lower].co, iv0 ); - v3_sub( skele->bones[ik->pole].co, skele->bones[ik->lower].co, iv1 ); - v3_cross( iv0, iv1, ivaxis ); - v3_normalize( ivaxis ); - - skeleton_inverse_for_ik( skele, ivaxis, ik->lower, inverse ); + m4x3_identity( skele->final_mtx[ik->lower] ); + m4x3_identity( skele->final_mtx[ik->upper] ); /* create rotation matrix */ v3f co_knee; @@ -198,21 +336,38 @@ static void skeleton_apply_ik_pass( struct skeleton *skele ) v3_cross( transform[0], transform[1], transform[2] ); v3_copy( co_base, transform[3] ); - m4x3_mul( transform, inverse, skele->final_transforms[ik->lower] ); - - /* 'upper' or knee bone */ - skeleton_inverse_for_ik( skele, ivaxis, ik->upper, inverse ); + m3x3_mul( transform, ik->ia, transform ); + m4x3_copy( transform, skele->final_mtx[ik->lower] ); + /* upper/knee bone */ v3_copy( vaxis, transform[0] ); v3_sub( co_target, co_knee, transform[1] ); v3_normalize( transform[1] ); v3_cross( transform[0], transform[1], transform[2] ); v3_copy( co_knee, transform[3] ); - m4x3_mul( transform, inverse, skele->final_transforms[ik->upper] ); + m3x3_mul( transform, ik->ib, transform ); + m4x3_copy( transform, skele->final_mtx[ik->upper] ); } } +/* + * Applies the typical operations that you want for an IK rig: + * Pose, IK, Pose(deferred), Inverses, Transform + */ +static void skeleton_apply_standard( struct skeleton *skele, mdl_keyframe *pose, + m4x3f transform ) +{ + skeleton_apply_pose( skele, pose, k_anim_apply_defer_ik ); + skeleton_apply_ik_pass( skele ); + skeleton_apply_pose( skele, pose, k_anim_apply_deffered_only ); + skeleton_apply_inverses( skele ); + skeleton_apply_transform( skele, transform ); +} + +/* + * Get an animation by name + */ static struct skeleton_anim *skeleton_get_anim( struct skeleton *skele, const char *name ) { @@ -233,7 +388,7 @@ static int skeleton_setup( struct skeleton *skele, mdl_header *mdl ) u32 bone_count = 1, skeleton_root = 0, ik_count = 0; skele->bone_count = 0; skele->bones = NULL; - skele->final_transforms = NULL; + skele->final_mtx = NULL; skele->anims = NULL; struct classtype_skeleton *inf = NULL; @@ -278,6 +433,7 @@ static int skeleton_setup( struct skeleton *skele, mdl_header *mdl ) v3_copy( pnode->co, sb->co ); v3_copy( pnode->s, sb->end ); sb->parent = pnode->parent-skeleton_root; + strncpy( sb->name, mdl_pstr(mdl,pnode->pstr_name), 15 ); if( is_ik ) { @@ -337,7 +493,7 @@ static int skeleton_setup( struct skeleton *skele, mdl_header *mdl ) v3_copy( (v3f){0.0f,1.0f,0.0f}, skele->bones[0].end ); skele->bones[0].parent = 0xffffffff; - skele->final_transforms = malloc( sizeof(m4x3f) * skele->bone_count ); + skele->final_mtx = malloc( sizeof(m4x3f) * skele->bone_count ); skele->anim_count = inf->anim_count; skele->anims = malloc( sizeof(struct skeleton_anim) * inf->anim_count); @@ -358,6 +514,7 @@ static int skeleton_setup( struct skeleton *skele, mdl_header *mdl ) memcpy( dst, mdl_get_animdata( mdl, anim ), block_size ); } + skeleton_create_inverses( skele ); vg_success( "Loaded skeleton with %u bones\n", skele->bone_count ); return 1; @@ -378,8 +535,8 @@ static void skeleton_debug( struct skeleton *skele ) v3_add( p0, sb->end, p1 ); //vg_line( p0, p1, 0xffffffff ); - m4x3_mulv( skele->final_transforms[i], p0, p0 ); - m4x3_mulv( skele->final_transforms[i], p1, p1 ); + m4x3_mulv( skele->final_mtx[i], p0, p0 ); + m4x3_mulv( skele->final_mtx[i], p1, p1 ); if( sb->deform ) {