From: hgn Date: Mon, 11 Dec 2023 16:03:09 +0000 (+0000) Subject: ragdoll quality improvements X-Git-Url: https://harrygodden.com/git/?p=carveJwlIkooP6JGAAIwe30JlM.git;a=commitdiff_plain;h=08b11851edbca3f8951b6023554169cc67aa4f22 ragdoll quality improvements --- diff --git a/models_src/ch_none.mdl b/models_src/ch_none.mdl index fb3b9ea..34a6cc1 100644 Binary files a/models_src/ch_none.mdl and b/models_src/ch_none.mdl differ diff --git a/player.h b/player.h index 18936a7..c18e51b 100644 --- a/player.h +++ b/player.h @@ -152,6 +152,8 @@ struct { id_ik_elbow_l, id_ik_elbow_r, id_head, + id_foot_l, + id_foot_r, id_ik_foot_l, id_ik_foot_r, id_ik_knee_l, diff --git a/player_dead.c b/player_dead.c index 1f6087b..4ee2236 100644 --- a/player_dead.c +++ b/player_dead.c @@ -138,9 +138,9 @@ static void player__dead_post_animate(void){ static void player__dead_im_gui(void){ } -static void player__dead_transition(void){ +static void player__dead_transition( enum player_die_type type ){ localplayer.subsystem = k_player_subsystem_dead; - copy_localplayer_to_ragdoll( &localplayer.ragdoll, localplayer.rb.v ); + copy_localplayer_to_ragdoll( &localplayer.ragdoll, type ); struct ragdoll_part *part = &localplayer.ragdoll.parts[ localplayer.id_hip-1 ]; diff --git a/player_dead.h b/player_dead.h index 19d6e59..e4c177e 100644 --- a/player_dead.h +++ b/player_dead.h @@ -24,7 +24,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_transition (void); +static void player__dead_transition ( enum player_die_type type ); static void player__dead_animator_exchange( bitpack_ctx *ctx, void *data ); struct player_subsystem_interface static player_subsystem_dead = { diff --git a/player_ragdoll.c b/player_ragdoll.c index f0a6f88..ff6a533 100644 --- a/player_ragdoll.c +++ b/player_ragdoll.c @@ -4,12 +4,47 @@ #include "player.h" #include "audio.h" -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_limit_scale ); 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 ); } static void player_init_ragdoll_bone_collider( struct skeleton_bone *bone, @@ -226,12 +261,20 @@ static void copy_ragdoll_pose_to_localplayer( struct player_ragdoll *rd ){ /* * Make the ragdoll copy the player model */ -static void copy_localplayer_to_ragdoll( struct player_ragdoll *rd, v3f v ){ +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; + v3f *bone_mtx = localplayer.final_mtx[bone]; m4x3_mulv( bone_mtx, localplayer.skeleton.bones[bone].co, pos ); @@ -242,8 +285,19 @@ static void copy_localplayer_to_ragdoll( struct player_ragdoll *rd, v3f v ){ m3x3_mul( bone_mtx, part->collider_mtx, r ); m3x3_q( r, part->obj.rb.q ); - v3_copy( v, 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 ); @@ -401,10 +455,10 @@ static void player_ragdoll_iter( struct player_ragdoll *rd ){ rb_update_transform( &rd->parts[i].obj.rb ); rb_correct_swingtwist_constraints( rd->cone_constraints, - rd->cone_constraints_count, 0.25f ); + rd->cone_constraints_count, 0.125f ); rb_correct_position_constraints( rd->position_constraints, - rd->position_constraints_count, 0.5f ); + rd->position_constraints_count, 0.25f ); } rb_ct *stress = NULL; diff --git a/player_ragdoll.h b/player_ragdoll.h index 2ea5727..0afc330 100644 --- a/player_ragdoll.h +++ b/player_ragdoll.h @@ -45,6 +45,12 @@ static int k_ragdoll_div = 1, k_ragdoll_debug_collider = 1, k_ragdoll_debug_constraints = 0; +enum player_die_type { + k_player_die_type_generic, + k_player_die_type_head, + k_player_die_type_feet +}; + static void player_ragdoll_init(void); static void player_init_ragdoll_bone_collider( struct skeleton_bone *bone, struct ragdoll_part *rp ); @@ -52,7 +58,9 @@ static u32 ragdoll_bone_parent( struct player_ragdoll *rd, u32 bone_id ); static void setup_ragdoll_from_skeleton( struct skeleton *sk, struct player_ragdoll *rd ); static void copy_ragdoll_pose_to_localplayer( struct player_ragdoll *rd ); -static void copy_localplayer_to_ragdoll( struct player_ragdoll *rd, v3f v ); +static void copy_localplayer_to_ragdoll( struct player_ragdoll *rd, + enum player_die_type type ); + static void player_debug_ragdoll(void); static void player_ragdoll_iter( struct player_ragdoll *rd ); diff --git a/player_render.c b/player_render.c index aed6caf..44ab25b 100644 --- a/player_render.c +++ b/player_render.c @@ -35,6 +35,8 @@ static void player_load_animation_reference( const char *path ){ localplayer.id_ik_elbow_l = skeleton_bone_id( sk, "elbow.L" ); localplayer.id_ik_elbow_r = skeleton_bone_id( sk, "elbow.R" ); localplayer.id_head = skeleton_bone_id( sk, "head" ); + localplayer.id_foot_l = skeleton_bone_id( sk, "foot.L" ); + localplayer.id_foot_r = skeleton_bone_id( sk, "foot.R" ); localplayer.id_ik_foot_l = skeleton_bone_id( sk, "foot.IK.L" ); localplayer.id_ik_foot_r = skeleton_bone_id( sk, "foot.IK.R" ); localplayer.id_board = skeleton_bone_id( sk, "board" ); diff --git a/player_replay.c b/player_replay.c index 12f7f6b..c1bf7b4 100644 --- a/player_replay.c +++ b/player_replay.c @@ -333,7 +333,7 @@ void skaterift_restore_frame( replay_frame *frame ){ memcpy( &player_skate.state, src, src_size ); } else if( frame->system == k_player_subsystem_dead ){ - player__dead_transition(); + player__dead_transition(0); struct replay_rb *arr = src; for( u32 i=0; itrick_time > 0.2f) { player__skate_kill_audio(); - player__dead_transition(); + player__dead_transition( k_player_die_type_feet ); } state->trick_euler[0] = roundf( state->trick_euler[0] ); @@ -2048,7 +2048,7 @@ static void player__skate_update(void){ k_player_walk_soundeffect_splash, localplayer.rb.co, 1.0f ); player__skate_kill_audio(); - player__dead_transition(); + player__dead_transition( k_player_die_type_generic ); return; } } @@ -2323,7 +2323,7 @@ begin_collision:; rb_update_transform( &localplayer.rb ); player__skate_kill_audio(); - player__dead_transition(); + player__dead_transition( k_player_die_type_head ); return; } @@ -2491,7 +2491,7 @@ begin_collision:; if( nforce > 4.0f ){ if( nforce > 17.6f ){ v3_muladds( localplayer.rb.v, normal_total, -1.0f, localplayer.rb.v ); - player__dead_transition(); + player__dead_transition( k_player_die_type_feet ); player__skate_kill_audio(); return; } diff --git a/player_walk.c b/player_walk.c index 34ad072..ec863b6 100644 --- a/player_walk.c +++ b/player_walk.c @@ -435,7 +435,7 @@ static void player__walk_update(void){ player__networked_sfx( k_player_subsystem_walk, 32, k_player_walk_soundeffect_splash, localplayer.rb.co, 1.0f ); - player__dead_transition(); + player__dead_transition( k_player_die_type_generic ); return; } } diff --git a/rigidbody.h b/rigidbody.h index 7d878e9..2c074c4 100644 --- a/rigidbody.h +++ b/rigidbody.h @@ -1076,6 +1076,48 @@ static int rb_capsule__triangle( m4x3f mtxA, rb_capsule *c, capsule_manifold manifold; rb_capsule_manifold_init( &manifold ); + + v3f v0, v1, n; + v3_sub( tri[1], tri[0], v0 ); + v3_sub( tri[2], tri[0], v1 ); + v3_cross( v0, v1, n ); + + if( v3_length2( n ) <= 0.00001f ){ +#ifdef RIGIDBODY_CRY_ABOUT_EVERYTHING + vg_error( "Zero area triangle!\n" ); +#endif + return 0; + } + + v3_normalize( n ); + +#if 1 + /* deep penetration recovery. for when we clip through the triangles. so its + * not very 'correct' */ + f32 dist; + if( ray_tri( tri, p0w, mtxA[1], &dist, 1 ) ){ + f32 l = c->height - c->radius*2.0f; + if( (dist >= 0.0f) && (dist < l) ){ + v3f co; + v3_muladds( p0w, mtxA[1], dist, co ); + vg_line_point( co, 0.02f, 0xffffff00 ); + + v3f d0, d1; + v3_sub( p0w, co, d0 ); + v3_sub( p1w, co, d1 ); + + f32 p = vg_minf( v3_dot( n, d0 ), v3_dot( n, d1 ) ) - c->radius; + + rb_ct *ct = buf; + ct->p = -p; + ct->type = k_contact_type_default; + v3_copy( n, ct->n ); + v3_muladds( co, n, p, ct->co ); + + return 1; + } + } +#endif v3f c0, c1; closest_on_triangle_1( p0w, tri, c0 ); @@ -1090,12 +1132,13 @@ static int rb_capsule__triangle( m4x3f mtxA, rb_capsule *c, v3_normalize(d1); v3_normalize(da); + /* the two balls at the ends */ if( v3_dot( da, d0 ) <= 0.01f ) rb_capsule_manifold( p0w, c0, 0.0f, c->radius, &manifold ); - if( v3_dot( da, d1 ) >= -0.01f ) rb_capsule_manifold( p1w, c1, 1.0f, c->radius, &manifold ); + /* the edges to edges */ for( int i=0; i<3; i++ ){ int i0 = i, i1 = (i+1)%3; @@ -1106,20 +1149,6 @@ static int rb_capsule__triangle( m4x3f mtxA, rb_capsule *c, rb_capsule_manifold( ca, cb, ta, c->radius, &manifold ); } - v3f v0, v1, n; - v3_sub( tri[1], tri[0], v0 ); - v3_sub( tri[2], tri[0], v1 ); - v3_cross( v0, v1, n ); - - if( v3_length2( n ) <= 0.00001f ){ -#ifdef RIGIDBODY_CRY_ABOUT_EVERYTHING - vg_error( "Zero area triangle!\n" ); -#endif - return 0; - } - - v3_normalize( n ); - int count = rb_capsule__manifold_done( mtxA, c, &manifold, buf ); for( int i=0; irba, *rbb = ct->rbb; - float mass_total = 1.0f / (rba->inv_mass + rbb->inv_mass); + f32 mass_total = 1.0f / (rba->inv_mass + rbb->inv_mass), + d = ct->p*mass_total*amt; - v3_muladds( rba->co, ct->n, -mass_total * rba->inv_mass, rba->co ); - v3_muladds( rbb->co, ct->n, mass_total * rbb->inv_mass, rbb->co ); + v3_muladds( rba->co, ct->n, -d * rba->inv_mass, rba->co ); + v3_muladds( rbb->co, ct->n, d * rbb->inv_mass, rbb->co ); } } diff --git a/scene.h b/scene.h index ba23ffb..d8fac1a 100644 --- a/scene.h +++ b/scene.h @@ -414,7 +414,7 @@ static int scene_raycast( scene_context *s, bh_tree *bh, v3_copy( s->arrvertices[tri[i]].co, vs[i] ); f32 t; - if( ray_tri( vs, co, dir, &t ) ){ + if( ray_tri( vs, co, dir, &t, 0 ) ){ if( t < hit->dist ){ hit->dist = t; hit->tri = tri;