ragdoll quality improvements
authorhgn <hgodden00@gmail.com>
Mon, 11 Dec 2023 16:03:09 +0000 (16:03 +0000)
committerhgn <hgodden00@gmail.com>
Mon, 11 Dec 2023 16:03:09 +0000 (16:03 +0000)
12 files changed:
models_src/ch_none.mdl
player.h
player_dead.c
player_dead.h
player_ragdoll.c
player_ragdoll.h
player_render.c
player_replay.c
player_skate.c
player_walk.c
rigidbody.h
scene.h

index fb3b9eaa3700251d89a674f34d793079f7ef636d..34a6cc12d100d3f76afe9d5e71b6c2b38cc7ad85 100644 (file)
Binary files a/models_src/ch_none.mdl and b/models_src/ch_none.mdl differ
index 18936a7ade2248844468cc7e182299c46ea14042..c18e51b89b88b2bc01fe538a99fd634d18f2ae2b 100644 (file)
--- 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,
index 1f6087be079b30fe671ac9235b0d881ecfc0ad42..4ee223697394643f9dc1b74081e094dc38ee1928 100644 (file)
@@ -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 ];
index 19d6e5900c3eaa96cd664cf39d0746edce9e6a06..e4c177e721c12dc610d83c02ea018df5fea86693 100644 (file)
@@ -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 = {
index f0a6f88c7b5de75bd31888f0fe70a699d6e7d72b..ff6a533bdebe862673e4b89cd2d0d9e264e2f52d 100644 (file)
@@ -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; i<rd->part_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;
index 2ea5727fe1e94b3fbe17348edd057cf7a177b14d..0afc330486d6be8e96bd82790a5b5dc9746ebff8 100644 (file)
@@ -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 );
 
index aed6caf099359f9993c050344ebb1ef17c77a7c3..44ab25b92a755505b8786062b555275f0aa93299 100644 (file)
@@ -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" );
index 12f7f6b830a046559591cda15af319950b766582..c1bf7b4d785e4a0e00326c9a1e91e16c9716ac41 100644 (file)
@@ -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; i<localplayer.ragdoll.part_count; i ++ ){
index 72055cf7ffb6a54dd9eb435ca0c581cd2c2236c3..94b523b3ee3e567c4d3367d33183ff690c36ea2d 100644 (file)
@@ -758,7 +758,7 @@ static void skate_apply_trick_model(void){
           state->trick_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;
       }
index 34ad072a8a5b5d9d27f1cf38dc174f1386cddd28..ec863b62abe3e17fa7c0121a12e9cb13f47cc022 100644 (file)
@@ -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;
       }
    }
index 7d878e9a4976146a08cf09cb9cc2a5519e978408..2c074c47d46aea97d7b56b67d8aa70191f7c198b 100644 (file)
@@ -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; i<count; i++ )
       v3_copy( n, buf[i].n );
@@ -1791,10 +1820,11 @@ static void rb_correct_contact_constraints( rb_ct *buf, int len, float amt ){
       rigidbody *rba = ct->rba,
                 *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 ba23ffbfa4efcc9183153d9cc55f976e0d442bf4..d8fac1ad524a05672feabee916237ddfbeac8acf 100644 (file)
--- 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;