2 * Resources: Box2D - Erin Catto
9 static void rb_tangent_basis( v3f n
, v3f tx
, v3f ty
);
10 static bh_system bh_system_rigidbodies
;
16 #define k_rb_rate 60.0f
17 #define k_rb_delta (1.0f/k_rb_rate)
19 typedef struct rigidbody rigidbody
;
20 typedef struct contact rb_ct
;
51 v3f right
, up
, forward
;
58 v3f delta
; /* where is the origin of this in relation to a parent body */
59 m4x3f to_world
, to_local
;
62 static rigidbody rb_static_null
=
65 .q
={0.0f
,0.0f
,0.0f
,1.0f
},
72 static void rb_debug( rigidbody
*rb
, u32 colour
);
79 float mass_total
, p
, bias
, norm_impulse
, tangent_impulse
[2];
81 rb_contact_buffer
[256];
82 static int rb_contact_count
= 0;
84 static void rb_update_transform( rigidbody
*rb
)
87 q_m3x3( rb
->q
, rb
->to_world
);
88 v3_copy( rb
->co
, rb
->to_world
[3] );
90 m4x3_invert_affine( rb
->to_world
, rb
->to_local
);
92 box_copy( rb
->bbx
, rb
->bbx_world
);
93 m4x3_transform_aabb( rb
->to_world
, rb
->bbx_world
);
95 m3x3_mulv( rb
->to_world
, (v3f
){1.0f
,0.0f
, 0.0f
}, rb
->right
);
96 m3x3_mulv( rb
->to_world
, (v3f
){0.0f
,1.0f
, 0.0f
}, rb
->up
);
97 m3x3_mulv( rb
->to_world
, (v3f
){0.0f
,0.0f
,-1.0f
}, rb
->forward
);
100 static float sphere_volume( float radius
)
102 float r3
= radius
*radius
*radius
;
103 return (4.0f
/3.0f
) * VG_PIf
* r3
;
106 static void rb_init( rigidbody
*rb
)
110 if( rb
->type
== k_rb_shape_box
)
113 v3_sub( rb
->bbx
[1], rb
->bbx
[0], dims
);
114 volume
= dims
[0]*dims
[1]*dims
[2];
116 else if( rb
->type
== k_rb_shape_sphere
)
118 volume
= sphere_volume( rb
->inf
.sphere
.radius
);
119 v3_fill( rb
->bbx
[0], -rb
->inf
.sphere
.radius
);
120 v3_fill( rb
->bbx
[1], rb
->inf
.sphere
.radius
);
122 else if( rb
->type
== k_rb_shape_capsule
)
124 float r
= rb
->inf
.capsule
.radius
,
125 h
= rb
->inf
.capsule
.height
;
126 volume
= sphere_volume( r
) + VG_PIf
* r
*r
* (h
- r
*2.0f
);
128 v3_fill( rb
->bbx
[0], -rb
->inf
.sphere
.radius
);
129 v3_fill( rb
->bbx
[1], rb
->inf
.sphere
.radius
);
140 rb
->inv_mass
= 1.0f
/(8.0f
*volume
);
146 rb_update_transform( rb
);
149 static void rb_iter( rigidbody
*rb
)
151 v3f gravity
= { 0.0f
, -9.6f
, 0.0f
};
152 v3_muladds( rb
->v
, gravity
, k_rb_delta
, rb
->v
);
154 /* intergrate velocity */
155 v3_muladds( rb
->co
, rb
->v
, k_rb_delta
, rb
->co
);
156 v3_lerp( rb
->w
, (v3f
){0.0f
,0.0f
,0.0f
}, 0.0025f
, rb
->w
);
158 /* inegrate inertia */
159 if( v3_length2( rb
->w
) > 0.0f
)
163 v3_copy( rb
->w
, axis
);
165 float mag
= v3_length( axis
);
166 v3_divs( axis
, mag
, axis
);
167 q_axis_angle( rotation
, axis
, mag
*k_rb_delta
);
168 q_mul( rotation
, rb
->q
, rb
->q
);
172 static void rb_torque( rigidbody
*rb
, v3f axis
, float mag
)
174 v3_muladds( rb
->w
, axis
, mag
*k_rb_delta
, rb
->w
);
177 static void rb_tangent_basis( v3f n
, v3f tx
, v3f ty
)
179 /* Compute tangent basis (box2d) */
180 if( fabsf( n
[0] ) >= 0.57735027f
)
194 v3_cross( n
, tx
, ty
);
197 static void rb_solver_reset(void);
198 static void rb_build_manifold_terrain( rigidbody
*rb
);
199 static void rb_build_manifold_terrain_sphere( rigidbody
*rb
);
200 static void rb_solve_contacts(void);
203 * These closest point tests were learned from Real-Time Collision Detection by
206 static float closest_segment_segment( v3f p1
, v3f q1
, v3f p2
, v3f q2
,
207 float *s
, float *t
, v3f c1
, v3f c2
)
210 v3_sub( q1
, p1
, d1
);
211 v3_sub( q2
, p2
, d2
);
214 float a
= v3_length2( d1
),
215 e
= v3_length2( d2
),
218 const float kEpsilon
= 0.0001f
;
220 if( a
<= kEpsilon
&& e
<= kEpsilon
)
228 v3_sub( c1
, c2
, v0
);
230 return v3_length2( v0
);
236 *t
= vg_clampf( f
/ e
, 0.0f
, 1.0f
);
240 float c
= v3_dot( d1
, r
);
244 *s
= vg_clampf( -c
/ a
, 0.0f
, 1.0f
);
248 float b
= v3_dot(d1
,d2
),
253 *s
= vg_clampf((b
*f
- c
*e
)/d
, 0.0f
, 1.0f
);
265 *s
= vg_clampf( -c
/ a
, 0.0f
, 1.0f
);
270 *s
= vg_clampf((b
-c
)/a
,0.0f
,1.0f
);
275 v3_muladds( p1
, d1
, *s
, c1
);
276 v3_muladds( p2
, d2
, *t
, c2
);
279 v3_sub( c1
, c2
, v0
);
280 return v3_length2( v0
);
283 static void closest_point_aabb( v3f p
, boxf box
, v3f dest
)
285 v3_maxv( p
, box
[0], dest
);
286 v3_minv( dest
, box
[1], dest
);
289 static void closest_point_obb( v3f p
, rigidbody
*rb
, v3f dest
)
292 m4x3_mulv( rb
->to_local
, p
, local
);
293 closest_point_aabb( local
, rb
->bbx
, local
);
294 m4x3_mulv( rb
->to_world
, local
, dest
);
297 static void closest_point_segment( v3f a
, v3f b
, v3f point
, v3f dest
)
301 v3_sub( point
, a
, v1
);
303 float t
= v3_dot( v1
, v0
) / v3_length2(v0
);
304 v3_muladds( a
, v0
, vg_clampf(t
,0.0f
,1.0f
), dest
);
307 static void closest_on_triangle( v3f p
, v3f tri
[3], v3f dest
)
312 /* Region outside A */
313 v3_sub( tri
[1], tri
[0], ab
);
314 v3_sub( tri
[2], tri
[0], ac
);
315 v3_sub( p
, tri
[0], ap
);
319 if( d1
<= 0.0f
&& d2
<= 0.0f
)
321 v3_copy( tri
[0], dest
);
322 v3_copy( (v3f
){INFINITY
,INFINITY
,INFINITY
}, dest
);
326 /* Region outside B */
330 v3_sub( p
, tri
[1], bp
);
331 d3
= v3_dot( ab
, bp
);
332 d4
= v3_dot( ac
, bp
);
334 if( d3
>= 0.0f
&& d4
<= d3
)
336 v3_copy( tri
[1], dest
);
337 v3_copy( (v3f
){INFINITY
,INFINITY
,INFINITY
}, dest
);
341 /* Edge region of AB */
342 float vc
= d1
*d4
- d3
*d2
;
343 if( vc
<= 0.0f
&& d1
>= 0.0f
&& d3
<= 0.0f
)
345 float v
= d1
/ (d1
-d3
);
346 v3_muladds( tri
[0], ab
, v
, dest
);
347 v3_copy( (v3f
){INFINITY
,INFINITY
,INFINITY
}, dest
);
351 /* Region outside C */
354 v3_sub( p
, tri
[2], cp
);
358 if( d6
>= 0.0f
&& d5
<= d6
)
360 v3_copy( tri
[2], dest
);
361 v3_copy( (v3f
){INFINITY
,INFINITY
,INFINITY
}, dest
);
366 float vb
= d5
*d2
- d1
*d6
;
367 if( vb
<= 0.0f
&& d2
>= 0.0f
&& d6
<= 0.0f
)
369 float w
= d2
/ (d2
-d6
);
370 v3_muladds( tri
[0], ac
, w
, dest
);
371 v3_copy( (v3f
){INFINITY
,INFINITY
,INFINITY
}, dest
);
376 float va
= d3
*d6
- d5
*d4
;
377 if( va
<= 0.0f
&& (d4
-d3
) >= 0.0f
&& (d5
-d6
) >= 0.0f
)
379 float w
= (d4
-d3
) / ((d4
-d3
) + (d5
-d6
));
381 v3_sub( tri
[2], tri
[1], bc
);
382 v3_muladds( tri
[1], bc
, w
, dest
);
383 v3_copy( (v3f
){INFINITY
,INFINITY
,INFINITY
}, dest
);
387 /* P inside region, Q via barycentric coordinates uvw */
388 float d
= 1.0f
/(va
+vb
+vc
),
392 v3_muladds( tri
[0], ab
, v
, dest
);
393 v3_muladds( dest
, ac
, w
, dest
);
399 * These do not automatically allocate contacts, an appropriately sized
400 * buffer must be supplied. The function returns the size of the manifold
401 * which was generated.
403 * The values set on the contacts are: n, co, p, rba, rbb
406 static void rb_debug_contact( rb_ct
*ct
)
409 v3_muladds( ct
->co
, ct
->n
, 0.2f
, p1
);
410 vg_line_pt3( ct
->co
, 0.1f
, 0xff0000ff );
411 vg_line( ct
->co
, p1
, 0xffffffff );
414 static int rb_sphere_vs_box( rigidbody
*rba
, rigidbody
*rbb
, rb_ct
*buf
)
418 closest_point_obb( rba
->co
, rbb
, co
);
419 v3_sub( rba
->co
, co
, delta
);
421 float d2
= v3_length2(delta
),
422 r
= rba
->inf
.sphere
.radius
;
429 v3_sub( rbb
->co
, rba
->co
, delta
);
430 d2
= v3_length2(delta
);
436 v3_muls( delta
, 1.0f
/d
, ct
->n
);
437 v3_copy( co
, ct
->co
);
447 static int rb_sphere_vs_sphere( rigidbody
*rba
, rigidbody
*rbb
, rb_ct
*buf
)
450 v3_sub( rba
->co
, rbb
->co
, delta
);
452 float d2
= v3_length2(delta
),
453 r
= rba
->inf
.sphere
.radius
+ rbb
->inf
.sphere
.radius
;
460 v3_muls( delta
, -1.0f
/d
, ct
->n
);
463 v3_muladds( rba
->co
, ct
->n
, rba
->inf
.sphere
.radius
, p0
);
464 v3_muladds( rbb
->co
, ct
->n
,-rbb
->inf
.sphere
.radius
, p1
);
465 v3_add( p0
, p1
, ct
->co
);
466 v3_muls( ct
->co
, 0.5f
, ct
->co
);
476 static int rb_box_vs_sphere( rigidbody
*rba
, rigidbody
*rbb
, rb_ct
*buf
)
478 return rb_sphere_vs_box( rbb
, rba
, buf
);
481 static int rb_box_vs_box( rigidbody
*rba
, rigidbody
*rbb
, rb_ct
*buf
)
483 /* TODO: Generating a stable quad manifold, lots of clipping */
488 * This function does not accept triangle as a dynamic object, it is assumed
489 * to always be static.
491 * The triangle is also assumed to be one sided for better detection
493 static int rb_sphere_vs_triangle( rigidbody
*rba
, v3f tri
[3], rb_ct
*buf
)
497 closest_on_triangle( rba
->co
, tri
, co
);
498 v3_sub( rba
->co
, co
, delta
);
500 float d2
= v3_length2( delta
),
501 r
= rba
->inf
.sphere
.radius
;
506 v3_sub( tri
[1], tri
[0], ab
);
507 v3_sub( tri
[2], tri
[0], ac
);
508 v3_cross( ac
, ab
, tn
);
510 if( v3_dot( delta
, tn
) > 0.0f
)
511 v3_muls( delta
, -1.0f
, delta
);
516 v3_muls( delta
, 1.0f
/d
, ct
->n
);
517 v3_copy( co
, ct
->co
);
520 ct
->rbb
= &rb_static_null
;
533 static int sphere_vs_triangle( v3f c
, float r
, v3f tri
[3],
534 v3f co
, v3f norm
, float *p
)
537 closest_on_triangle( c
, tri
, co
);
539 v3_sub( c
, co
, delta
);
542 float d
= v3_length2( delta
);
546 v3_sub( tri
[1], tri
[0], ab
);
547 v3_sub( tri
[2], tri
[0], ac
);
548 v3_cross( ac
, ab
, tn
);
550 if( v3_dot( delta
, tn
) > 0.0f
)
551 v3_muls( delta
, -1.0f
, delta
);
553 vg_line_pt3( co
, 0.05f
, 0xff00ff00 );
556 v3_muls( delta
, 1.0f
/d
, norm
);
567 static void rb_solver_reset(void)
569 rb_contact_count
= 0;
572 static rb_ct
*rb_global_ct(void)
574 return rb_contact_buffer
+ rb_contact_count
;
577 static struct contact
*rb_start_contact(void)
579 if( rb_contact_count
== vg_list_size(rb_contact_buffer
) )
581 vg_error( "rigidbody: too many contacts generated (%u)\n",
586 return &rb_contact_buffer
[ rb_contact_count
];
589 static void rb_commit_contact( struct contact
*ct
, float p
)
591 ct
->bias
= -0.2f
*k_rb_rate
*vg_minf(0.0f
,-p
+0.04f
);
592 rb_tangent_basis( ct
->n
, ct
->t
[0], ct
->t
[1] );
594 ct
->norm_impulse
= 0.0f
;
595 ct
->tangent_impulse
[0] = 0.0f
;
596 ct
->tangent_impulse
[1] = 0.0f
;
601 static void rb_build_manifold_terrain_sphere( rigidbody
*rb
)
605 int len
= bh_select( &world
.geo
.bhtris
, rb
->bbx_world
, geo
, 256 );
607 for( int i
=0; i
<len
; i
++ )
609 u32
*ptri
= &world
.geo
.indices
[ geo
[i
]*3 ];
611 for( int j
=0; j
<3; j
++ )
612 v3_copy( world
.geo
.verts
[ptri
[j
]].co
, tri
[j
] );
614 vg_line(tri
[0],tri
[1],0xff00ff00 );
615 vg_line(tri
[1],tri
[2],0xff00ff00 );
616 vg_line(tri
[2],tri
[0],0xff00ff00 );
621 for( int j
=0; j
<2; j
++ )
623 if( sphere_vs_triangle( rb
->co
, rb
->inf
.sphere
.radius
, tri
,co
,norm
,&p
))
625 struct contact
*ct
= rb_start_contact();
631 v3_muladds( rb
->co
, norm
, p
, p1
);
632 vg_line( rb
->co
, p1
, 0xffffffff );
635 v3_copy( co
, ct
->co
);
636 v3_copy( norm
, ct
->n
);
637 rb_commit_contact( ct
, p
);
645 static void rb_build_manifold_terrain( rigidbody
*rb
)
649 float *p000
= pts
[0], *p001
= pts
[1], *p010
= pts
[2], *p011
= pts
[3],
650 *p100
= pts
[4], *p101
= pts
[5], *p110
= pts
[6], *p111
= pts
[7];
652 p000
[0]=box
[0][0];p000
[1]=box
[0][1];p000
[2]=box
[0][2];
653 p001
[0]=box
[0][0];p001
[1]=box
[0][1];p001
[2]=box
[1][2];
654 p010
[0]=box
[0][0];p010
[1]=box
[1][1];p010
[2]=box
[0][2];
655 p011
[0]=box
[0][0];p011
[1]=box
[1][1];p011
[2]=box
[1][2];
657 p100
[0]=box
[1][0];p100
[1]=box
[0][1];p100
[2]=box
[0][2];
658 p101
[0]=box
[1][0];p101
[1]=box
[0][1];p101
[2]=box
[1][2];
659 p110
[0]=box
[1][0];p110
[1]=box
[1][1];p110
[2]=box
[0][2];
660 p111
[0]=box
[1][0];p111
[1]=box
[1][1];p111
[2]=box
[1][2];
662 m4x3_mulv( rb
->to_world
, p000
, p000
);
663 m4x3_mulv( rb
->to_world
, p001
, p001
);
664 m4x3_mulv( rb
->to_world
, p010
, p010
);
665 m4x3_mulv( rb
->to_world
, p011
, p011
);
666 m4x3_mulv( rb
->to_world
, p100
, p100
);
667 m4x3_mulv( rb
->to_world
, p101
, p101
);
668 m4x3_mulv( rb
->to_world
, p110
, p110
);
669 m4x3_mulv( rb
->to_world
, p111
, p111
);
673 for( int i
=0; i
<8; i
++ )
675 float *point
= pts
[i
];
676 struct contact
*ct
= rb_start_contact();
684 v3_copy( point
, surface
);
689 if( !ray_world( surface
, (v3f
){0.0f
,-1.0f
,0.0f
}, &hit
))
692 v3_copy( hit
.pos
, surface
);
694 float p
= vg_minf( surface
[1] - point
[1], 1.0f
);
698 v3_copy( hit
.normal
, ct
->n
);
699 v3_add( point
, surface
, ct
->co
);
700 v3_muls( ct
->co
, 0.5f
, ct
->co
);
702 rb_commit_contact( ct
, p
);
711 * Initializing things like tangent vectors
713 static void rb_presolve_contacts(void)
715 for( int i
=0; i
<rb_contact_count
; i
++ )
717 rb_ct
*ct
= &rb_contact_buffer
[i
];
719 ct
->bias
= -0.2f
* k_rb_rate
* vg_minf(0.0f
,-ct
->p
+0.04f
);
720 rb_tangent_basis( ct
->n
, ct
->t
[0], ct
->t
[1] );
722 ct
->norm_impulse
= 0.0f
;
723 ct
->tangent_impulse
[0] = 0.0f
;
724 ct
->tangent_impulse
[1] = 0.0f
;
725 ct
->mass_total
= 1.0f
/(ct
->rba
->inv_mass
+ ct
->rbb
->inv_mass
);
727 rb_debug_contact( ct
);
732 * Creates relative contact velocity vector, and offsets between each body */
733 static void rb_rcv( rb_ct
*ct
, v3f rv
, v3f da
, v3f db
)
735 rigidbody
*rba
= ct
->rba
,
738 v3_sub( rba
->co
, ct
->co
, da
);
739 v3_sub( rbb
->co
, ct
->co
, db
);
742 v3_cross( rba
->w
, da
, rva
);
743 v3_add( rba
->v
, rva
, rva
);
745 v3_cross( rbb
->w
, db
, rvb
);
746 v3_add( rbb
->v
, rvb
, rvb
);
747 v3_add( rva
, rvb
, rv
);
750 static void rb_standard_impulse( rb_ct
*ct
, v3f da
, v3f db
, v3f impulse
)
752 rigidbody
*rba
= ct
->rba
,
756 v3_muladds( rba
->v
, impulse
, ct
->mass_total
* rba
->inv_mass
, rba
->v
);
757 v3_muladds( rbb
->v
, impulse
, ct
->mass_total
* rbb
->inv_mass
, rbb
->v
);
759 /* Angular velocity */
761 v3_cross( da
, impulse
, wa
);
762 v3_cross( db
, impulse
, wb
);
763 v3_muladds( rba
->w
, wa
, ct
->mass_total
* rba
->inv_mass
, rba
->w
);
764 v3_muladds( rbb
->w
, wb
, ct
->mass_total
* rbb
->inv_mass
, rbb
->w
);
767 static void rb_solve_contacts(void)
769 float k_friction
= 0.1f
;
771 /* TODO: second object
772 * Static objects route to static element */
774 /* Friction Impulse */
775 for( int i
=0; i
<rb_contact_count
; i
++ )
777 struct contact
*ct
= &rb_contact_buffer
[i
];
778 rigidbody
*rb
= ct
->rba
;
781 rb_rcv( ct
, rv
, da
, db
);
783 for( int j
=0; j
<2; j
++ )
785 float f
= k_friction
* ct
->norm_impulse
,
786 vt
= -v3_dot( rv
, ct
->t
[j
] );
788 float temp
= ct
->tangent_impulse
[j
];
789 ct
->tangent_impulse
[j
] = vg_clampf( temp
+vt
, -f
, f
);
790 vt
= ct
->tangent_impulse
[j
] - temp
;
793 v3_muls( ct
->t
[j
], vt
, impulse
);
794 rb_standard_impulse( ct
, da
, db
, impulse
);
799 for( int i
=0; i
<rb_contact_count
; i
++ )
801 struct contact
*ct
= &rb_contact_buffer
[i
];
802 rigidbody
*rba
= ct
->rba
,
806 rb_rcv( ct
, rv
, da
, db
);
808 float vn
= -v3_dot( rv
, ct
->n
);
811 float temp
= ct
->norm_impulse
;
812 ct
->norm_impulse
= vg_maxf( temp
+ vn
, 0.0f
);
813 vn
= ct
->norm_impulse
- temp
;
816 v3_muls( ct
->n
, vn
, impulse
);
817 rb_standard_impulse( ct
, da
, db
, impulse
);
821 struct rb_angle_limit
823 rigidbody
*rba
, *rbb
;
828 static int rb_angle_limit_force( rigidbody
*rba
, v3f va
,
829 rigidbody
*rbb
, v3f vb
,
833 m3x3_mulv( rba
->to_world
, va
, wva
);
834 m3x3_mulv( rbb
->to_world
, vb
, wvb
);
836 float dt
= v3_dot(wva
,wvb
)*0.999f
,
841 float correction
= max
-ang
;
844 v3_cross( wva
, wvb
, axis
);
847 q_axis_angle( rotation
, axis
, -correction
*0.25f
);
848 q_mul( rotation
, rba
->q
, rba
->q
);
850 q_axis_angle( rotation
, axis
, correction
*0.25f
);
851 q_mul( rotation
, rbb
->q
, rbb
->q
);
859 static void rb_constraint_angle_limit( struct rb_angle_limit
*limit
)
865 static void rb_constraint_angle( rigidbody
*rba
, v3f va
,
866 rigidbody
*rbb
, v3f vb
,
867 float max
, float spring
)
870 m3x3_mulv( rba
->to_world
, va
, wva
);
871 m3x3_mulv( rbb
->to_world
, vb
, wvb
);
873 float dt
= v3_dot(wva
,wvb
)*0.999f
,
877 v3_cross( wva
, wvb
, axis
);
878 v3_muladds( rba
->w
, axis
, ang
*spring
*0.5f
, rba
->w
);
879 v3_muladds( rbb
->w
, axis
, -ang
*spring
*0.5f
, rbb
->w
);
883 /* TODO: convert max into the dot product value so we dont have to always
884 * evaluate acosf, only if its greater than the angle specified */
888 float correction
= max
-ang
;
891 q_axis_angle( rotation
, axis
, -correction
*0.125f
);
892 q_mul( rotation
, rba
->q
, rba
->q
);
894 q_axis_angle( rotation
, axis
, correction
*0.125f
);
895 q_mul( rotation
, rbb
->q
, rbb
->q
);
899 static void rb_relative_velocity( rigidbody
*ra
, v3f lca
,
900 rigidbody
*rb
, v3f lcb
, v3f rcv
)
903 m3x3_mulv( ra
->to_world
, lca
, wca
);
904 m3x3_mulv( rb
->to_world
, lcb
, wcb
);
906 v3_sub( ra
->v
, rb
->v
, rcv
);
909 v3_cross( ra
->w
, wca
, rcv_Ra
);
910 v3_cross( rb
->w
, wcb
, rcv_Rb
);
911 v3_add( rcv_Ra
, rcv
, rcv
);
912 v3_sub( rcv
, rcv_Rb
, rcv
);
915 static void rb_constraint_position( rigidbody
*ra
, v3f lca
,
916 rigidbody
*rb
, v3f lcb
)
918 /* C = (COa + Ra*LCa) - (COb + Rb*LCb) = 0 */
920 m3x3_mulv( ra
->to_world
, lca
, wca
);
921 m3x3_mulv( rb
->to_world
, lcb
, wcb
);
924 v3_add( wcb
, rb
->co
, delta
);
925 v3_sub( delta
, wca
, delta
);
926 v3_sub( delta
, ra
->co
, delta
);
928 v3_muladds( ra
->co
, delta
, 0.5f
, ra
->co
);
929 v3_muladds( rb
->co
, delta
, -0.5f
, rb
->co
);
932 v3_sub( ra
->v
, rb
->v
, rcv
);
935 v3_cross( ra
->w
, wca
, rcv_Ra
);
936 v3_cross( rb
->w
, wcb
, rcv_Rb
);
937 v3_add( rcv_Ra
, rcv
, rcv
);
938 v3_sub( rcv
, rcv_Rb
, rcv
);
940 float nm
= 0.5f
/(rb
->inv_mass
+ ra
->inv_mass
);
942 float mass_a
= 1.0f
/ra
->inv_mass
,
943 mass_b
= 1.0f
/rb
->inv_mass
,
944 total_mass
= mass_a
+mass_b
;
947 v3_muls( rcv
, 1.0f
, impulse
);
948 v3_muladds( rb
->v
, impulse
, mass_b
/total_mass
, rb
->v
);
949 v3_cross( wcb
, impulse
, impulse
);
950 v3_add( impulse
, rb
->w
, rb
->w
);
952 v3_muls( rcv
, -1.0f
, impulse
);
953 v3_muladds( ra
->v
, impulse
, mass_a
/total_mass
, ra
->v
);
954 v3_cross( wca
, impulse
, impulse
);
955 v3_add( impulse
, ra
->w
, ra
->w
);
959 * this could be used for spring joints
960 * its not good for position constraint
963 v3_muls( delta
, 0.5f
*spring
, impulse
);
965 v3_add( impulse
, ra
->v
, ra
->v
);
966 v3_cross( wca
, impulse
, impulse
);
967 v3_add( impulse
, ra
->w
, ra
->w
);
969 v3_muls( delta
, -0.5f
*spring
, impulse
);
971 v3_add( impulse
, rb
->v
, rb
->v
);
972 v3_cross( wcb
, impulse
, impulse
);
973 v3_add( impulse
, rb
->w
, rb
->w
);
977 static void debug_sphere( m4x3f m
, float radius
, u32 colour
)
979 v3f ly
= { 0.0f
, 0.0f
, radius
},
980 lx
= { 0.0f
, radius
, 0.0f
},
981 lz
= { 0.0f
, 0.0f
, radius
};
983 for( int i
=0; i
<16; i
++ )
985 float t
= ((float)(i
+1) * (1.0f
/16.0f
)) * VG_PIf
* 2.0f
,
989 v3f py
= { s
*radius
, 0.0f
, c
*radius
},
990 px
= { s
*radius
, c
*radius
, 0.0f
},
991 pz
= { 0.0f
, s
*radius
, c
*radius
};
993 v3f p0
, p1
, p2
, p3
, p4
, p5
;
994 m4x3_mulv( m
, py
, p0
);
995 m4x3_mulv( m
, ly
, p1
);
996 m4x3_mulv( m
, px
, p2
);
997 m4x3_mulv( m
, lx
, p3
);
998 m4x3_mulv( m
, pz
, p4
);
999 m4x3_mulv( m
, lz
, p5
);
1001 vg_line( p0
, p1
, colour
== 0x00? 0xff00ff00: colour
);
1002 vg_line( p2
, p3
, colour
== 0x00? 0xff0000ff: colour
);
1003 vg_line( p4
, p5
, colour
== 0x00? 0xffff0000: colour
);
1011 static void rb_debug( rigidbody
*rb
, u32 colour
)
1013 if( rb
->type
== k_rb_shape_box
)
1016 vg_line_boxf_transformed( rb
->to_world
, rb
->bbx
, colour
);
1018 else if( rb
->type
== k_rb_shape_sphere
)
1020 debug_sphere( rb
->to_world
, rb
->inf
.sphere
.radius
, colour
);
1025 * out penetration distance, normal
1027 static int rb_point_in_body( rigidbody
*rb
, v3f pos
, float *pen
, v3f normal
)
1030 m4x3_mulv( rb
->to_local
, pos
, local
);
1032 if( local
[0] > rb
->bbx
[0][0] && local
[0] < rb
->bbx
[1][0] &&
1033 local
[1] > rb
->bbx
[0][1] && local
[1] < rb
->bbx
[1][1] &&
1034 local
[2] > rb
->bbx
[0][2] && local
[2] < rb
->bbx
[1][2] )
1036 v3f area
, com
, comrel
;
1037 v3_add( rb
->bbx
[0], rb
->bbx
[1], com
);
1038 v3_muls( com
, 0.5f
, com
);
1040 v3_sub( rb
->bbx
[1], rb
->bbx
[0], area
);
1041 v3_sub( local
, com
, comrel
);
1042 v3_div( comrel
, area
, comrel
);
1045 float max_mag
= fabsf(comrel
[0]);
1047 if( fabsf(comrel
[1]) > max_mag
)
1050 max_mag
= fabsf(comrel
[1]);
1052 if( fabsf(comrel
[2]) > max_mag
)
1055 max_mag
= fabsf(comrel
[2]);
1059 normal
[axis
] = vg_signf(comrel
[axis
]);
1061 if( normal
[axis
] < 0.0f
)
1062 *pen
= local
[axis
] - rb
->bbx
[0][axis
];
1064 *pen
= rb
->bbx
[1][axis
] - local
[axis
];
1066 m3x3_mulv( rb
->to_world
, normal
, normal
);
1074 static void rb_build_manifold_rb_static( rigidbody
*ra
, rigidbody
*rb_static
)
1079 v3_copy( ra
->bbx
[0], a
);
1080 v3_copy( ra
->bbx
[1], b
);
1082 m4x3_mulv( ra
->to_world
, (v3f
){ a
[0], a
[1], a
[2] }, verts
[0] );
1083 m4x3_mulv( ra
->to_world
, (v3f
){ a
[0], b
[1], a
[2] }, verts
[1] );
1084 m4x3_mulv( ra
->to_world
, (v3f
){ b
[0], b
[1], a
[2] }, verts
[2] );
1085 m4x3_mulv( ra
->to_world
, (v3f
){ b
[0], a
[1], a
[2] }, verts
[3] );
1086 m4x3_mulv( ra
->to_world
, (v3f
){ a
[0], a
[1], b
[2] }, verts
[4] );
1087 m4x3_mulv( ra
->to_world
, (v3f
){ a
[0], b
[1], b
[2] }, verts
[5] );
1088 m4x3_mulv( ra
->to_world
, (v3f
){ b
[0], b
[1], b
[2] }, verts
[6] );
1089 m4x3_mulv( ra
->to_world
, (v3f
){ b
[0], a
[1], b
[2] }, verts
[7] );
1091 vg_line_boxf_transformed( rb_static
->to_world
, rb_static
->bbx
, 0xff0000ff );
1095 for( int i
=0; i
<8; i
++ )
1097 if( ra
->manifold_count
== vg_list_size(ra
->manifold
) )
1100 struct contact
*ct
= &ra
->manifold
[ ra
->manifold_count
];
1105 if( rb_point_in_body( rb_static
, verts
[i
], &p
, normal
))
1107 v3_copy( normal
, ct
->n
);
1108 v3_muladds( verts
[i
], ct
->n
, p
*0.5f
, ct
->co
);
1109 v3_sub( ct
->co
, ra
->co
, ct
->delta
);
1111 vg_line_pt3( ct
->co
, 0.0125f
, 0xffff00ff );
1113 ct
->bias
= -0.2f
* (1.0f
/k_rb_delta
) * vg_minf( 0.0f
, -p
+0.04f
);
1114 rb_tangent_basis( ct
->n
, ct
->t
[0], ct
->t
[1] );
1116 ct
->norm_impulse
= 0.0f
;
1117 ct
->tangent_impulse
[0] = 0.0f
;
1118 ct
->tangent_impulse
[1] = 0.0f
;
1120 ra
->manifold_count
++;
1133 static void debug_capsule( m4x3f m
, float height
, float radius
, u32 colour
)
1135 v3f last
= { 0.0f
, 0.0f
, radius
};
1137 m3x3_copy( m
, lower
);
1138 m3x3_copy( m
, upper
);
1139 m4x3_mulv( m
, (v3f
){0.0f
,-height
*0.5f
+radius
,0.0f
}, lower
[3] );
1140 m4x3_mulv( m
, (v3f
){0.0f
, height
*0.5f
-radius
,0.0f
}, upper
[3] );
1142 for( int i
=0; i
<16; i
++ )
1144 float t
= ((float)(i
+1) * (1.0f
/16.0f
)) * VG_PIf
* 2.0f
,
1148 v3f p
= { s
*radius
, 0.0f
, c
*radius
};
1151 m4x3_mulv( lower
, p
, p0
);
1152 m4x3_mulv( lower
, last
, p1
);
1153 vg_line( p0
, p1
, colour
);
1155 m4x3_mulv( upper
, p
, p0
);
1156 m4x3_mulv( upper
, last
, p1
);
1157 vg_line( p0
, p1
, colour
);
1162 for( int i
=0; i
<4; i
++ )
1164 float t
= ((float)(i
) * (1.0f
/4.0f
)) * VG_PIf
* 2.0f
,
1168 v3f p
= { s
*radius
, 0.0f
, c
*radius
};
1171 m4x3_mulv( lower
, p
, p0
);
1172 m4x3_mulv( upper
, p
, p1
);
1173 vg_line( p0
, p1
, colour
);
1175 m4x3_mulv( lower
, (v3f
){0.0f
,-radius
,0.0f
}, p0
);
1176 m4x3_mulv( upper
, (v3f
){0.0f
, radius
,0.0f
}, p1
);
1177 vg_line( p0
, p1
, colour
);
1182 * BVH implementation, this is ONLY for static rigidbodies, its to slow for
1186 static void rb_bh_expand_bound( void *user
, boxf bound
, u32 item_index
)
1188 rigidbody
*rb
= &((rigidbody
*)user
)[ item_index
];
1189 box_concat( bound
, rb
->bbx_world
);
1192 static float rb_bh_centroid( void *user
, u32 item_index
, int axis
)
1194 rigidbody
*rb
= &((rigidbody
*)user
)[ item_index
];
1195 return (rb
->bbx_world
[axis
][0] + rb
->bbx_world
[1][axis
]) * 0.5f
;
1198 static void rb_bh_swap( void *user
, u32 ia
, u32 ib
)
1200 rigidbody temp
, *rba
, *rbb
;
1201 rba
= &((rigidbody
*)user
)[ ia
];
1202 rbb
= &((rigidbody
*)user
)[ ib
];
1209 static void rb_bh_debug( void *user
, u32 item_index
)
1211 rigidbody
*rb
= &((rigidbody
*)user
)[ item_index
];
1212 rb_debug( rb
, 0xff00ffff );
1215 static bh_system bh_system_rigidbodies
=
1217 .expand_bound
= rb_bh_expand_bound
,
1218 .item_centroid
= rb_bh_centroid
,
1219 .item_swap
= rb_bh_swap
,
1220 .item_debug
= rb_bh_debug
,
1224 #endif /* RIGIDBODY_H */