-#ifndef PLAYER_RAGDOLL_C
-#define PLAYER_RAGDOLL_C
+#pragma once
+#include "vg/vg_rigidbody.h"
+#include "vg/vg_rigidbody_collision.h"
+#include "vg/vg_rigidbody_constraints.h"
+#include "scene_rigidbody.h"
#include "player.h"
+#include "player_dead.h"
#include "audio.h"
+static float k_ragdoll_floatyiness = 20.0f,
+ k_ragdoll_floatydrag = 1.0f,
+ k_ragdoll_limit_scale = 1.0f,
+ k_ragdoll_spring = 127.0f,
+ k_ragdoll_dampening = 15.0f,
+ k_ragdoll_correction = 0.5f,
+ k_ragdoll_angular_drag = 0.08f,
+ k_ragdoll_active_threshold = 5.0f;
+
+static int k_ragdoll_div = 1,
+ ragdoll_frame = 0,
+ k_ragdoll_debug_collider = 1,
+ k_ragdoll_debug_constraints = 0;
+
static int dev_ragdoll_saveload(int argc, const char *argv[]){
if( argc != 2 ){
vg_info( "Usage: ragdoll load/save filepath\n" );
return 0;
}
-static void player_ragdoll_init(void){
+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_console_reg_cmd( "ragdoll", dev_ragdoll_saveload, NULL );
}
-static void player_init_ragdoll_bone_collider( struct skeleton_bone *bone,
- struct ragdoll_part *rp )
+void player_init_ragdoll_bone_collider( struct skeleton_bone *bone,
+ struct ragdoll_part *rp )
{
+ f32 k_density = 8.0f,
+ k_inertia_scale = 2.0f;
+
m4x3_identity( rp->collider_mtx );
+ rp->type = bone->collider;
if( bone->collider == k_bone_collider_box ){
v3f delta;
v3_sub( bone->hitbox[1], bone->hitbox[0], delta );
v3_muls( delta, 0.5f, delta );
v3_add( bone->hitbox[0], delta, rp->collider_mtx[3] );
- v3_copy( delta, rp->obj.rb.bbx[1] );
- v3_muls( delta, -1.0f, rp->obj.rb.bbx[0] );
+ v3_muls( delta, -1.0f, rp->inf.box[0] );
+ v3_copy( delta, rp->inf.box[1] );
- q_identity( rp->obj.rb.q );
- rp->obj.type = k_rb_shape_box;
rp->colour = 0xffcccccc;
+
+ rb_setbody_box( &rp->rb, rp->inf.box, k_density, k_inertia_scale );
}
else if( bone->collider == k_bone_collider_capsule ){
v3f v0, v1, tx, ty;
v1[ major_axis ] = 1.0f;
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 ]);
-
+ rp->inf.capsule.r = (fabsf(v3_dot(tx,v0)) + fabsf(v3_dot(ty,v0))) * 0.25f;
+ rp->inf.capsule.h = fabsf(v0[ major_axis ]);
+
/* orientation */
v3_muls( tx, -1.0f, rp->collider_mtx[0] );
v3_muls( v1, -1.0f, rp->collider_mtx[1] );
v3_add( bone->hitbox[0], bone->hitbox[1], rp->collider_mtx[3] );
v3_muls( rp->collider_mtx[3], 0.5f, rp->collider_mtx[3] );
- rp->obj.type = k_rb_shape_capsule;
- rp->obj.inf.capsule.height = l;
- rp->obj.inf.capsule.radius = r;
-
rp->colour = 0xff000000 | (0xff << (major_axis*8));
+
+ rb_setbody_capsule( &rp->rb, rp->inf.capsule.r, rp->inf.capsule.h,
+ k_density, k_inertia_scale );
}
else{
vg_warn( "type: %u\n", bone->collider );
m4x3_invert_affine( rp->collider_mtx, rp->inv_collider_mtx );
/* Position collider into rest */
- m3x3_q( rp->collider_mtx, rp->obj.rb.q );
- v3_add( rp->collider_mtx[3], bone->co, rp->obj.rb.co );
- v3_zero( rp->obj.rb.v );
- v3_zero( rp->obj.rb.w );
- rb_init_object( &rp->obj );
+ m3x3_q( rp->collider_mtx, rp->rb.q );
+ v3_add( rp->collider_mtx[3], bone->co, rp->rb.co );
+ v3_zero( rp->rb.v );
+ v3_zero( rp->rb.w );
+ rb_update_matrices( &rp->rb );
}
/*
* Get parent index in the ragdoll
*/
-static u32 ragdoll_bone_parent( struct player_ragdoll *rd, u32 bone_id ){
+u32 ragdoll_bone_parent( struct player_ragdoll *rd, u32 bone_id )
+{
for( u32 j=0; j<rd->part_count; j++ )
if( rd->parts[ j ].bone_id == bone_id )
return j;
/*
* Setup ragdoll colliders from skeleton
*/
-static void setup_ragdoll_from_skeleton( struct skeleton *sk,
- struct player_ragdoll *rd ){
+void setup_ragdoll_from_skeleton( struct skeleton *sk,
+ struct player_ragdoll *rd )
+{
rd->part_count = 0;
if( !sk->collider_count )
rd->constraint_associations[conid][1] = part_id;
/* Convention: rba -- parent, rbb -- child */
- c->rba = &pp->obj.rb;
- c->rbb = &rp->obj.rb;
+ c->rba = &pp->rb;
+ c->rbb = &rp->rb;
v3f delta;
v3_sub( bj->co, bp->co, delta );
struct rb_constr_swingtwist *a =
&rd->cone_constraints[ rd->cone_constraints_count ++ ];
- a->rba = &pp->obj.rb;
- a->rbb = &rp->obj.rb;
+ a->rba = &pp->rb;
+ a->rbb = &rp->rb;
a->conet = cosf( inf->conet )-0.0001f;
/* Store constraint in local space vectors */
/*
* Make avatar copy the ragdoll
*/
-static void copy_ragdoll_pose_to_localplayer( struct player_ragdoll *rd ){
+void copy_ragdoll_pose_to_localplayer( struct player_ragdoll *rd )
+{
for( int i=0; i<rd->part_count; i++ ){
struct ragdoll_part *part = &rd->parts[i];
v3f co_int;
float substep = vg.time_fixed_extrapolate;
- v3_lerp( part->prev_co, part->obj.rb.co, substep, co_int );
- q_nlerp( part->prev_q, part->obj.rb.q, substep, q_int );
+ v3_lerp( part->prev_co, part->rb.co, substep, co_int );
+ q_nlerp( part->prev_q, part->rb.q, substep, q_int );
q_m3x3( q_int, mtx );
v3_copy( co_int, mtx[3] );
/*
* Make the ragdoll copy the player model
*/
-static void copy_localplayer_to_ragdoll( struct player_ragdoll *rd,
- enum player_die_type type ){
+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[bone].co, pos );
m3x3_mulv( bone_mtx, part->collider_mtx[3], offset );
- v3_add( pos, offset, part->obj.rb.co );
+ v3_add( pos, offset, part->rb.co );
m3x3f r;
m3x3_mul( bone_mtx, part->collider_mtx, r );
- m3x3_q( r, part->obj.rb.q );
+ m3x3_q( r, part->rb.q );
v3f ra, v;
- v3_sub( part->obj.rb.co, centroid, ra );
+ v3_sub( part->rb.co, centroid, ra );
v3_cross( localplayer.rb.w, ra, v );
- v3_add( localplayer.rb.v, v, part->obj.rb.v );
+ v3_add( localplayer.rb.v, v, part->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_zero( part->rb.v );
}
}
- v3_copy( localplayer.rb.w, part->obj.rb.w );
+ v3_copy( localplayer.rb.w, part->rb.w );
- v3_copy( part->obj.rb.co, part->prev_co );
- v4_copy( part->obj.rb.q, part->prev_q );
+ v3_copy( part->rb.co, part->prev_co );
+ v4_copy( part->rb.q, part->prev_q );
- rb_update_transform( &part->obj.rb );
+ rb_update_matrices( &part->rb );
}
}
/*
* Ragdoll physics step
*/
-static void player_ragdoll_iter( struct player_ragdoll *rd ){
+void player_ragdoll_iter( struct player_ragdoll *rd )
+{
world_instance *world = world_current_instance();
int run_sim = 0;
float contact_velocities[256];
+ rigidbody _null = {0};
+ _null.inv_mass = 0.0f;
+ m3x3_zero( _null.iI );
+
for( int i=0; i<rd->part_count; i ++ ){
- v4_copy( rd->parts[i].obj.rb.q, rd->parts[i].prev_q );
- v3_copy( rd->parts[i].obj.rb.co, rd->parts[i].prev_co );
+ v4_copy( rd->parts[i].rb.q, rd->parts[i].prev_q );
+ v3_copy( rd->parts[i].rb.co, rd->parts[i].prev_co );
if( rb_global_has_space() ){
rb_ct *buf = rb_global_buffer();
int l;
- 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,
+ if( rd->parts[i].type == k_bone_collider_capsule ){
+ l = rb_capsule__scene( rd->parts[i].rb.to_world,
+ &rd->parts[i].inf.capsule,
+ NULL, world->geo_bh, 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,
+ else if( rd->parts[i].type == k_bone_collider_box ){
+ l = rb_box__scene( rd->parts[i].rb.to_world,
+ rd->parts[i].inf.box,
+ NULL, world->geo_bh, buf,
k_material_flag_ghosts );
}
else continue;
for( int j=0; j<l; j++ ){
- buf[j].rba = &rd->parts[i].obj.rb;
- buf[j].rbb = &world->rb_geo.rb;
+ buf[j].rba = &rd->parts[i].rb;
+ buf[j].rbb = &_null;
}
rb_contact_count += l;
if( !rb_global_has_space() )
break;
- if( rd->parts[j].obj.type != k_rb_shape_capsule )
+ if( rd->parts[j].type != k_bone_collider_capsule )
continue;
- if( rd->parts[i].obj.type != k_rb_shape_capsule )
+ if( rd->parts[i].type != k_bone_collider_capsule )
continue;
rb_ct *buf = rb_global_buffer();
- int l = rb_capsule__capsule( rd->parts[i].obj.rb.to_world,
- &rd->parts[i].obj.inf.capsule,
- rd->parts[j].obj.rb.to_world,
- &rd->parts[j].obj.inf.capsule,
+ int l = rb_capsule__capsule( rd->parts[i].rb.to_world,
+ &rd->parts[i].inf.capsule,
+ rd->parts[j].rb.to_world,
+ &rd->parts[j].inf.capsule,
buf );
for( int k=0; k<l; k++ ){
- buf[k].rba = &rd->parts[i].obj.rb;
- buf[k].rbb = &rd->parts[j].obj.rb;
+ buf[k].rba = &rd->parts[i].rb;
+ buf[k].rbb = &rd->parts[j].rb;
}
rb_contact_count += l;
struct ragdoll_part *pj = &rd->parts[j];
if( run_sim ){
- rb_effect_simple_bouyency( &pj->obj.rb, world->water.plane,
+ rb_effect_simple_bouyency( &pj->rb, world->water.plane,
k_ragdoll_floatyiness,
k_ragdoll_floatydrag );
}
contact_velocities[i] = vn;
}
- rb_presolve_contacts( rb_contact_buffer, rb_contact_count );
+ rb_presolve_contacts( rb_contact_buffer, vg.time_fixed_delta,
+ rb_contact_count );
rb_presolve_swingtwist_constraints( rd->cone_constraints,
rd->cone_constraints_count );
* DEBUG
*/
if( k_ragdoll_debug_collider ){
- for( u32 i=0; i<rd->part_count; i ++ )
- rb_object_debug( &rd->parts[i].obj, rd->parts[i].colour );
+ for( u32 i=0; i<rd->part_count; i ++ ){
+ struct ragdoll_part *rp = &rd->parts[i];
+
+ if( rp->type == k_bone_collider_capsule ){
+ vg_line_capsule( rp->rb.to_world,
+ rp->inf.capsule.r, rp->inf.capsule.h, rp->colour );
+ }
+ else if( rp->type == k_bone_collider_box ){
+ vg_line_boxf_transformed( rp->rb.to_world,
+ rp->inf.box, rp->colour );
+ }
+ }
}
if( k_ragdoll_debug_constraints ){
* SOLVE CONSTRAINTS & Integrate
*/
if( run_sim ){
- 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 );
+ /* the solver is not very quickly converging so... */
+ for( int i=0; i<40; i++ ){
+ if( i<20 ){
+ rb_solve_contacts( rb_contact_buffer, rb_contact_count );
+ rb_solve_swingtwist_constraints( rd->cone_constraints,
+ rd->cone_constraints_count );
+ rb_postsolve_swingtwist_constraints( rd->cone_constraints,
+ rd->cone_constraints_count );
+ }
rb_solve_position_constraints( rd->position_constraints,
rd->position_constraints_count );
}
+ rb_correct_position_constraints( rd->position_constraints,
+ rd->position_constraints_count,
+ k_ragdoll_correction * 0.5f );
+ rb_correct_swingtwist_constraints( rd->cone_constraints,
+ rd->cone_constraints_count,
+ k_ragdoll_correction * 0.25f );
+
for( int i=0; i<rd->part_count; i++ ){
- rb_iter( &rd->parts[i].obj.rb );
+ rb_iter( &rd->parts[i].rb );
v3f w;
- v3_copy( rd->parts[i].obj.rb.w, w );
+ v3_copy( rd->parts[i].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 );
+ v3_muladds( rd->parts[i].rb.w, w, -k_ragdoll_angular_drag,
+ rd->parts[i].rb.w );
}
}
for( int i=0; i<rd->part_count; i++ )
- rb_update_transform( &rd->parts[i].obj.rb );
-
- 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,
- k_ragdoll_correction * 0.5f );
- }
+ rb_update_matrices( &rd->parts[i].rb );
}
rb_ct *stress = NULL;
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 );
v3f torque;
v3_muls( axis, F, torque );
- v3_muladds( st->rbb->w, torque, k_rb_delta, st->rbb->w );
+ v3_muladds( st->rbb->w, torque, vg.time_fixed_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 );
+ v3_muladds( st->rbb->v, vcb, vg.time_fixed_delta, st->rbb->v );
#endif
}
}
audio_unlock();
}
}
-
-#endif /* PLAYER_RAGDOLL_C */