better physics
authorhgn <hgodden00@gmail.com>
Mon, 7 Nov 2022 03:15:38 +0000 (03:15 +0000)
committerhgn <hgodden00@gmail.com>
Mon, 7 Nov 2022 03:15:38 +0000 (03:15 +0000)
models_src/mp_dev.mdl
player.h
player_physics.h
rigidbody.h
vg_config.h

index e81a01341c43cde9a56c0c1a003ed229df367ec0..5a431b1904064715da263275029b521925514dc1 100644 (file)
Binary files a/models_src/mp_dev.mdl and b/models_src/mp_dev.mdl differ
index 972807b7a9892c1c09caedddd7a3b5a831023d2e..c8c9abc54b8932ecd480838014a44001ca9c4dfb 100644 (file)
--- a/player.h
+++ b/player.h
@@ -14,7 +14,7 @@
 #include "bvh.h"
 
 VG_STATIC float 
-   k_walkspeed             = 20.0f,  /* no longer used */
+   k_walkspeed             = 12.0f,  /* no longer used */
    k_runspeed              = 20.0f,
    k_board_radius          = 0.3f,
    k_board_length          = 0.45f,
@@ -97,7 +97,8 @@ VG_STATIC struct gplayer
                         *input_emjs2v,
                         *input_jump,
                         *input_push,
-                        *input_walk,
+                        *input_walkh,
+                        *input_walkv,
                         *input_switch_mode,
                         *input_reset,
                         *input_grab;
@@ -203,6 +204,8 @@ VG_STATIC void player_save_rewind_frame(void);
 /* 
  * Submodules
  */
+VG_STATIC void player_mouseview(void);
+
 #include "player_physics.h"
 #include "player_ragdoll.h"
 #include "player_model.h"
@@ -226,21 +229,26 @@ VG_STATIC void player_init(void)                                            /* 1
    player.input_emjs2v = vg_create_named_input( "kbgrab-v", k_input_type_axis );
    player.input_jump = vg_create_named_input( "jump", k_input_type_button );
    player.input_push = vg_create_named_input( "push", k_input_type_axis_norm );
-   player.input_walk = vg_create_named_input( "walk", k_input_type_axis_norm );
+
+   player.input_walkh = vg_create_named_input( "walk-h", 
+                                               k_input_type_axis );
+   player.input_walkv = vg_create_named_input( "walk-v", 
+                                               k_input_type_axis );
+
+
    player.input_switch_mode = vg_create_named_input( "switch-mode",
                                                      k_input_type_button );
    player.input_reset = vg_create_named_input( "reset", k_input_type_button );
 
    const char *default_cfg[] = 
    {
-      "bind steer-h gp-ls-h",
       "bind  steer-h gp-ls-h",
       "bind -steer-h a",
       "bind +steer-h d",
 
       "bind  steer-v gp-ls-v",
-      "bind -steer-v s",
-      "bind +steer-v w",
+      "bind -steer-v w",
+      "bind +steer-v s",
 
       "bind grab gp-rt",
       "bind grab-h gp-rs-h",
@@ -256,9 +264,13 @@ VG_STATIC void player_init(void)                                            /* 1
 
       "bind  push gp-lt",
       "bind +push shift",
-
-      "bind  walk gp-lt",
-      "bind +walk w",
+      
+      "bind  walk-h gp-ls-h",
+      "bind  walk-v gp-ls-v",
+      "bind +walk-h d",
+      "bind -walk-h a",
+      "bind +walk-v w",
+      "bind -walk-v s",
 
       "bind reset gp-lb",
       "bind reset r",
@@ -287,7 +299,7 @@ VG_STATIC void player_init(void)                                            /* 1
       .data = &k_walkspeed,
       .data_type = k_convar_dtype_f32,
       .opt_f32 = { .clamp = 0 },
-      .persistent = 1
+      .persistent = 0
    });
 
    vg_convar_push( (struct vg_convar){
@@ -359,6 +371,18 @@ VG_STATIC void player_save_rewind_frame(void)
    }
 }
 
+/*
+ * Free camera movement
+ */
+VG_STATIC void player_mouseview(void)
+{
+   if( ui_want_mouse() )
+      return;
+
+   v2_muladds( player.angles, vg.mouse_delta, 0.0025f, player.angles );
+   player.angles[1] = vg_clampf( player.angles[1], -VG_PIf*0.5f, VG_PIf*0.5f );
+}
+
 /* Deal with input etc */
 VG_STATIC void player_update_pre(void)
 {
@@ -450,6 +474,9 @@ VG_STATIC void player_update_pre(void)
 
       audio_unlock();
    }
+
+   if( !phys->on_board )
+      player_mouseview();
 }
 
 VG_STATIC void player_update_fixed(void)                                    /* 2 */
index 0213fc7b65a18deb66d756b3d20f4b18e64ce8fb..4178e04265eea1d1125640fb97f0b8ec3c41e34d 100644 (file)
@@ -293,130 +293,201 @@ VG_STATIC void player_physics_control_air(void)
 #endif
 }
 
-/*
- * Entire Walking physics model
- * TODO: sleep when under certain velotiy
- */
-VG_STATIC void player_walk_physics(void)
+VG_STATIC void player_walk_update_collision(void)
 {
    struct player_phys *phys = &player.phys;
-   rigidbody *rbf = &player.collide_front,
-             *rbb = &player.collide_back;
-
-   m3x3_copy( phys->rb.to_world, player.collide_front.to_world );
-   m3x3_copy( phys->rb.to_world, player.collide_back.to_world );
-   
    float h0 = 0.3f,
          h1 = 0.9f;
 
-   m4x3_mulv( phys->rb.to_world, (v3f){0.0f,h0,0.0f}, rbf->co );
+   rigidbody *rbf = &player.collide_front,
+             *rbb = &player.collide_back;
+
+   v3_add( phys->rb.co, (v3f){0.0f,h0,0.0f}, rbf->co );
+   v3_add( phys->rb.co, (v3f){0.0f,h1,0.0f}, rbb->co );
    v3_copy( rbf->co, rbf->to_world[3] );
-   m4x3_mulv( phys->rb.to_world, (v3f){0.0f,h1,0.0f}, rbb->co );
    v3_copy( rbb->co, rbb->to_world[3] );
-
    m4x3_invert_affine( rbf->to_world, rbf->to_local );
    m4x3_invert_affine( rbb->to_world, rbb->to_local );
 
    rb_update_bounds( rbf );
    rb_update_bounds( rbb );
+}
 
-   rb_debug( rbf, 0xff0000ff );
-   rb_debug( rbb, 0xff0000ff );
+VG_STATIC void player_integrate(void);
+/*
+ * Entire Walking physics model
+ * TODO: sleep when under certain velotiy
+ */
+VG_STATIC void player_walk_physics(void)
+{
+   struct player_phys *phys = &player.phys;
+   rigidbody *rbf = &player.collide_front,
+             *rbb = &player.collide_back;
 
-   rb_ct manifold[64];
-   int len = 0;
+   m3x3_identity( player.collide_front.to_world );
+   m3x3_identity( player.collide_back.to_world );
 
-   len += rb_sphere_scene( rbf, &world.rb_geo, manifold+len );
-   len += rb_sphere_scene( rbb, &world.rb_geo, manifold+len );
+   v3_zero( phys->rb.w );
+   q_axis_angle( phys->rb.q, (v3f){0.0f,1.0f,0.0f}, -player.angles[0] );
 
-   rb_presolve_contacts( manifold, len );
+   rb_ct manifold[64];
+   int len;
 
-   for( int j=0; j<5; j++ )
+   v3f forward_dir = { sinf(player.angles[0]),0.0f,-cosf(player.angles[0]) };
+   v3f right_dir = { -forward_dir[2], 0.0f, forward_dir[0] };
+
+   if( phys->in_air )
    {
+      player_walk_update_collision();
+      rb_debug( rbf, 0xff0000ff );
+      rb_debug( rbb, 0xff0000ff );
+
+      len = 0;
+      len += rb_sphere_scene( rbf, &world.rb_geo, manifold+len );
+      len += rb_sphere_scene( rbb, &world.rb_geo, manifold+len );
+      rb_presolve_contacts( manifold, len );
+
       for( int i=0; i<len; i++ )
       {
          struct contact *ct = &manifold[i];
-         
-         /*normal */
-         float vn = -v3_dot( phys->rb.v, ct->n );
-         vn += ct->bias;
+         if( v3_dot( ct->n, (v3f){0.0f,1.0f,0.0f} ) > 0.5f )
+            phys->in_air = 0;
+      }
 
-         float temp = ct->norm_impulse;
-         ct->norm_impulse = vg_maxf( temp + vn, 0.0f );
-         vn = ct->norm_impulse - temp;
+      for( int j=0; j<5; j++ )
+      {
+         for( int i=0; i<len; i++ )
+         {
+            struct contact *ct = &manifold[i];
+            
+            /*normal */
+            float vn = -v3_dot( phys->rb.v, ct->n );
+            vn += ct->bias;
 
-         v3f impulse;
-         v3_muls( ct->n, vn, impulse );
+            float temp = ct->norm_impulse;
+            ct->norm_impulse = vg_maxf( temp + vn, 0.0f );
+            vn = ct->norm_impulse - temp;
 
-         v3_add( impulse, phys->rb.v, phys->rb.v );
+            v3f impulse;
+            v3_muls( ct->n, vn, impulse );
 
-         /* friction */
-         for( int j=0; j<2; j++ )
-         {
-            float     f = k_friction * ct->norm_impulse,
-                     vt = v3_dot( phys->rb.v, ct->t[j] ),
-                 lambda = -vt;
-            
-            float temp = ct->tangent_impulse[j];
-            ct->tangent_impulse[j] = vg_clampf( temp + lambda, -f, f );
-            lambda = ct->tangent_impulse[j] - temp;
+            v3_add( impulse, phys->rb.v, phys->rb.v );
+
+            /* friction */
+            for( int j=0; j<2; j++ )
+            {
+               float     f = k_friction * ct->norm_impulse,
+                        vt = v3_dot( phys->rb.v, ct->t[j] ),
+                    lambda = -vt;
+               
+               float temp = ct->tangent_impulse[j];
+               ct->tangent_impulse[j] = vg_clampf( temp + lambda, -f, f );
+               lambda = ct->tangent_impulse[j] - temp;
 
-            v3_muladds( phys->rb.v, ct->t[j], lambda, phys->rb.v );
+               v3_muladds( phys->rb.v, ct->t[j], lambda, phys->rb.v );
+            }
          }
       }
-   }
 
-   if( len == 0 )
-      phys->in_air = 1;
+      player_integrate();
+   }
    else
    {
-      phys->in_air = 0;
-      struct world_material *surface_mat = world_contact_material( manifold );
-      player.surface_prop = surface_mat->info.surface_prop;
-   }
+      /* translate player */
+      v2f walk = { player.input_walkh->axis.value,
+                   player.input_walkv->axis.value };
+      
+      if( v2_length2(walk) > 0.001f )
+         v2_normalize( walk );
 
-   if( !phys->in_air )
-   {
-      float const DOWNFORCE = -k_walk_downforce*VG_TIMESTEP_FIXED;
-      v3_muladds( phys->rb.v, (v3f){0.0f,-1.0f,0.0f}, DOWNFORCE, phys->rb.v );
+      v2_muls( walk, vg_maxf( player.input_push->axis.value, 0.5f ) *
+                        k_walkspeed * VG_TIMESTEP_FIXED, walk );
 
+      v3f walk_apply;
+      v3_zero( walk_apply );
+
+      /* Do XY translation */
+      v3_muladds( walk_apply, right_dir,   walk[0], walk_apply );
+      v3_muladds( walk_apply, forward_dir, walk[1], walk_apply );
+      v3_add( walk_apply, phys->rb.co, phys->rb.co );
+      v3_divs( walk_apply, VG_TIMESTEP_FIXED, phys->rb.v );
+
+      /* Directly resolve collisions */
+      player_walk_update_collision();
+      rb_debug( rbf, 0xffffff00 );
+      rb_debug( rbb, 0xffffff00 );
+
+      len = 0;
+      len += rb_sphere_scene( rbf, &world.rb_geo, manifold+len );
+      len += rb_sphere_scene( rbb, &world.rb_geo, manifold+len );
+
+      v3f dt;
+      v3_zero( dt );
+      for( int j=0; j<3; j++ )
+      {
+         for( int i=0; i<len; i++ )
+         {
+            struct contact *ct = &manifold[i];
+
+            float p   = vg_maxf( 0.0f, ct->p - 0.00f ),
+                  cur = vg_clampf( v3_dot( ct->n, dt ), 0.0f, p );
+            v3_muladds( dt, ct->n, (p - cur) * 0.333333333f, dt );
+         }
+      }
+      v3_add( dt, phys->rb.co, phys->rb.co );
+
+      /* jump */
       if( player.input_jump->button.value )
       {
          phys->rb.v[1] = 5.0f;
+         phys->in_air = 1;
+         return;
       }
-   }
-   
-   v3_zero( phys->rb.w );
-   q_axis_angle( phys->rb.q, (v3f){0.0f,1.0f,0.0f}, -player.angles[0] );
-
-   v3f forward_dir = { sinf(player.angles[0]),0.0f,-cosf(player.angles[0]) };
+      
+      /* if we've put us in the air, step down slowly */
+      phys->in_air = 1;
+      float max_dist = 0.3f,
+            start_y = phys->rb.co[1];
 
-   v3f p1;
-   v3_muladds( phys->rb.co, forward_dir, 2.0f, p1 );
-   vg_line( phys->rb.co, p1, 0xff0000ff );
+      for( int j=0; j<8; j++ )
+      {
+         for( int i=0; i<len; i++ )
+         {
+            struct contact *ct = &manifold[i];
+            if( v3_dot( ct->n, (v3f){0.0f,1.0f,0.0f} ) > 0.5f )
+            {
+               phys->in_air = 0;
+               if( j == 0 )
+                  return;
+
+               v3f dt;
+               v3_zero( dt );
+               for( int j=0; j<3; j++ )
+               {
+                  for( int i=0; i<len; i++ )
+                  {
+                     struct contact *ct = &manifold[i];
+
+                     float p   = vg_maxf( 0.0f, ct->p - 0.0025f ),
+                           cur = vg_clampf( v3_dot( ct->n, dt ), 0.0f, p );
+                     v3_muladds( dt, ct->n, (p - cur) * 0.333333333f, dt );
+                  }
+               }
+               v3_add( dt, phys->rb.co, phys->rb.co );
+               return;
+            }
+         }
 
-   float walk = player.input_walk->axis.value;
-   player.walk = powf( walk, 4.0f );
+         phys->rb.co[1] -= max_dist * 0.125f;
 
-   if( player.walk > 0.025f )
-   {
-      float 
-            speed     = vg_lerpf( 0.025f*k_runspeed, k_runspeed, player.walk ),
-            amt       = k_walk_accel * VG_TIMESTEP_FIXED,
-            zvel      = v3_dot( phys->rb.v, forward_dir ),
-            new_vel   = vg_minf( zvel + amt, speed ),
-            diff      = new_vel - vg_minf( zvel, speed );
-
-      if( !phys->in_air )
-      {
-         v3_muladds( phys->rb.v, forward_dir, diff, phys->rb.v );
+         player_walk_update_collision();
+         len = 0;
+         len += rb_sphere_scene( rbf, &world.rb_geo, manifold+len );
+         len += rb_sphere_scene( rbb, &world.rb_geo, manifold+len );
       }
-   }
-   
-   if( !phys->in_air )
-   {
-      phys->rb.v[0] *= 1.0f - (VG_TIMESTEP_FIXED * k_walk_friction);
-      phys->rb.v[2] *= 1.0f - (VG_TIMESTEP_FIXED * k_walk_friction);
+      
+      /* Transitioning into air mode */
+      phys->rb.co[1] = start_y;
    }
 }
 
@@ -645,6 +716,13 @@ VG_STATIC void player_restore_frame(void)
    rb_update_transform( &player.phys.rb );
 }
 
+VG_STATIC void player_integrate(void)
+{
+   struct player_phys *phys = &player.phys;
+   apply_gravity( phys->rb.v, VG_TIMESTEP_FIXED );
+   v3_muladds( phys->rb.co, phys->rb.v, VG_TIMESTEP_FIXED, phys->rb.co );
+}
+
 VG_STATIC void player_do_motion(void)
 {
    struct player_phys *phys = &player.phys;
@@ -664,18 +742,19 @@ VG_STATIC void player_do_motion(void)
       }
    }
 
+
+   v3f prevco;
+   v3_copy( phys->rb.co, prevco );
+
    if( phys->on_board )
+   {
       player_physics();
+      player_integrate();
+   }
    else
       player_walk_physics();
    
-   /* Integrate velocity */
-   v3f prevco;
-   v3_copy( phys->rb.co, prevco );
    
-   apply_gravity( phys->rb.v, VG_TIMESTEP_FIXED );
-   v3_muladds( phys->rb.co, phys->rb.v, VG_TIMESTEP_FIXED, phys->rb.co );
-
    /* Real angular velocity integration */
    v3_lerp( phys->rb.w, (v3f){0.0f,0.0f,0.0f}, 0.125f, phys->rb.w );
    if( v3_length2( phys->rb.w ) > 0.0f )
@@ -748,36 +827,6 @@ VG_STATIC void player_do_motion(void)
    rb_update_transform( &phys->rb );
 }
 
-/*
- * Free camera movement
- */
-VG_STATIC void player_mouseview(void)
-{
-   if( ui_want_mouse() )
-      return;
-
-   static v2f mouse_last,
-              view_vel = { 0.0f, 0.0f };
-
-#if 0
-   if( vg_get_button_down( "primary" ) )
-      v2_copy( vg.mouse, mouse_last );
-
-   else if( vg_get_button( "primary" ) )
-   {
-      v2f delta;
-      v2_sub( vg.mouse, mouse_last, delta );
-      v2_copy( vg.mouse, mouse_last );
-
-      v2_muladds( view_vel, delta, 0.06f*vg.time_delta, view_vel );
-   }
-#endif
-   
-   v2_muls( view_vel, 1.0f-4.2f*vg.time_delta, view_vel );
-   v2_add( view_vel, player.angles, player.angles );
-   player.angles[1] = vg_clampf( player.angles[1], -VG_PIf*0.5f, VG_PIf*0.5f );
-}
-
 VG_STATIC void player_freecam(void)
 {
    player_mouseview();
index 94ad18142249a4f76d31f87af06efdfabc0c5572..10b4359f56537641354c59e982e0d9d8a37b6098 100644 (file)
@@ -1252,7 +1252,7 @@ VG_STATIC int rb_sphere_triangle( rigidbody *rba, rigidbody *rbb,
 {
    v3f delta, co;
 
-   closest_on_triangle( rba->co, tri, co );
+   closest_on_triangle_1( rba->co, tri, co );
    v3_sub( rba->co, co, delta );
 
    vg_line( rba->co, co, 0xffff0000 );
index 8b1ea59eb7d2748fcd0ae3b4d5d4bbae00fe80be..08006140c61c2c52b14b69884ab1bc46769c01b1 100644 (file)
@@ -14,10 +14,13 @@ VG_STATIC struct button_binding vg_button_binds[] =
    { .name = "forward", .bind = GLFW_KEY_W },
    { .name = "back", .bind = GLFW_KEY_S },
    { .name = "up", .bind = GLFW_KEY_R },
+   { .name = "reset", .bind = GLFW_KEY_R },
    { .name = "down", .bind = GLFW_KEY_F },
    { .name = "yawl", .bind = GLFW_KEY_Q },
    { .name = "yawr", .bind = GLFW_KEY_E },
-   { .name = "push", .bind = GLFW_KEY_T },
+   { .name = "jump", .bind = GLFW_KEY_SPACE },
+   { .name = "kbdwalk/push", .bind = GLFW_KEY_LEFT_SHIFT },
+   { .name = "switchmode", .bind = GLFW_KEY_E },
    { .name = "menu", .bind = GLFW_KEY_ESCAPE }
 };