X-Git-Url: https://harrygodden.com/git/?a=blobdiff_plain;f=player_ragdoll.c;h=e3345808923f0ed5e01fe15622dc2e24dc3b16c2;hb=76315944e5a98838163e0aba8601ed3522f0724d;hp=a7e3e7569dae27d7eb413ade9c91a85b96cc2f1f;hpb=1b522daa02f28128498b04def4d60b63e590d1f3;p=carveJwlIkooP6JGAAIwe30JlM.git diff --git a/player_ragdoll.c b/player_ragdoll.c index a7e3e75..e334580 100644 --- a/player_ragdoll.c +++ b/player_ragdoll.c @@ -4,15 +4,55 @@ #include "player.h" #include "audio.h" -VG_STATIC void player_ragdoll_init(void) -{ +static int dev_ragdoll_saveload(int argc, const char *argv[]){ + if( argc != 2 ){ + vg_info( "Usage: ragdoll load/save filepath\n" ); + return 1; + } + + if( !strcmp(argv[0],"save") ){ + FILE *fp = fopen( argv[1], "wb" ); + if( !fp ){ + vg_error( "Failed to open file\n" ); + return 1; + } + fwrite( &localplayer.ragdoll.parts, + sizeof(localplayer.ragdoll.parts), 1, fp ); + fclose( fp ); + } + else if( !strcmp(argv[0],"load") ){ + FILE *fp = fopen( argv[1], "rb" ); + if( !fp ){ + vg_error( "Failed to open file\n" ); + return 1; + } + + fread( &localplayer.ragdoll.parts, + sizeof(localplayer.ragdoll.parts), 1, fp ); + fclose( fp ); + } + else { + vg_error( "Unknown command: %s (options are: save,load)\n", argv[0] ); + return 1; + } + + return 0; +} + +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 ); + vg_console_reg_cmd( "ragdoll", dev_ragdoll_saveload, NULL ); } -VG_STATIC void player_init_ragdoll_bone_collider( struct skeleton_bone *bone, +static void player_init_ragdoll_bone_collider( struct skeleton_bone *bone, struct ragdoll_part *rp ) { m4x3_identity( rp->collider_mtx ); @@ -46,7 +86,7 @@ VG_STATIC void player_init_ragdoll_bone_collider( struct skeleton_bone *bone, v3_zero( v1 ); v1[ major_axis ] = 1.0f; - rb_tangent_basis( v1, tx, ty ); + v3_tangent_basis( v1, tx, ty ); float r = (fabsf(v3_dot(tx,v0)) + fabsf(v3_dot(ty,v0))) * 0.25f, l = fabsf(v0[ major_axis ]); @@ -66,7 +106,7 @@ VG_STATIC void player_init_ragdoll_bone_collider( struct skeleton_bone *bone, } else{ vg_warn( "type: %u\n", bone->collider ); - vg_fatal_exit_loop( "Invalid bone collider type" ); + vg_fatal_error( "Invalid bone collider type" ); } m4x3_invert_affine( rp->collider_mtx, rp->inv_collider_mtx ); @@ -82,33 +122,30 @@ VG_STATIC void player_init_ragdoll_bone_collider( struct skeleton_bone *bone, /* * Get parent index in the ragdoll */ -VG_STATIC u32 ragdoll_bone_parent( struct player_ragdoll *rd, - struct player_avatar *av, u32 bone_id ) -{ +static u32 ragdoll_bone_parent( struct player_ragdoll *rd, u32 bone_id ){ for( u32 j=0; jpart_count; j++ ) if( rd->parts[ j ].bone_id == bone_id ) return j; - vg_fatal_exit_loop( "Referenced parent bone does not have a rigidbody" ); + vg_fatal_error( "Referenced parent bone does not have a rigidbody" ); return 0; } /* - * Setup ragdoll colliders + * Setup ragdoll colliders from skeleton */ -VG_STATIC void player_setup_ragdoll_from_avatar( struct player_ragdoll *rd, - struct player_avatar *av ) -{ +static void setup_ragdoll_from_skeleton( struct skeleton *sk, + struct player_ragdoll *rd ){ rd->part_count = 0; - if( !av->sk.collider_count ) + if( !sk->collider_count ) return; rd->position_constraints_count = 0; rd->cone_constraints_count = 0; - for( u32 i=1; isk.bone_count; i ++ ){ - struct skeleton_bone *bone = &av->sk.bones[i]; + for( u32 i=1; ibone_count; i ++ ){ + struct skeleton_bone *bone = &sk->bones[i]; /* * Bones with colliders @@ -117,9 +154,12 @@ VG_STATIC void player_setup_ragdoll_from_avatar( struct player_ragdoll *rd, continue; if( rd->part_count > vg_list_size(rd->parts) ) - vg_fatal_exit_loop( "Playermodel has too many colliders" ); + 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; @@ -131,16 +171,20 @@ VG_STATIC void player_setup_ragdoll_from_avatar( struct player_ragdoll *rd, if( !bone->parent ) continue; - rp->parent = ragdoll_bone_parent( rd, av, bone->parent ); - + 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 skeleton_bone *bj = &av->sk.bones[rp->bone_id]; + 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 = &av->sk.bones[pp->bone_id]; + 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; @@ -186,9 +230,7 @@ VG_STATIC void player_setup_ragdoll_from_avatar( struct player_ragdoll *rd, /* * Make avatar copy the ragdoll */ -VG_STATIC void copy_ragdoll_pose_to_avatar( struct player_ragdoll *rd, - struct player_avatar *av ) -{ +static void copy_ragdoll_pose_to_localplayer( struct player_ragdoll *rd ){ for( int i=0; ipart_count; i++ ){ struct ragdoll_part *part = &rd->parts[i]; @@ -204,51 +246,71 @@ VG_STATIC void copy_ragdoll_pose_to_avatar( struct player_ragdoll *rd, q_m3x3( q_int, mtx ); v3_copy( co_int, mtx[3] ); - m4x3_mul( mtx, part->inv_collider_mtx, av->sk.final_mtx[part->bone_id] ); + m4x3_mul( mtx, part->inv_collider_mtx, + localplayer.final_mtx[part->bone_id] ); } - for( u32 i=1; isk.bone_count; i++ ){ - struct skeleton_bone *sb = &av->sk.bones[i]; + for( u32 i=1; iparent && !sb->collider ){ v3f delta; - v3_sub( av->sk.bones[i].co, av->sk.bones[sb->parent].co, delta ); + v3_sub( localplayer.skeleton.bones[i].co, + localplayer.skeleton.bones[sb->parent].co, delta ); m4x3f posemtx; m3x3_identity( posemtx ); v3_copy( delta, posemtx[3] ); /* final matrix */ - m4x3_mul( av->sk.final_mtx[sb->parent], posemtx, av->sk.final_mtx[i] ); + m4x3_mul( localplayer.final_mtx[sb->parent], posemtx, + localplayer.final_mtx[i] ); } } - skeleton_apply_inverses( &av->sk ); + skeleton_apply_inverses( &localplayer.skeleton, localplayer.final_mtx ); } /* * Make the ragdoll copy the player model */ -VG_STATIC void copy_avatar_pose_to_ragdoll( struct player_avatar *av, - struct player_ragdoll *rd, - v3f velocity ) -{ +static void copy_localplayer_to_ragdoll( struct player_ragdoll *rd, + enum player_die_type type ){ + v3f centroid; + + v3f *bone_mtx = localplayer.final_mtx[localplayer.id_hip]; + m4x3_mulv( bone_mtx, + localplayer.skeleton.bones[localplayer.id_hip].co, centroid ); + for( int i=0; ipart_count; i++ ){ struct ragdoll_part *part = &rd->parts[i]; v3f pos, offset; u32 bone = part->bone_id; - m4x3_mulv( av->sk.final_mtx[bone], av->sk.bones[bone].co, pos ); - m3x3_mulv( av->sk.final_mtx[bone], part->collider_mtx[3], offset ); + v3f *bone_mtx = localplayer.final_mtx[bone]; + + m4x3_mulv( bone_mtx, localplayer.skeleton.bones[bone].co, pos ); + m3x3_mulv( bone_mtx, part->collider_mtx[3], offset ); v3_add( pos, offset, part->obj.rb.co ); m3x3f r; - m3x3_mul( av->sk.final_mtx[bone], part->collider_mtx, r ); + m3x3_mul( bone_mtx, part->collider_mtx, r ); m3x3_q( r, part->obj.rb.q ); - v3_copy( velocity, part->obj.rb.v ); - v3_zero( part->obj.rb.w ); + v3f ra, v; + v3_sub( part->obj.rb.co, centroid, ra ); + v3_cross( localplayer.rb.w, ra, v ); + v3_add( localplayer.rb.v, v, part->obj.rb.v ); + + if( type == k_player_die_type_feet ){ + if( (bone == localplayer.id_foot_l) || + (bone == localplayer.id_foot_r) ){ + v3_zero( part->obj.rb.v ); + } + } + + v3_copy( localplayer.rb.w, part->obj.rb.w ); v3_copy( part->obj.rb.co, part->prev_co ); v4_copy( part->obj.rb.q, part->prev_q ); @@ -257,19 +319,11 @@ VG_STATIC void copy_avatar_pose_to_ragdoll( struct player_avatar *av, } } -/* - * Draw rigidbody colliders for ragdoll - */ -VG_STATIC void player_debug_ragdoll(void) -{ -} - /* * Ragdoll physics step */ -VG_STATIC void player_ragdoll_iter( struct player_ragdoll *rd ) -{ - world_instance *world = get_active_world(); +static void player_ragdoll_iter( struct player_ragdoll *rd ){ + world_instance *world = world_current_instance(); int run_sim = 0; ragdoll_frame ++; @@ -295,12 +349,14 @@ VG_STATIC void player_ragdoll_iter( struct player_ragdoll *rd ) if( rd->parts[i].obj.type == k_rb_shape_capsule ){ l = rb_capsule__scene( rd->parts[i].obj.rb.to_world, &rd->parts[i].obj.inf.capsule, - NULL, &world->rb_geo.inf.scene, buf ); + NULL, &world->rb_geo.inf.scene, buf, + k_material_flag_ghosts ); } else if( rd->parts[i].obj.type == k_rb_shape_box ){ l = rb_box__scene( rd->parts[i].obj.rb.to_world, rd->parts[i].obj.rb.bbx, - NULL, &world->rb_geo.inf.scene, buf ); + NULL, &world->rb_geo.inf.scene, buf, + k_material_flag_ghosts ); } else continue; @@ -346,14 +402,15 @@ VG_STATIC void player_ragdoll_iter( struct player_ragdoll *rd ) } } - for( int j=0; jpart_count; j++ ){ - struct ragdoll_part *pj = &rd->parts[j]; + if( world->water.enabled ){ + for( int j=0; jpart_count; j++ ){ + struct ragdoll_part *pj = &rd->parts[j]; - if( run_sim ){ - v4f plane = {0.0f,1.0f,0.0f,0.0f}; - rb_effect_simple_bouyency( &pj->obj.rb, plane, - k_ragdoll_floatyiness, - k_ragdoll_floatydrag ); + if( run_sim ){ + rb_effect_simple_bouyency( &pj->obj.rb, world->water.plane, + k_ragdoll_floatyiness, + k_ragdoll_floatydrag ); + } } } @@ -393,10 +450,10 @@ VG_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 ); @@ -404,17 +461,30 @@ VG_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.25f ); + 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.5f ); + rb_correct_position_constraints( rd->position_constraints, + rd->position_constraints_count, + k_ragdoll_correction * 0.5f ); + } } rb_ct *stress = NULL; @@ -438,6 +508,68 @@ VG_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; @@ -446,7 +578,8 @@ VG_STATIC void player_ragdoll_iter( struct player_ragdoll *rd ) if( stress ){ temp_filter = 20; audio_lock(); - audio_oneshot_3d( &audio_hits[rand()%5], stress->co, 20.0f, 1.0f ); + audio_oneshot_3d( &audio_hits[vg_randu32(&vg.rand)%5], + stress->co, 20.0f, 1.0f ); audio_unlock(); } }