From: hgn Date: Tue, 12 Dec 2023 16:02:38 +0000 (+0000) Subject: active ragdolls X-Git-Url: https://harrygodden.com/git/?p=carveJwlIkooP6JGAAIwe30JlM.git;a=commitdiff_plain;h=89b5a93c0fa9b72a14ce17c433127ef646ce338f active ragdolls --- diff --git a/models_src/ch_none.mdl b/models_src/ch_none.mdl index 34a6cc1..e17c759 100644 Binary files a/models_src/ch_none.mdl and b/models_src/ch_none.mdl differ diff --git a/player_dead.c b/player_dead.c index 4ee2236..7733c32 100644 --- a/player_dead.c +++ b/player_dead.c @@ -172,4 +172,9 @@ static void player__dead_animator_exchange( bitpack_ctx *ctx, void *data ){ } } +static void player__dead_bind(void){ + struct skeleton *sk = &localplayer.skeleton; + player_dead.anim_bail = skeleton_get_anim( sk, "pose_bail_ball" ); +} + #endif /* PLAYER_DEAD_C */ diff --git a/player_dead.h b/player_dead.h index e4c177e..f90a302 100644 --- a/player_dead.h +++ b/player_dead.h @@ -15,6 +15,8 @@ struct player_dead{ transforms[ 32 ]; } animator; + + struct skeleton_anim *anim_bail; } static player_dead; @@ -24,6 +26,7 @@ static void player__dead_animate (void); static void player__dead_pose (void *animator, player_pose *pose); static void player__dead_post_animate(void); static void player__dead_im_gui (void); +static void player__dead_bind (void); static void player__dead_transition ( enum player_die_type type ); static void player__dead_animator_exchange( bitpack_ctx *ctx, void *data ); @@ -34,6 +37,7 @@ struct player_subsystem_interface static player_subsystem_dead = { .pose = player__dead_pose, .post_animate = player__dead_post_animate, .im_gui = player__dead_im_gui, + .bind = player__dead_bind, .animator_data = &player_dead.animator, .animator_size = sizeof(player_dead.animator), diff --git a/player_ragdoll.c b/player_ragdoll.c index ff6a533..e334580 100644 --- a/player_ragdoll.c +++ b/player_ragdoll.c @@ -40,7 +40,12 @@ static int dev_ragdoll_saveload(int argc, const char *argv[]){ } static void player_ragdoll_init(void){ + VG_VAR_F32( k_ragdoll_active_threshold ); + VG_VAR_F32( k_ragdoll_angular_drag ); + VG_VAR_F32( k_ragdoll_correction ); VG_VAR_F32( k_ragdoll_limit_scale ); + VG_VAR_F32( k_ragdoll_spring ); + VG_VAR_F32( k_ragdoll_dampening ); VG_VAR_I32( k_ragdoll_div ); VG_VAR_I32( k_ragdoll_debug_collider ); VG_VAR_I32( k_ragdoll_debug_constraints ); @@ -151,7 +156,10 @@ static void setup_ragdoll_from_skeleton( struct skeleton *sk, if( rd->part_count > vg_list_size(rd->parts) ) vg_fatal_error( "Playermodel has too many colliders" ); - struct ragdoll_part *rp = &rd->parts[ rd->part_count ++ ]; + u32 part_id = rd->part_count; + rd->part_count ++; + + struct ragdoll_part *rp = &rd->parts[ part_id ]; rp->bone_id = i; rp->parent = 0xffffffff; @@ -166,12 +174,17 @@ static void setup_ragdoll_from_skeleton( struct skeleton *sk, rp->parent = ragdoll_bone_parent( rd, bone->parent ); if( bone->orig_bone->flags & k_bone_flag_cone_constraint ){ - struct rb_constr_pos *c = - &rd->position_constraints[ rd->position_constraints_count ++ ]; + u32 conid = rd->position_constraints_count; + rd->position_constraints_count ++; + + struct rb_constr_pos *c = &rd->position_constraints[ conid ]; struct skeleton_bone *bj = &sk->bones[rp->bone_id]; struct ragdoll_part *pp = &rd->parts[rp->parent]; struct skeleton_bone *bp = &sk->bones[pp->bone_id]; + + rd->constraint_associations[conid][0] = rp->parent; + rd->constraint_associations[conid][1] = part_id; /* Convention: rba -- parent, rbb -- child */ c->rba = &pp->obj.rb; @@ -437,10 +450,10 @@ static void player_ragdoll_iter( struct player_ragdoll *rd ){ } /* - * SOLVE CONSTRAINTS + * SOLVE CONSTRAINTS & Integrate */ if( run_sim ){ - for( int i=0; i<16; i++ ){ + for( int i=0; i<12; i++ ){ rb_solve_contacts( rb_contact_buffer, rb_contact_count ); rb_solve_swingtwist_constraints( rd->cone_constraints, rd->cone_constraints_count ); @@ -448,17 +461,30 @@ static void player_ragdoll_iter( struct player_ragdoll *rd ){ rd->position_constraints_count ); } - for( int i=0; ipart_count; i++ ) + for( int i=0; ipart_count; i++ ){ rb_iter( &rd->parts[i].obj.rb ); + v3f w; + v3_copy( rd->parts[i].obj.rb.w, w ); + if( v3_length2( w ) > 0.00001f ){ + v3_normalize( w ); + v3_muladds( rd->parts[i].obj.rb.w, w, -k_ragdoll_angular_drag, + rd->parts[i].obj.rb.w ); + } + } + for( int i=0; ipart_count; i++ ) rb_update_transform( &rd->parts[i].obj.rb ); - rb_correct_swingtwist_constraints( rd->cone_constraints, - rd->cone_constraints_count, 0.125f ); + for( int i=0; i<5; i ++ ){ + rb_correct_swingtwist_constraints( rd->cone_constraints, + rd->cone_constraints_count, + k_ragdoll_correction * 0.25f ); - rb_correct_position_constraints( rd->position_constraints, - rd->position_constraints_count, 0.25f ); + rb_correct_position_constraints( rd->position_constraints, + rd->position_constraints_count, + k_ragdoll_correction * 0.5f ); + } } rb_ct *stress = NULL; @@ -482,6 +508,68 @@ static void player_ragdoll_iter( struct player_ragdoll *rd ){ static u32 temp_filter = 0; + /* + * motorized joints + */ + if( run_sim && + (v3_length2(player_dead.v_lpf)>(k_ragdoll_active_threshold* + k_ragdoll_active_threshold)) ){ + assert( rd->cone_constraints_count == rd->position_constraints_count ); + + mdl_keyframe anim[32]; + skeleton_sample_anim( &localplayer.skeleton, player_dead.anim_bail, + 0.0f, anim ); + + for( u32 i=0; icone_constraints_count; i ++ ){ + rb_constr_swingtwist *st = &rd->cone_constraints[i]; + rb_constr_pos *pc = &rd->position_constraints[i]; + + v3f va, vap; + + m3x3_mulv( st->rbb->to_world, st->coneva, va ); + + /* calculate va as seen in rest position, from the perspective of the + * parent object, mapped to pose world space using the parents + * transform. thats our target */ + + u32 id_p = rd->constraint_associations[i][0], + id_a = rd->constraint_associations[i][1]; + + struct ragdoll_part *pa = &rd->parts[ id_a ], + *pp = &rd->parts[ id_p ]; + + mdl_keyframe *kf = &anim[ pa->bone_id-1 ]; + m3x3_mulv( pa->collider_mtx, st->coneva, vap ); + q_mulv( kf->q, vap, vap ); + + /* This could be a transfer function */ + m3x3_mulv( pp->inv_collider_mtx, vap, vap ); + m3x3_mulv( st->rba->to_world, vap, vap ); + + f32 d = v3_dot( vap, va ), + a = acosf( vg_clampf( d, -1.0f, 1.0f ) ); + + v3f axis; + v3_cross( vap, va, axis ); + + f32 Fs = -a * k_ragdoll_spring, + Fd = -v3_dot( st->rbb->w, axis ) * k_ragdoll_dampening, + F = Fs+Fd; + + v3f torque; + v3_muls( axis, F, torque ); + v3_muladds( st->rbb->w, torque, k_rb_delta, st->rbb->w ); + + /* apply a adjustment to keep velocity at joint 0 */ +#if 0 + v3f wcb, vcb; + m3x3_mulv( st->rbb->to_world, pc->lcb, wcb ); + v3_cross( torque, wcb, vcb ); + v3_muladds( st->rbb->v, vcb, k_rb_delta, st->rbb->v ); +#endif + } + } + if( temp_filter ){ temp_filter --; return; diff --git a/player_ragdoll.h b/player_ragdoll.h index 0afc330..6f5a331 100644 --- a/player_ragdoll.h +++ b/player_ragdoll.h @@ -33,12 +33,19 @@ struct player_ragdoll{ rb_constr_swingtwist cone_constraints[32]; u32 cone_constraints_count; + /* TODO: Fix duplicated data */ + u32 constraint_associations[32][2]; int shoes[2]; }; static float k_ragdoll_floatyiness = 20.0f, k_ragdoll_floatydrag = 1.0f, - k_ragdoll_limit_scale = 1.0f; + k_ragdoll_limit_scale = 1.0f, + k_ragdoll_spring = 127.0f, + k_ragdoll_dampening = 15.0f, + k_ragdoll_correction = 0.5f, + k_ragdoll_angular_drag = 0.08f, + k_ragdoll_active_threshold = 5.0f; static int k_ragdoll_div = 1, ragdoll_frame = 0, diff --git a/rigidbody.h b/rigidbody.h index 2c074c4..a69e4af 100644 --- a/rigidbody.h +++ b/rigidbody.h @@ -330,9 +330,11 @@ static void rb_iter( rigidbody *rb ){ q_mul( rotation, rb->q, rb->q ); } +#if 0 /* damping */ v3_muls( rb->v, 1.0f/(1.0f+k_rb_delta*k_damp_linear), rb->v ); v3_muls( rb->w, 1.0f/(1.0f+k_rb_delta*k_damp_angular), rb->w ); +#endif }