f6b9417a2b90e2fabb62b37d0d2fcc87cf5888fd
4 * Copyright (C) 2021-2024 Mt.ZERO Software - All Rights Reserved
6 * Rigidbody main file, related:
7 * vg_rigidbody_collision.h
8 * vg_rigidbody_constraints.h
11 #include "vg_console.h"
15 * -----------------------------------------------------------------------------
17 * -----------------------------------------------------------------------------
21 //k_rb_rate = (1.0/VG_TIMESTEP_FIXED),
22 //k_rb_delta = (1.0/k_rb_rate),
24 k_damp_linear
= 0.1f
, /* scale velocity 1/(1+x) */
25 k_damp_angular
= 0.1f
, /* scale angular 1/(1+x) */
26 k_penetration_slop
= 0.01f
,
27 k_inertia_scale
= 4.0f
,
28 k_phys_baumgarte
= 0.2f
,
34 k_joint_correction
= 0.01f
,
35 k_joint_impulse
= 1.0f
,
36 k_joint_bias
= 0.08f
; /* positional joints */
38 static void rb_register_cvar(void){
39 VG_VAR_F32( k_limit_bias
, flags
=VG_VAR_CHEAT
);
40 VG_VAR_F32( k_joint_bias
, flags
=VG_VAR_CHEAT
);
41 VG_VAR_F32( k_joint_correction
, flags
=VG_VAR_CHEAT
);
42 VG_VAR_F32( k_joint_impulse
, flags
=VG_VAR_CHEAT
);
48 k_rb_shape_sphere
= 2,
49 k_rb_shape_capsule
= 3,
53 * -----------------------------------------------------------------------------
54 * structure definitions
55 * -----------------------------------------------------------------------------
58 typedef struct rigidbody rigidbody
;
59 typedef struct rb_capsule rb_capsule
;
71 m3x3f iI
, iIw
; /* inertia model and inverse world tensor */
72 m4x3f to_world
, to_local
;
76 * Initialize rigidbody inverse mass and inertia tensor with some common shapes
78 static void rb_setbody_capsule( rigidbody
*rb
, f32 r
, f32 h
,
79 f32 density
, f32 inertia_scale
){
80 f32 vol
= vg_capsule_volume( r
, h
),
83 rb
->inv_mass
= 1.0f
/mass
;
86 vg_capsule_inertia( r
, h
, mass
* inertia_scale
, I
);
87 m3x3_inv( I
, rb
->iI
);
90 static void rb_setbody_box( rigidbody
*rb
, boxf box
,
91 f32 density
, f32 inertia_scale
){
92 f32 vol
= vg_box_volume( box
),
95 rb
->inv_mass
= 1.0f
/mass
;
98 vg_box_inertia( box
, mass
* inertia_scale
, I
);
99 m3x3_inv( I
, rb
->iI
);
102 static void rb_setbody_sphere( rigidbody
*rb
, f32 r
,
103 f32 density
, f32 inertia_scale
){
104 f32 vol
= vg_sphere_volume( r
),
107 rb
->inv_mass
= 1.0f
/mass
;
109 vg_sphere_inertia( r
, mass
* inertia_scale
, I
);
110 m3x3_inv( I
, rb
->iI
);
114 * Update ALL matrices and tensors on rigidbody
116 static void rb_update_matrices( rigidbody
*rb
){
117 //q_normalize( rb->q );
118 q_m3x3( rb
->q
, rb
->to_world
);
119 v3_copy( rb
->co
, rb
->to_world
[3] );
120 m4x3_invert_affine( rb
->to_world
, rb
->to_local
);
123 m3x3_mul( rb
->to_world
, rb
->iI
, rb
->iIw
);
124 m3x3_mul( rb
->iIw
, rb
->to_local
, rb
->iIw
);
128 * Extrapolate rigidbody into a transform based on vg accumulator.
129 * Useful for rendering
131 static void rb_extrapolate( rigidbody
*rb
, v3f co
, v4f q
){
132 float substep
= vg
.time_fixed_extrapolate
;
133 v3_muladds( rb
->co
, rb
->v
, vg
.time_fixed_delta
*substep
, co
);
135 if( v3_length2( rb
->w
) > 0.0f
){
138 v3_copy( rb
->w
, axis
);
140 float mag
= v3_length( axis
);
141 v3_divs( axis
, mag
, axis
);
142 q_axis_angle( rotation
, axis
, mag
*vg
.time_fixed_delta
*substep
);
143 q_mul( rotation
, rb
->q
, q
);
151 static void rb_iter( rigidbody
*rb
){
152 if( !vg_validf( rb
->v
[0] ) ||
153 !vg_validf( rb
->v
[1] ) ||
154 !vg_validf( rb
->v
[2] ) )
156 vg_fatal_error( "NaN velocity" );
159 v3f gravity
= { 0.0f
, -9.8f
, 0.0f
};
160 v3_muladds( rb
->v
, gravity
, vg
.time_fixed_delta
, rb
->v
);
162 /* intergrate velocity */
163 v3_muladds( rb
->co
, rb
->v
, vg
.time_fixed_delta
, rb
->co
);
165 v3_lerp( rb
->w
, (v3f
){0.0f
,0.0f
,0.0f
}, 0.0025f
, rb
->w
);
168 /* inegrate inertia */
169 if( v3_length2( rb
->w
) > 0.0f
){
172 v3_copy( rb
->w
, axis
);
174 float mag
= v3_length( axis
);
175 v3_divs( axis
, mag
, axis
);
176 q_axis_angle( rotation
, axis
, mag
*vg
.time_fixed_delta
);
177 q_mul( rotation
, rb
->q
, rb
->q
);
178 q_normalize( rb
->q
);
183 * based on: https://box2d.org/files/ErinCatto_NumericalMethods_GDC2015.pdf,
186 static void rb_solve_gyroscopic( rigidbody
*rb
, m3x3f I
, f32 h
){
187 /* convert to body coordinates */
189 m3x3_mulv( rb
->to_local
, rb
->w
, w_local
);
191 /* Residual vector */
193 m3x3_mulv( I
, w_local
, v0
);
194 v3_cross( w_local
, v0
, f
);
198 m3x3f iJ
, J
, skew_w_local
, skew_v0
, m0
;
199 m3x3_skew_symetric( skew_w_local
, w_local
);
200 m3x3_mul( skew_w_local
, I
, m0
);
202 m3x3_skew_symetric( skew_v0
, v0
);
203 m3x3_sub( m0
, skew_v0
, J
);
207 /* Single Newton-Raphson update */
210 m3x3_mulv( iJ
, f
, w1
);
211 v3_sub( w_local
, w1
, rb
->w
);
213 m3x3_mulv( rb
->to_world
, rb
->w
, rb
->w
);
217 * Creates relative contact velocity vector
219 static void rb_rcv( rigidbody
*rba
, rigidbody
*rbb
, v3f ra
, v3f rb
, v3f rv
){
221 v3_cross( rba
->w
, ra
, rva
);
222 v3_add( rba
->v
, rva
, rva
);
223 v3_cross( rbb
->w
, rb
, rvb
);
224 v3_add( rbb
->v
, rvb
, rvb
);
226 v3_sub( rva
, rvb
, rv
);
230 * Apply impulse to object
232 static void rb_linear_impulse( rigidbody
*rb
, v3f delta
, v3f impulse
){
234 v3_muladds( rb
->v
, impulse
, rb
->inv_mass
, rb
->v
);
236 /* Angular velocity */
238 v3_cross( delta
, impulse
, wa
);
240 m3x3_mulv( rb
->iIw
, wa
, wa
);
241 v3_add( rb
->w
, wa
, rb
->w
);
248 static void rb_effect_simple_bouyency( rigidbody
*ra
, v4f plane
,
249 float amt
, float drag
){
251 float depth
= v3_dot( plane
, ra
->co
) - plane
[3],
252 lambda
= vg_clampf( -depth
, 0.0f
, 1.0f
) * amt
;
254 v3_muladds( ra
->v
, plane
, lambda
* vg
.time_fixed_delta
, ra
->v
);
257 v3_muls( ra
->v
, 1.0f
-(drag
*vg
.time_fixed_delta
), ra
->v
);
260 /* apply a spring&dampener force to match ra(worldspace) on rigidbody, to
263 static void rb_effect_spring_target_vector( rigidbody
*rba
, v3f ra
, v3f rt
,
264 float spring
, float dampening
,
266 float d
= v3_dot( rt
, ra
);
267 float a
= acosf( vg_clampf( d
, -1.0f
, 1.0f
) );
270 v3_cross( rt
, ra
, axis
);
272 float Fs
= -a
* spring
,
273 Fd
= -v3_dot( rba
->w
, axis
) * dampening
;
275 v3_muladds( rba
->w
, axis
, (Fs
+Fd
) * timestep
, rba
->w
);