From 0a40a20806ec52fc13817fd78a43793de5e32ffa Mon Sep 17 00:00:00 2001 From: hgn Date: Fri, 10 Feb 2023 19:43:59 +0000 Subject: [PATCH] get fak --- common.h | 15 +- maps_src/mp_gridmap.mdl | Bin 1422720 -> 1424944 bytes player_skate.c | 463 ++++++++++++++++++++++++++-------------- player_skate.h | 2 + player_walk.c | 2 +- rigidbody.h | 12 +- 6 files changed, 316 insertions(+), 178 deletions(-) diff --git a/common.h b/common.h index 49d2c99..2c48560 100644 --- a/common.h +++ b/common.h @@ -99,8 +99,6 @@ VG_STATIC void str_utf8_collapse( const char *str, char *buf, u32 length ) VG_STATIC float k_runspeed = 20.0f, /* depr */ - k_board_radius = 0.3f, - k_board_length = 0.45f, k_board_allowance = 0.04f, k_friction_lat = 12.0f, k_friction_resistance = 0.01f, @@ -136,9 +134,16 @@ VG_STATIC float k_grind_spring = 100.0f, k_grind_dampener = 1.0f, - k_board_spring = 2.0f, - k_board_dampener = 0.2f, - k_board_interia = 8.0f; + k_board_spring = 100.0f, + k_board_dampener = 20.0f, + k_manul_spring = 200.0f, + k_manul_dampener = 30.0f, + k_board_interia = 8.0f, + + k_board_length = 0.45f, + k_board_width = 0.13f, + k_board_end_radius = 0.2f, + k_board_radius = 0.07f; VG_STATIC float diff --git a/maps_src/mp_gridmap.mdl b/maps_src/mp_gridmap.mdl index e20369b630d48456e26a3d2c25e5e9290f083a88..43b26adbd59e1191d08075e9b632a9018d9b3fd8 100644 GIT binary patch delta 6757 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 delta 4943 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 NV|!g#?&DHd@PDm&N}>P& diff --git a/player_skate.c b/player_skate.c index eb4e27e..a04a0dd 100644 --- a/player_skate.c +++ b/player_skate.c @@ -1475,38 +1475,53 @@ VG_STATIC void player__skate_update( player_instance *player ) v3_copy( player->rb.co, s->state.prev_pos ); s->state.activity_prev = s->state.activity; - float l = k_board_length, - w = 0.13f; - -#if 0 - v3f wheel_positions[] = + struct board_collider { - { -w, 0.0f, -l }, - { w, 0.0f, -l }, - { -w, 0.0f, l }, - { w, 0.0f, l }, - }; -#else - v3f wheel_positions[] = - { - { 0.0f, 0.0f, -l }, - { 0.0f, 0.0f, l }, - }; -#endif + v3f pos; + float radius; - u32 wheel_colours[] = - { - VG__RED, VG__GREEN, VG__BLUE, VG__YELOW - }; + int apply_angular; + u32 colour; - int wheel_states[] = + enum board_collider_state + { + k_collider_state_default, + k_collider_state_disabled, + k_collider_state_colliding + } + state; + } + wheels[] = { - 1, 1, 1, 1 + { + { 0.0f, 0.0f, -k_board_length }, + .radius = 0.07f, + .apply_angular = 1, + .colour = VG__RED + }, + { + { 0.0f, 0.0f, k_board_length }, + .radius = 0.07f, + .apply_angular = 1, + .colour = VG__GREEN + }, + { + { 0.0f, k_board_end_radius, -k_board_length - k_board_end_radius }, + .radius = k_board_end_radius, + .apply_angular = 0, + .colour = VG__YELOW + }, + { + { 0.0f, k_board_end_radius, k_board_length + k_board_end_radius }, + .radius = k_board_end_radius, + .apply_angular = 0, + .colour = VG__YELOW + }, }; - const int wheel_count = 2; + const int k_wheel_count = 4; - if( skate_grind_scansq( player, (v3f){ 0.0f, 0.0f, -l } ) ) + if( skate_grind_scansq( player, (v3f){ 0.0f, 0.0f, -k_board_length } ) ) { #if 0 wheel_states[0] = 0; @@ -1514,7 +1529,7 @@ VG_STATIC void player__skate_update( player_instance *player ) #endif } - if( skate_grind_scansq( player, (v3f){ 0.0f, 0.0f, l } ) ) + if( skate_grind_scansq( player, (v3f){ 0.0f, 0.0f, k_board_length } ) ) { #if 0 wheel_states[2] = 0; @@ -1522,29 +1537,22 @@ VG_STATIC void player__skate_update( player_instance *player ) #endif } - rb_sphere collider; - collider.radius = 0.07f; - s->substep = k_rb_delta; - - int substep_count = 0; -begin_collision:; + v3f original_velocity; + v3_muladds( player->rb.v, (v3f){0.0f,-k_gravity,0.0f}, + k_rb_delta, original_velocity ); +begin_collision:; - for( int i=0; irb.to_world, mtx ); - m4x3_mulv( player->rb.to_world, wheel_positions[i], mtx[3] ); - debug_sphere( mtx, collider.radius, - (u32[]){ VG__BLACK, VG__WHITE, - wheel_colours[i] }[ wheel_states[i] ]); - } - + /* + * Phase 0: Continous collision detection + * -------------------------------------------------------------------------- + */ -#ifdef SKATE_CCD + for( int i=0; isubstep, - cast_radius = collider.radius - k_penetration_slop*1.2f; + float max_time = s->substep; - for( int i=0; irb.q, wheel_positions[i], current ); + q_mulv( player->rb.q, wheels[i].pos, current ); v3_add( current, player->rb.co, current ); - float t; /* TODO: ignore lightly grazing normals? */ + float t; v3f n; + + float cast_radius = wheels[i].radius - k_penetration_slop * 1.2f; if( spherecast_world( current, future, cast_radius, &t, n ) != -1) - { max_time = vg_minf( max_time, t * s->substep ); - } } /* clamp to a fraction of delta, to prevent locking */ @@ -1615,123 +1622,259 @@ begin_collision:; v3f gravity = { 0.0f, -9.6f, 0.0f }; v3_muladds( player->rb.v, gravity, s->substep_delta, player->rb.v ); -#else - - s->substep_delta = k_rb_delta; - -#endif - s->substep -= s->substep_delta; + /* + * Phase 1: Regular collision detection + * TODO: Me might want to automatically add contacts from CCD, + * since at high angular velocities, theres a small change + * that discreet detection will miss. + * -------------------------------------------------------------------------- + */ - /* create manifold(s) */ rb_ct manifold[128]; + + int manifold_len = 0; - int manifold_len = 0, - manifold_front = 0, - manifold_back = 0, - manifold_interface = 0; - - rb_ct *cmanifold = manifold; - - for( int i=0; irb.to_world, wheel_positions[i], mtx[3] ); + m4x3_mulv( player->rb.to_world, wheels[i].pos, mtx[3] ); - int l = skate_collide_smooth( player, mtx, &collider, cmanifold ); + rb_sphere collider = { .radius = wheels[i].radius }; + rb_ct *man = &manifold[ manifold_len ]; + + int l = skate_collide_smooth( player, mtx, &collider, man ); if( l ) - wheel_states[i] = 2; + wheels[i].state = k_collider_state_colliding; - cmanifold += l; - manifold_len += l; - manifold_interface += l; + /* for non-angular contacts we just want Y. contact positions are + * snapped to the local xz plane */ + if( !wheels[i].apply_angular ) + { + for( int j=0; jrb.co, ra ); - if( i<=1 ) - manifold_front ++; - else - manifold_back ++; + float dy = v3_dot( player->rb.to_world[1], ra ); + v3_muladds( man[j].co, player->rb.to_world[1], -dy, man[j].co ); + } + } + + manifold_len += l; } -#if 0 - /* try to slap both wheels onto the ground when landing to prevent mega - * angular velocities being added */ - if( (s->state.activity == k_skate_activity_air) && - (manifold_front != manifold_back ) ) + /* + * Phase 2: Truck alignment (spring/dampener model) + * it uses the first two colliders as truck positions + * -------------------------------------------------------------------------- + */ + + v3f surface_picture; + v3_zero( surface_picture ); + + for( int i=0; i<2; i++ ) { - v3f trace_from, trace_dir; - v3_muls( player->rb.to_world[1], -1.0f, trace_dir ); + v3f truck, left, right; + m4x3_mulv( player->rb.to_world, wheels[i].pos, truck ); + v3_muladds( truck, player->rb.to_world[0], -k_board_width, left ); + v3_muladds( truck, player->rb.to_world[0], k_board_width, right ); + + vg_line( left, right, wheels[i].colour ); - if( manifold_front ) - v3_copy( (v3f){0.0f,0.0f, k_board_length}, trace_from ); - else - v3_copy( (v3f){0.0f,0.0f,-k_board_length}, trace_from ); - m4x3_mulv( player->rb.to_world, trace_from, trace_from ); + v3_muladds( left, player->rb.to_world[1], 0.1f, left ); + v3_muladds( right, player->rb.to_world[1], 0.1f, right ); + + float k_max_truck_flex = VG_PIf * 0.25f; + + ray_hit ray_l, ray_r; + ray_l.dist = 0.2f; + ray_r.dist = 0.2f; + + v3f dir; + v3_muls( player->rb.to_world[1], -1.0f, dir ); + + int res_l = ray_world( left, dir, &ray_l ), + res_r = ray_world( right, dir, &ray_r ); + + /* ignore bad normals */ + if( res_l ) + { + if( v3_dot( ray_l.normal, player->rb.to_world[1] ) < 0.7071f ) + res_l = 0; + else + v3_add( ray_l.normal, surface_picture, surface_picture ); + } - ray_hit ray; - ray.dist = 0.6f; + if( res_r ) + { + if( v3_dot( ray_r.normal, player->rb.to_world[1] ) < 0.7071f ) + res_r = 0; + else + v3_add( ray_l.normal, surface_picture, surface_picture ); + } + + v3f v0; + v3f midpoint; + v3_muladds( truck, player->rb.to_world[1], -wheels[i].radius, midpoint ); - if( ray_world( trace_from, trace_dir, &ray ) ) + if( res_l || res_r ) { - rb_ct *ct = cmanifold; + v3f p0, p1; + v3_copy( midpoint, p0 ); + v3_copy( midpoint, p1 ); - v3_copy( ray.pos, ct->co ); - v3_copy( ray.normal, ct->n ); - ct->p = 0.0f; + if( res_l ) v3_copy( ray_l.pos, p0 ); + if( res_r ) v3_copy( ray_r.pos, p1 ); - manifold_len ++; - manifold_interface ++; + v3_sub( p1, p0, v0 ); + v3_normalize( v0 ); + } + else + { + /* fallback: use the closes point to the trucks */ + v3f closest; + int idx = bh_closest_point( world.geo_bh, midpoint, closest, 0.1f ); + + if( idx != -1 ) + { + u32 *tri = &world.scene_geo->arrindices[ idx * 3 ]; + v3f verts[3]; + + for( int j=0; j<3; j++ ) + v3_copy( world.scene_geo->arrvertices[ tri[j] ].co, verts[j] ); + + v3f v0, v1, n; + v3_sub( verts[1], verts[0], v0 ); + v3_sub( verts[2], verts[0], v1 ); + v3_cross( v0, v1, n ); + v3_normalize( n ); + + if( v3_dot( n, player->rb.to_world[1] ) < 0.7071f ) + continue; + + continue; + } + else + continue; } + + float a = vg_clampf( v3_dot( v0, player->rb.to_world[0] ), -1.0f, 1.0f ); + a = acosf( a ); + + v3_muladds( truck, v0, k_board_width, right ); + v3_muladds( truck, v0, -k_board_width, left ); + + vg_line( left, right, VG__WHITE ); + + v3f axis; + v3_cross( v0, player->rb.to_world[0], axis ); + + float Fs = -a * k_board_spring, + Fd = -v3_dot( player->rb.w, axis ) * k_board_dampener; + + v3_muladds( player->rb.w, axis, (Fs+Fd) * s->substep_delta, + player->rb.w ); } - int grind_len = skate_grind_collide( player, cmanifold ); - manifold_len += grind_len; -#endif + /* + * Phase 2a: Manual alignment (spring/dampener model) + * -------------------------------------------------------------------------- + */ - int grind_len = 0; + v3f weight, world_cog; + v3_zero( weight ); - v3f surface_normal = {0.0f,0.0f,0.0f}; + int reverse_dir = v3_dot( player->rb.to_world[2], player->rb.v ) < 0.0f?1:-1; - for( int i=0; istate.manual_direction == 0 ) + { + if( (player->input_js1v->axis.value > 0.7f) && + s->state.activity == k_skate_activity_ground ) + s->state.manual_direction = reverse_dir; + } + else { - rb_ct *ct = &manifold[i]; - ct->bias = -0.2f * - (s->substep_delta * 3600.0f) - * vg_minf( 0.0f, -ct->p+k_penetration_slop ); - rb_tangent_basis( ct->n, ct->t[0], ct->t[1] ); - ct->norm_impulse = 0.0f; - ct->tangent_impulse[0] = 0.0f; - ct->tangent_impulse[1] = 0.0f; + if( player->input_js1v->axis.value < 0.1f ) + { + s->state.manual_direction = 0; + } + else + { + if( reverse_dir != s->state.manual_direction ) + { + player__dead_transition( player ); + return; + } + } + } - v3_add( ct->n, surface_normal, surface_normal ); + if( s->state.manual_direction ) + { + float amt = vg_minf( player->input_js1v->axis.value * 8.0f, 1.0f ); + weight[2] = k_board_length * amt * (float)s->state.manual_direction; } - if( manifold_len ) + m4x3_mulv( player->rb.to_world, weight, world_cog ); + vg_line_pt3( world_cog, 0.1f, VG__BLACK ); + + /* TODO: Fall back on land normal */ + /* TODO: Lerp weight distribution */ + + if( v3_length2( surface_picture ) > 0.001f && + v3_length2( weight ) > 0.001f && + s->state.manual_direction ) { - v3_muls( surface_normal, 1.0f/(float)manifold_len, surface_normal ); + v3_normalize( surface_picture ); + v3f plane_z; - float a = v3_dot( player->rb.to_world[1], surface_normal ); + m3x3_mulv( player->rb.to_world, weight, plane_z ); + v3_negate( plane_z, plane_z ); - if( a <= 0.9999f ) - { - v3f axis; - v3_cross( surface_normal, player->rb.to_world[1], axis ); + v3_muladds( plane_z, surface_picture, + -v3_dot( plane_z, surface_picture ), plane_z ); + v3_normalize( plane_z ); - float Fs = -a * k_board_spring, - Fd = -v3_dot( player->rb.w, axis ) * k_board_dampener; + v3_muladds( plane_z, surface_picture, 0.3f, plane_z ); + v3_normalize( plane_z ); - v3_muladds( player->rb.w, axis, (Fs+Fd) * s->substep_delta, - player->rb.w ); - } + v3f p1; + v3_muladds( player->rb.co, plane_z, 1.5f, p1 ); + vg_line( player->rb.co, p1, VG__GREEN ); + + v3f refdir; + v3_muls( player->rb.to_world[2], -(float)s->state.manual_direction, + refdir ); + + float a = v3_dot( plane_z, refdir ); + a = acosf( vg_clampf( a, -1.0f, 1.0f ) ); + + v3f axis; + v3_cross( plane_z, refdir, axis ); + + float Fs = -a * k_manul_spring, + Fd = -v3_dot( player->rb.w, axis ) * k_manul_dampener; + + v3_muladds( player->rb.w, axis, (Fs+Fd) * s->substep_delta, + player->rb.w ); } - v3f extent = { w, 0.1f, k_board_length }; + /* + * Phase 3: Dynamics + * -------------------------------------------------------------------------- + */ + + for( int i=0; isubstep_delta ); + + /* yes, we are currently rebuilding mass matrices every frame. too bad! */ + v3f extent = { k_board_width, 0.1f, k_board_length }; float ex2 = k_board_interia*extent[0]*extent[0], ey2 = k_board_interia*extent[1]*extent[1], ez2 = k_board_interia*extent[2]*extent[2]; @@ -1759,10 +1902,14 @@ begin_collision:; { for( int i=0; ico, player->rb.co, delta ); + v3_sub( ct->co, world_cog, delta ); v3_cross( player->rb.w, delta, rv ); v3_add( player->rb.v, rv, rv ); @@ -1772,13 +1919,9 @@ begin_collision:; v3f raCnI, rbCnI; m3x3_mulv( iIw, raCn, raCnI ); - float normal_mass = 1.0f / (inv_mass + v3_dot(raCn,raCnI)); - float vn = v3_dot( rv, ct->n ); - - - - - float lambda = normal_mass * ( -vn + ct->bias ); + float normal_mass = 1.0f / (inv_mass + v3_dot(raCn,raCnI)), + vn = v3_dot( rv, ct->n ), + lambda = normal_mass * ( -vn + ct->bias ); float temp = ct->norm_impulse; ct->norm_impulse = vg_maxf( temp + lambda, 0.0f ); @@ -1787,15 +1930,6 @@ begin_collision:; v3f impulse; v3_muls( ct->n, lambda, impulse ); -#if 0 - if( fabsf(v3_dot( impulse, player->rb.to_world[2] )) > 10.0f || - fabsf(v3_dot( impulse, player->rb.to_world[1] )) > 50.0f ) - { - player__dead_transition( player ); - return; - } -#endif - v3_muladds( player->rb.v, impulse, inv_mass, player->rb.v ); v3_cross( delta, impulse, impulse ); m3x3_mulv( iIw, impulse, impulse ); @@ -1804,42 +1938,41 @@ begin_collision:; v3_cross( player->rb.w, delta, rv ); v3_add( player->rb.v, rv, rv ); vn = v3_dot( rv, ct->n ); - } } - - - - - - substep_count ++; - if( s->substep >= 0.0001f ) - goto begin_collision; - + goto begin_collision; /* again! */ + /* + * End of collision and dynamics routine + * -------------------------------------------------------------------------- + */ - for( int i=0; irb.to_world, mtx ); - m4x3_mulv( player->rb.to_world, wheel_positions[i], mtx[3] ); - debug_sphere( mtx, collider.radius, - (u32[]){ VG__BLACK, VG__WHITE, - wheel_colours[i] }[ wheel_states[i] ]); + m4x3_mulv( player->rb.to_world, wheels[i].pos, mtx[3] ); + debug_sphere( mtx, wheels[i].radius, + (u32[]){ VG__WHITE, VG__BLACK, + wheels[i].colour }[ wheels[i].state ]); } + v3f velocity_change, p1; + v3_sub( player->rb.v, original_velocity, velocity_change ); + v3_normalize( velocity_change ); + v3_muladds( player->rb.co, velocity_change, 2.0f, p1 ); + vg_line( player->rb.co, p1, VG__PINK ); +#if 0 + skate_apply_grind_model( player, &manifold[manifold_len], grind_len ); +#endif - - - - skate_apply_grind_model( player, &manifold[manifold_interface], grind_len ); - skate_apply_interface_model( player, manifold, manifold_interface ); + skate_apply_interface_model( player, manifold, manifold_len ); skate_apply_pump_model( player ); skate_apply_cog_model( player ); diff --git a/player_skate.h b/player_skate.h index 24e9ab9..e87e4ba 100644 --- a/player_skate.h +++ b/player_skate.h @@ -25,6 +25,8 @@ struct player_skate reverse, slip; + int manual_direction; + /* tricks */ v3f flip_axis; float flip_time, diff --git a/player_walk.c b/player_walk.c index 0b84ef1..d916c26 100644 --- a/player_walk.c +++ b/player_walk.c @@ -384,7 +384,7 @@ VG_STATIC void player__walk_update( player_instance *player ) v3_add( surface_avg, ct->n, surface_avg ); } - rb_prepare_contact( ct ); + rb_prepare_contact( ct, k_rb_delta ); } /* diff --git a/rigidbody.h b/rigidbody.h index 58b416e..324e5e1 100644 --- a/rigidbody.h +++ b/rigidbody.h @@ -1993,14 +1993,12 @@ VG_STATIC rb_ct *rb_global_ct(void) return rb_contact_buffer + rb_contact_count; } -VG_STATIC void rb_prepare_contact( rb_ct *ct ) +VG_STATIC void rb_prepare_contact( rb_ct *ct, float timestep ) { - ct->bias = -0.2f * k_rb_rate * vg_minf( 0.0f, -ct->p+k_penetration_slop ); + ct->bias = -0.2f * (timestep*3600.0f) + * vg_minf( 0.0f, -ct->p+k_penetration_slop ); + rb_tangent_basis( ct->n, ct->t[0], ct->t[1] ); - -#if 0 - ct->type = k_contact_type_default; -#endif ct->norm_impulse = 0.0f; ct->tangent_impulse[0] = 0.0f; ct->tangent_impulse[1] = 0.0f; @@ -2014,7 +2012,7 @@ VG_STATIC void rb_presolve_contacts( rb_ct *buffer, int len ) for( int i=0; ico, ct->rba->co, ra ); -- 2.25.1