assorted crap
[carveJwlIkooP6JGAAIwe30JlM.git] / rigidbody.h
1 /*
2 * Copyright (C) 2021-2022 Mt.ZERO Software, Harry Godden - All Rights Reserved
3 */
4
5 /*
6 * Resources: Box2D - Erin Catto
7 * qu3e - Randy Gaul
8 */
9
10 #include "common.h"
11 #include "bvh.h"
12 #include "scene.h"
13 #include "distq.h"
14
15 VG_STATIC void rb_tangent_basis( v3f n, v3f tx, v3f ty );
16 VG_STATIC bh_system bh_system_rigidbodies;
17
18 #ifndef RIGIDBODY_H
19 #define RIGIDBODY_H
20
21 /*
22 * -----------------------------------------------------------------------------
23 * (K)onstants
24 * -----------------------------------------------------------------------------
25 */
26
27 VG_STATIC const float
28 k_rb_rate = (1.0/VG_TIMESTEP_FIXED),
29 k_rb_delta = (1.0/k_rb_rate),
30 k_friction = 0.6f,
31 k_damp_linear = 0.05f, /* scale velocity 1/(1+x) */
32 k_damp_angular = 0.1f, /* scale angular 1/(1+x) */
33 k_limit_bias = 0.02f,
34 k_joint_bias = 0.08f, /* positional joints */
35 k_joint_correction = 0.01f,
36 k_penetration_slop = 0.01f,
37 k_inertia_scale = 4.0f;
38
39 /*
40 * -----------------------------------------------------------------------------
41 * structure definitions
42 * -----------------------------------------------------------------------------
43 */
44
45 typedef struct rigidbody rigidbody;
46 typedef struct contact rb_ct;
47
48 struct rigidbody
49 {
50 v3f co, v, w;
51 v4f q;
52
53 enum rb_shape
54 {
55 k_rb_shape_box = 0,
56 k_rb_shape_sphere = 1,
57 k_rb_shape_capsule = 2,
58 k_rb_shape_scene = 3
59 }
60 type;
61
62 union
63 {
64 struct rb_sphere
65 {
66 float radius;
67 }
68 sphere;
69
70 struct rb_capsule
71 {
72 float height, radius;
73 }
74 capsule;
75
76 struct rb_scene
77 {
78 bh_tree *bh_scene;
79 }
80 scene;
81 }
82 inf;
83
84 v3f right, up, forward;
85
86 int is_world;
87
88 boxf bbx, bbx_world;
89 float inv_mass;
90
91 /* inertia model and inverse world tensor */
92 v3f I;
93 m3x3f iI, iIw;
94
95 m4x3f to_world, to_local;
96 };
97
98 VG_STATIC struct contact
99 {
100 rigidbody *rba, *rbb;
101 v3f co, n;
102 v3f t[2];
103 float p, bias, norm_impulse, tangent_impulse[2],
104 normal_mass, tangent_mass[2];
105
106 u32 element_id;
107
108 enum contact_type type;
109 }
110 rb_contact_buffer[256];
111 VG_STATIC int rb_contact_count = 0;
112
113 /*
114 * -----------------------------------------------------------------------------
115 * Math Utils
116 * -----------------------------------------------------------------------------
117 */
118
119 VG_STATIC float sphere_volume( float radius )
120 {
121 float r3 = radius*radius*radius;
122 return (4.0f/3.0f) * VG_PIf * r3;
123 }
124
125 VG_STATIC void rb_tangent_basis( v3f n, v3f tx, v3f ty )
126 {
127 /* Compute tangent basis (box2d) */
128 if( fabsf( n[0] ) >= 0.57735027f )
129 {
130 tx[0] = n[1];
131 tx[1] = -n[0];
132 tx[2] = 0.0f;
133 }
134 else
135 {
136 tx[0] = 0.0f;
137 tx[1] = n[2];
138 tx[2] = -n[1];
139 }
140
141 v3_normalize( tx );
142 v3_cross( n, tx, ty );
143 }
144
145 /*
146 * -----------------------------------------------------------------------------
147 * Debugging
148 * -----------------------------------------------------------------------------
149 */
150
151 VG_STATIC void rb_debug_contact( rb_ct *ct )
152 {
153 if( ct->type != k_contact_type_disabled )
154 {
155 v3f p1;
156 v3_muladds( ct->co, ct->n, 0.1f, p1 );
157 vg_line_pt3( ct->co, 0.025f, 0xff0000ff );
158 vg_line( ct->co, p1, 0xffffffff );
159 }
160 }
161
162 VG_STATIC void debug_sphere( m4x3f m, float radius, u32 colour )
163 {
164 v3f ly = { 0.0f, 0.0f, radius },
165 lx = { 0.0f, radius, 0.0f },
166 lz = { 0.0f, 0.0f, radius };
167
168 for( int i=0; i<16; i++ )
169 {
170 float t = ((float)(i+1) * (1.0f/16.0f)) * VG_PIf * 2.0f,
171 s = sinf(t),
172 c = cosf(t);
173
174 v3f py = { s*radius, 0.0f, c*radius },
175 px = { s*radius, c*radius, 0.0f },
176 pz = { 0.0f, s*radius, c*radius };
177
178 v3f p0, p1, p2, p3, p4, p5;
179 m4x3_mulv( m, py, p0 );
180 m4x3_mulv( m, ly, p1 );
181 m4x3_mulv( m, px, p2 );
182 m4x3_mulv( m, lx, p3 );
183 m4x3_mulv( m, pz, p4 );
184 m4x3_mulv( m, lz, p5 );
185
186 vg_line( p0, p1, colour == 0x00? 0xff00ff00: colour );
187 vg_line( p2, p3, colour == 0x00? 0xff0000ff: colour );
188 vg_line( p4, p5, colour == 0x00? 0xffff0000: colour );
189
190 v3_copy( py, ly );
191 v3_copy( px, lx );
192 v3_copy( pz, lz );
193 }
194 }
195
196 VG_STATIC void debug_capsule( m4x3f m, float radius, float h, u32 colour )
197 {
198 v3f ly = { 0.0f, 0.0f, radius },
199 lx = { 0.0f, radius, 0.0f },
200 lz = { 0.0f, 0.0f, radius };
201
202 float s0 = sinf(0.0f)*radius,
203 c0 = cosf(0.0f)*radius;
204
205 v3f p0, p1, up, right, forward;
206 m3x3_mulv( m, (v3f){0.0f,1.0f,0.0f}, up );
207 m3x3_mulv( m, (v3f){1.0f,0.0f,0.0f}, right );
208 m3x3_mulv( m, (v3f){0.0f,0.0f,-1.0f}, forward );
209 v3_muladds( m[3], up, -h*0.5f+radius, p0 );
210 v3_muladds( m[3], up, h*0.5f-radius, p1 );
211
212 v3f a0, a1, b0, b1;
213 v3_muladds( p0, right, radius, a0 );
214 v3_muladds( p1, right, radius, a1 );
215 v3_muladds( p0, forward, radius, b0 );
216 v3_muladds( p1, forward, radius, b1 );
217 vg_line( a0, a1, colour );
218 vg_line( b0, b1, colour );
219
220 v3_muladds( p0, right, -radius, a0 );
221 v3_muladds( p1, right, -radius, a1 );
222 v3_muladds( p0, forward, -radius, b0 );
223 v3_muladds( p1, forward, -radius, b1 );
224 vg_line( a0, a1, colour );
225 vg_line( b0, b1, colour );
226
227 for( int i=0; i<16; i++ )
228 {
229 float t = ((float)(i+1) * (1.0f/16.0f)) * VG_PIf * 2.0f,
230 s1 = sinf(t)*radius,
231 c1 = cosf(t)*radius;
232
233 v3f e0 = { s0, 0.0f, c0 },
234 e1 = { s1, 0.0f, c1 },
235 e2 = { s0, c0, 0.0f },
236 e3 = { s1, c1, 0.0f },
237 e4 = { 0.0f, c0, s0 },
238 e5 = { 0.0f, c1, s1 };
239
240 m3x3_mulv( m, e0, e0 );
241 m3x3_mulv( m, e1, e1 );
242 m3x3_mulv( m, e2, e2 );
243 m3x3_mulv( m, e3, e3 );
244 m3x3_mulv( m, e4, e4 );
245 m3x3_mulv( m, e5, e5 );
246
247 v3_add( p0, e0, a0 );
248 v3_add( p0, e1, a1 );
249 v3_add( p1, e0, b0 );
250 v3_add( p1, e1, b1 );
251
252 vg_line( a0, a1, colour );
253 vg_line( b0, b1, colour );
254
255 if( c0 < 0.0f )
256 {
257 v3_add( p0, e2, a0 );
258 v3_add( p0, e3, a1 );
259 v3_add( p0, e4, b0 );
260 v3_add( p0, e5, b1 );
261 }
262 else
263 {
264 v3_add( p1, e2, a0 );
265 v3_add( p1, e3, a1 );
266 v3_add( p1, e4, b0 );
267 v3_add( p1, e5, b1 );
268 }
269
270 vg_line( a0, a1, colour );
271 vg_line( b0, b1, colour );
272
273 s0 = s1;
274 c0 = c1;
275 }
276 }
277
278 VG_STATIC void rb_debug( rigidbody *rb, u32 colour )
279 {
280 if( rb->type == k_rb_shape_box )
281 {
282 v3f *box = rb->bbx;
283 vg_line_boxf_transformed( rb->to_world, rb->bbx, colour );
284 }
285 else if( rb->type == k_rb_shape_sphere )
286 {
287 debug_sphere( rb->to_world, rb->inf.sphere.radius, colour );
288 }
289 else if( rb->type == k_rb_shape_capsule )
290 {
291 m4x3f m0, m1;
292 float h = rb->inf.capsule.height,
293 r = rb->inf.capsule.radius;
294
295 debug_capsule( rb->to_world, r, h, colour );
296 }
297 else if( rb->type == k_rb_shape_scene )
298 {
299 vg_line_boxf( rb->bbx, colour );
300 }
301 }
302
303 /*
304 * -----------------------------------------------------------------------------
305 * Integration
306 * -----------------------------------------------------------------------------
307 */
308
309 /*
310 * Update world space bounding box based on local one
311 */
312 VG_STATIC void rb_update_bounds( rigidbody *rb )
313 {
314 box_copy( rb->bbx, rb->bbx_world );
315 m4x3_transform_aabb( rb->to_world, rb->bbx_world );
316 }
317
318 /*
319 * Commit transform to rigidbody. Updates matrices
320 */
321 VG_STATIC void rb_update_transform( rigidbody *rb )
322 {
323 q_normalize( rb->q );
324 q_m3x3( rb->q, rb->to_world );
325 v3_copy( rb->co, rb->to_world[3] );
326
327 m4x3_invert_affine( rb->to_world, rb->to_local );
328
329 m3x3_mulv( rb->to_world, (v3f){1.0f,0.0f, 0.0f}, rb->right );
330 m3x3_mulv( rb->to_world, (v3f){0.0f,1.0f, 0.0f}, rb->up );
331 m3x3_mulv( rb->to_world, (v3f){0.0f,0.0f,-1.0f}, rb->forward );
332
333 m3x3_mul( rb->iI, rb->to_local, rb->iIw );
334 m3x3_mul( rb->to_world, rb->iIw, rb->iIw );
335
336 rb_update_bounds( rb );
337 }
338
339 /*
340 * Extrapolate rigidbody into a transform based on vg accumulator.
341 * Useful for rendering
342 */
343 VG_STATIC void rb_extrapolate_transform( rigidbody *rb, m4x3f transform )
344 {
345 float substep = vg_clampf( vg.accumulator / k_rb_delta, 0.0f, 1.0f );
346
347 v3f co;
348 v4f q;
349
350 v3_muladds( rb->co, rb->v, k_rb_delta*substep, co );
351
352 if( v3_length2( rb->w ) > 0.0f )
353 {
354 v4f rotation;
355 v3f axis;
356 v3_copy( rb->w, axis );
357
358 float mag = v3_length( axis );
359 v3_divs( axis, mag, axis );
360 q_axis_angle( rotation, axis, mag*k_rb_delta*substep );
361 q_mul( rotation, rb->q, q );
362 q_normalize( q );
363 }
364 else
365 {
366 v4_copy( rb->q, q );
367 }
368
369 q_m3x3( q, transform );
370 v3_copy( co, transform[3] );
371 }
372
373 /*
374 * Initialize rigidbody and calculate masses, inertia
375 */
376 VG_STATIC void rb_init( rigidbody *rb )
377 {
378 float volume = 1.0f;
379
380 if( rb->type == k_rb_shape_box )
381 {
382 v3f dims;
383 v3_sub( rb->bbx[1], rb->bbx[0], dims );
384 volume = dims[0]*dims[1]*dims[2];
385 }
386 else if( rb->type == k_rb_shape_sphere )
387 {
388 volume = sphere_volume( rb->inf.sphere.radius );
389 v3_fill( rb->bbx[0], -rb->inf.sphere.radius );
390 v3_fill( rb->bbx[1], rb->inf.sphere.radius );
391 }
392 else if( rb->type == k_rb_shape_capsule )
393 {
394 float r = rb->inf.capsule.radius,
395 h = rb->inf.capsule.height;
396 volume = sphere_volume( r ) + VG_PIf * r*r * (h - r*2.0f);
397
398 v3_fill( rb->bbx[0], -rb->inf.sphere.radius );
399 v3_fill( rb->bbx[1], rb->inf.sphere.radius );
400 rb->bbx[0][1] = -h;
401 rb->bbx[1][1] = h;
402 }
403 else if( rb->type == k_rb_shape_scene )
404 {
405 rb->is_world = 1;
406 box_copy( rb->inf.scene.bh_scene->nodes[0].bbx, rb->bbx );
407 }
408
409 if( rb->is_world )
410 {
411 rb->inv_mass = 0.0f;
412 v3_zero( rb->I );
413 m3x3_zero(rb->iI);
414 }
415 else
416 {
417 float mass = 2.0f*volume;
418 rb->inv_mass = 1.0f/mass;
419
420 v3f extent;
421 v3_sub( rb->bbx[1], rb->bbx[0], extent );
422 v3_muls( extent, 0.5f, extent );
423
424 /* local intertia tensor */
425 float scale = k_inertia_scale;
426 float ex2 = scale*extent[0]*extent[0],
427 ey2 = scale*extent[1]*extent[1],
428 ez2 = scale*extent[2]*extent[2];
429
430 rb->I[0] = ((1.0f/12.0f) * mass * (ey2+ez2));
431 rb->I[1] = ((1.0f/12.0f) * mass * (ex2+ez2));
432 rb->I[2] = ((1.0f/12.0f) * mass * (ex2+ey2));
433
434 m3x3_identity( rb->iI );
435 rb->iI[0][0] = rb->I[0];
436 rb->iI[1][1] = rb->I[1];
437 rb->iI[2][2] = rb->I[2];
438 m3x3_inv( rb->iI, rb->iI );
439 }
440
441 v3_zero( rb->v );
442 v3_zero( rb->w );
443
444 rb_update_transform( rb );
445 }
446
447 VG_STATIC void rb_iter( rigidbody *rb )
448 {
449 v3f gravity = { 0.0f, -9.8f, 0.0f };
450 v3_muladds( rb->v, gravity, k_rb_delta, rb->v );
451
452 /* intergrate velocity */
453 v3_muladds( rb->co, rb->v, k_rb_delta, rb->co );
454 v3_lerp( rb->w, (v3f){0.0f,0.0f,0.0f}, 0.0025f, rb->w );
455
456 /* inegrate inertia */
457 if( v3_length2( rb->w ) > 0.0f )
458 {
459 v4f rotation;
460 v3f axis;
461 v3_copy( rb->w, axis );
462
463 float mag = v3_length( axis );
464 v3_divs( axis, mag, axis );
465 q_axis_angle( rotation, axis, mag*k_rb_delta );
466 q_mul( rotation, rb->q, rb->q );
467 }
468
469 /* damping */
470 v3_muls( rb->v, 1.0f/(1.0f+k_rb_delta*k_damp_linear), rb->v );
471 v3_muls( rb->w, 1.0f/(1.0f+k_rb_delta*k_damp_angular), rb->w );
472 }
473
474
475 /*
476 * -----------------------------------------------------------------------------
477 * Boolean shape overlap functions
478 * -----------------------------------------------------------------------------
479 */
480
481 /*
482 * Project AABB, and triangle interval onto axis to check if they overlap
483 */
484 VG_STATIC int rb_box_triangle_interval( v3f extent, v3f axis, v3f tri[3] )
485 {
486 float
487
488 r = extent[0] * fabsf(axis[0]) +
489 extent[1] * fabsf(axis[1]) +
490 extent[2] * fabsf(axis[2]),
491
492 p0 = v3_dot( axis, tri[0] ),
493 p1 = v3_dot( axis, tri[1] ),
494 p2 = v3_dot( axis, tri[2] ),
495
496 e = vg_maxf(-vg_maxf(p0,vg_maxf(p1,p2)), vg_minf(p0,vg_minf(p1,p2)));
497
498 if( e > r ) return 0;
499 else return 1;
500 }
501
502 /*
503 * Seperating axis test box vs triangle
504 */
505 VG_STATIC int rb_box_triangle_sat( rigidbody *rba, v3f tri_src[3] )
506 {
507 v3f tri[3];
508
509 v3f extent, c;
510 v3_sub( rba->bbx[1], rba->bbx[0], extent );
511 v3_muls( extent, 0.5f, extent );
512 v3_add( rba->bbx[0], extent, c );
513
514 for( int i=0; i<3; i++ )
515 {
516 m4x3_mulv( rba->to_local, tri_src[i], tri[i] );
517 v3_sub( tri[i], c, tri[i] );
518 }
519
520 /* u0, u1, u2 */
521 if(!rb_box_triangle_interval( extent, (v3f){1.0f,0.0f,0.0f}, tri )) return 0;
522 if(!rb_box_triangle_interval( extent, (v3f){0.0f,1.0f,0.0f}, tri )) return 0;
523 if(!rb_box_triangle_interval( extent, (v3f){0.0f,0.0f,1.0f}, tri )) return 0;
524
525 v3f v0,v1,v2,n, e0,e1,e2;
526 v3_sub( tri[1], tri[0], v0 );
527 v3_sub( tri[2], tri[0], v1 );
528 v3_sub( tri[2], tri[1], v2 );
529 v3_normalize( v0 );
530 v3_normalize( v1 );
531 v3_normalize( v2 );
532 v3_cross( v0, v1, n );
533 v3_cross( v0, n, e0 );
534 v3_cross( n, v1, e1 );
535 v3_cross( v2, n, e2 );
536
537 /* normal */
538 if(!rb_box_triangle_interval( extent, n, tri )) return 0;
539
540 v3f axis[9];
541 v3_cross( e0, (v3f){1.0f,0.0f,0.0f}, axis[0] );
542 v3_cross( e0, (v3f){0.0f,1.0f,0.0f}, axis[1] );
543 v3_cross( e0, (v3f){0.0f,0.0f,1.0f}, axis[2] );
544 v3_cross( e1, (v3f){1.0f,0.0f,0.0f}, axis[3] );
545 v3_cross( e1, (v3f){0.0f,1.0f,0.0f}, axis[4] );
546 v3_cross( e1, (v3f){0.0f,0.0f,1.0f}, axis[5] );
547 v3_cross( e2, (v3f){1.0f,0.0f,0.0f}, axis[6] );
548 v3_cross( e2, (v3f){0.0f,1.0f,0.0f}, axis[7] );
549 v3_cross( e2, (v3f){0.0f,0.0f,1.0f}, axis[8] );
550
551 for( int i=0; i<9; i++ )
552 if(!rb_box_triangle_interval( extent, axis[i], tri )) return 0;
553
554 return 1;
555 }
556
557 /*
558 * -----------------------------------------------------------------------------
559 * Manifold
560 * -----------------------------------------------------------------------------
561 */
562
563 VG_STATIC int rb_manifold_apply_filtered( rb_ct *man, int len )
564 {
565 int k = 0;
566
567 for( int i=0; i<len; i++ )
568 {
569 rb_ct *ct = &man[i];
570
571 if( ct->type == k_contact_type_disabled )
572 continue;
573
574 man[k ++] = man[i];
575 }
576
577 return k;
578 }
579
580 VG_STATIC void rb_manifold_filter_joint_edges( rb_ct *man, int len, float r )
581 {
582 for( int i=0; i<len-1; i++ )
583 {
584 rb_ct *ci = &man[i];
585 if( ci->type != k_contact_type_edge )
586 continue;
587
588 for( int j=i+1; j<len; j++ )
589 {
590 rb_ct *cj = &man[j];
591 if( cj->type != k_contact_type_edge )
592 continue;
593
594 if( v3_dist2( ci->co, cj->co ) < r*r )
595 {
596 cj->type = k_contact_type_disabled;
597 ci->p = (ci->p + cj->p) * 0.5f;
598
599 v3_add( ci->co, cj->co, ci->co );
600 v3_muls( ci->co, 0.5f, ci->co );
601
602 v3f delta;
603 v3_sub( ci->rba->co, ci->co, delta );
604
605 float c0 = v3_dot( ci->n, delta ),
606 c1 = v3_dot( cj->n, delta );
607
608 if( c0 < 0.0f || c1 < 0.0f )
609 {
610 /* error */
611 ci->type = k_contact_type_disabled;
612 }
613 else
614 {
615 v3f n;
616 v3_muls( ci->n, c0, n );
617 v3_muladds( n, cj->n, c1, n );
618 v3_normalize( n );
619 v3_copy( n, ci->n );
620 }
621 }
622 }
623 }
624 }
625
626 /*
627 * Resolve overlapping pairs
628 */
629 VG_STATIC void rb_manifold_filter_pairs( rb_ct *man, int len, float r )
630 {
631 for( int i=0; i<len-1; i++ )
632 {
633 rb_ct *ci = &man[i];
634 int similar = 0;
635
636 if( ci->type == k_contact_type_disabled ) continue;
637
638 for( int j=i+1; j<len; j++ )
639 {
640 rb_ct *cj = &man[j];
641
642 if( cj->type == k_contact_type_disabled ) continue;
643
644 if( v3_dist2( ci->co, cj->co ) < r*r )
645 {
646 cj->type = k_contact_type_disabled;
647 v3_add( cj->n, ci->n, ci->n );
648 ci->p += cj->p;
649 similar ++;
650 }
651 }
652
653 if( similar )
654 {
655 float n = 1.0f/((float)similar+1.0f);
656 v3_muls( ci->n, n, ci->n );
657 ci->p *= n;
658
659 if( v3_length2(ci->n) < 0.1f*0.1f )
660 ci->type = k_contact_type_disabled;
661 else
662 v3_normalize( ci->n );
663 }
664 }
665 }
666
667 /*
668 * Remove contacts that are facing away from A
669 */
670 VG_STATIC void rb_manifold_filter_backface( rb_ct *man, int len )
671 {
672 for( int i=0; i<len; i++ )
673 {
674 rb_ct *ct = &man[i];
675 if( ct->type == k_contact_type_disabled )
676 continue;
677
678 v3f delta;
679 v3_sub( ct->co, ct->rba->co, delta );
680
681 if( v3_dot( delta, ct->n ) > -0.001f )
682 ct->type = k_contact_type_disabled;
683 }
684 }
685
686 /*
687 * Filter out duplicate coplanar results. Good for spheres.
688 */
689 VG_STATIC void rb_manifold_filter_coplanar( rb_ct *man, int len, float w )
690 {
691 for( int i=0; i<len; i++ )
692 {
693 rb_ct *ci = &man[i];
694 if( ci->type == k_contact_type_disabled ||
695 ci->type == k_contact_type_edge )
696 continue;
697
698 float d1 = v3_dot( ci->co, ci->n );
699
700 for( int j=0; j<len; j++ )
701 {
702 if( j == i )
703 continue;
704
705 rb_ct *cj = &man[j];
706 if( cj->type == k_contact_type_disabled )
707 continue;
708
709 float d2 = v3_dot( cj->co, ci->n ),
710 d = d2-d1;
711
712 if( fabsf( d ) <= w )
713 {
714 cj->type = k_contact_type_disabled;
715 }
716 }
717 }
718 }
719
720 /*
721 * -----------------------------------------------------------------------------
722 * Collision matrix
723 * -----------------------------------------------------------------------------
724 */
725
726 /*
727 * Contact generators
728 *
729 * These do not automatically allocate contacts, an appropriately sized
730 * buffer must be supplied. The function returns the size of the manifold
731 * which was generated.
732 *
733 * The values set on the contacts are: n, co, p, rba, rbb
734 */
735
736 /*
737 * By collecting the minimum(time) and maximum(time) pairs of points, we
738 * build a reduced and stable exact manifold.
739 *
740 * tx: time at point
741 * rx: minimum distance of these points
742 * dx: the delta between the two points
743 *
744 * pairs will only ammend these if they are creating a collision
745 */
746 typedef struct capsule_manifold capsule_manifold;
747 struct capsule_manifold
748 {
749 float t0, t1;
750 float r0, r1;
751 v3f d0, d1;
752 };
753
754 /*
755 * Expand a line manifold with a new pair. t value is the time along segment
756 * on the oriented object which created this pair.
757 */
758 VG_STATIC void rb_capsule_manifold( v3f pa, v3f pb, float t, float r,
759 capsule_manifold *manifold )
760 {
761 v3f delta;
762 v3_sub( pa, pb, delta );
763
764 if( v3_length2(delta) < r*r )
765 {
766 if( t < manifold->t0 )
767 {
768 v3_copy( delta, manifold->d0 );
769 manifold->t0 = t;
770 manifold->r0 = r;
771 }
772
773 if( t > manifold->t1 )
774 {
775 v3_copy( delta, manifold->d1 );
776 manifold->t1 = t;
777 manifold->r1 = r;
778 }
779 }
780 }
781
782 VG_STATIC void rb_capsule_manifold_init( capsule_manifold *manifold )
783 {
784 manifold->t0 = INFINITY;
785 manifold->t1 = -INFINITY;
786 }
787
788 VG_STATIC int rb_capsule_manifold_done( rigidbody *rba, rigidbody *rbb,
789 capsule_manifold *manifold, rb_ct *buf )
790 {
791 float h = rba->inf.capsule.height,
792 ra = rba->inf.capsule.radius;
793
794 v3f p0, p1;
795 v3_muladds( rba->co, rba->up, -h*0.5f+ra, p0 );
796 v3_muladds( rba->co, rba->up, h*0.5f-ra, p1 );
797
798 int count = 0;
799 if( manifold->t0 <= 1.0f )
800 {
801 rb_ct *ct = buf;
802
803 v3f pa;
804 v3_muls( p0, 1.0f-manifold->t0, pa );
805 v3_muladds( pa, p1, manifold->t0, pa );
806
807 float d = v3_length( manifold->d0 );
808 v3_muls( manifold->d0, 1.0f/d, ct->n );
809 v3_muladds( pa, ct->n, -ra, ct->co );
810
811 ct->p = manifold->r0 - d;
812 ct->rba = rba;
813 ct->rbb = rbb;
814 ct->type = k_contact_type_default;
815
816 count ++;
817 }
818
819 if( (manifold->t1 >= 0.0f) && (manifold->t0 != manifold->t1) )
820 {
821 rb_ct *ct = buf+count;
822
823 v3f pa;
824 v3_muls( p0, 1.0f-manifold->t1, pa );
825 v3_muladds( pa, p1, manifold->t1, pa );
826
827 float d = v3_length( manifold->d1 );
828 v3_muls( manifold->d1, 1.0f/d, ct->n );
829 v3_muladds( pa, ct->n, -ra, ct->co );
830
831 ct->p = manifold->r1 - d;
832 ct->rba = rba;
833 ct->rbb = rbb;
834 ct->type = k_contact_type_default;
835
836 count ++;
837 }
838
839 /*
840 * Debugging
841 */
842
843 if( count == 2 )
844 vg_line( buf[0].co, buf[1].co, 0xff0000ff );
845
846 return count;
847 }
848
849 VG_STATIC int rb_capsule_sphere( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
850 {
851 float h = rba->inf.capsule.height,
852 ra = rba->inf.capsule.radius,
853 rb = rbb->inf.sphere.radius;
854
855 v3f p0, p1;
856 v3_muladds( rba->co, rba->up, -h*0.5f+ra, p0 );
857 v3_muladds( rba->co, rba->up, h*0.5f-ra, p1 );
858
859 v3f c, delta;
860 closest_point_segment( p0, p1, rbb->co, c );
861 v3_sub( c, rbb->co, delta );
862
863 float d2 = v3_length2(delta),
864 r = ra + rb;
865
866 if( d2 < r*r )
867 {
868 float d = sqrtf(d2);
869
870 rb_ct *ct = buf;
871 v3_muls( delta, 1.0f/d, ct->n );
872 ct->p = r-d;
873
874 v3f p0, p1;
875 v3_muladds( c, ct->n, -ra, p0 );
876 v3_muladds( rbb->co, ct->n, rb, p1 );
877 v3_add( p0, p1, ct->co );
878 v3_muls( ct->co, 0.5f, ct->co );
879
880 ct->rba = rba;
881 ct->rbb = rbb;
882 ct->type = k_contact_type_default;
883
884 return 1;
885 }
886
887 return 0;
888 }
889
890 VG_STATIC int rb_capsule_capsule( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
891 {
892 float ha = rba->inf.capsule.height,
893 hb = rbb->inf.capsule.height,
894 ra = rba->inf.capsule.radius,
895 rb = rbb->inf.capsule.radius,
896 r = ra+rb;
897
898 v3f p0, p1, p2, p3;
899 v3_muladds( rba->co, rba->up, -ha*0.5f+ra, p0 );
900 v3_muladds( rba->co, rba->up, ha*0.5f-ra, p1 );
901 v3_muladds( rbb->co, rbb->up, -hb*0.5f+rb, p2 );
902 v3_muladds( rbb->co, rbb->up, hb*0.5f-rb, p3 );
903
904 capsule_manifold manifold;
905 rb_capsule_manifold_init( &manifold );
906
907 v3f pa, pb;
908 float ta, tb;
909 closest_segment_segment( p0, p1, p2, p3, &ta, &tb, pa, pb );
910 rb_capsule_manifold( pa, pb, ta, r, &manifold );
911
912 ta = closest_point_segment( p0, p1, p2, pa );
913 tb = closest_point_segment( p0, p1, p3, pb );
914 rb_capsule_manifold( pa, p2, ta, r, &manifold );
915 rb_capsule_manifold( pb, p3, tb, r, &manifold );
916
917 closest_point_segment( p2, p3, p0, pa );
918 closest_point_segment( p2, p3, p1, pb );
919 rb_capsule_manifold( p0, pa, 0.0f, r, &manifold );
920 rb_capsule_manifold( p1, pb, 1.0f, r, &manifold );
921
922 return rb_capsule_manifold_done( rba, rbb, &manifold, buf );
923 }
924
925 /*
926 * Generates up to two contacts; optimised for the most stable manifold
927 */
928 VG_STATIC int rb_capsule_box( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
929 {
930 float h = rba->inf.capsule.height,
931 r = rba->inf.capsule.radius;
932
933 /*
934 * Solving this in symetric local space of the cube saves us some time and a
935 * couple branches when it comes to the quad stage.
936 */
937 v3f centroid;
938 v3_add( rbb->bbx[0], rbb->bbx[1], centroid );
939 v3_muls( centroid, 0.5f, centroid );
940
941 boxf bbx;
942 v3_sub( rbb->bbx[0], centroid, bbx[0] );
943 v3_sub( rbb->bbx[1], centroid, bbx[1] );
944
945 v3f pc, p0w, p1w, p0, p1;
946 v3_muladds( rba->co, rba->up, -h*0.5f+r, p0w );
947 v3_muladds( rba->co, rba->up, h*0.5f-r, p1w );
948
949 m4x3_mulv( rbb->to_local, p0w, p0 );
950 m4x3_mulv( rbb->to_local, p1w, p1 );
951 v3_sub( p0, centroid, p0 );
952 v3_sub( p1, centroid, p1 );
953 v3_add( p0, p1, pc );
954 v3_muls( pc, 0.5f, pc );
955
956 /*
957 * Finding an appropriate quad to collide lines with
958 */
959 v3f region;
960 v3_div( pc, bbx[1], region );
961
962 v3f quad[4];
963 if( (fabsf(region[0]) > fabsf(region[1])) &&
964 (fabsf(region[0]) > fabsf(region[2])) )
965 {
966 float px = vg_signf(region[0]) * bbx[1][0];
967 v3_copy( (v3f){ px, bbx[0][1], bbx[0][2] }, quad[0] );
968 v3_copy( (v3f){ px, bbx[1][1], bbx[0][2] }, quad[1] );
969 v3_copy( (v3f){ px, bbx[1][1], bbx[1][2] }, quad[2] );
970 v3_copy( (v3f){ px, bbx[0][1], bbx[1][2] }, quad[3] );
971 }
972 else if( fabsf(region[1]) > fabsf(region[2]) )
973 {
974 float py = vg_signf(region[1]) * bbx[1][1];
975 v3_copy( (v3f){ bbx[0][0], py, bbx[0][2] }, quad[0] );
976 v3_copy( (v3f){ bbx[1][0], py, bbx[0][2] }, quad[1] );
977 v3_copy( (v3f){ bbx[1][0], py, bbx[1][2] }, quad[2] );
978 v3_copy( (v3f){ bbx[0][0], py, bbx[1][2] }, quad[3] );
979 }
980 else
981 {
982 float pz = vg_signf(region[2]) * bbx[1][2];
983 v3_copy( (v3f){ bbx[0][0], bbx[0][1], pz }, quad[0] );
984 v3_copy( (v3f){ bbx[1][0], bbx[0][1], pz }, quad[1] );
985 v3_copy( (v3f){ bbx[1][0], bbx[1][1], pz }, quad[2] );
986 v3_copy( (v3f){ bbx[0][0], bbx[1][1], pz }, quad[3] );
987 }
988
989 capsule_manifold manifold;
990 rb_capsule_manifold_init( &manifold );
991
992 v3f c0, c1;
993 closest_point_aabb( p0, bbx, c0 );
994 closest_point_aabb( p1, bbx, c1 );
995
996 v3f d0, d1, da;
997 v3_sub( c0, p0, d0 );
998 v3_sub( c1, p1, d1 );
999 v3_sub( p1, p0, da );
1000
1001 v3_normalize(d0);
1002 v3_normalize(d1);
1003 v3_normalize(da);
1004
1005 if( v3_dot( da, d0 ) <= 0.01f )
1006 rb_capsule_manifold( p0, c0, 0.0f, r, &manifold );
1007
1008 if( v3_dot( da, d1 ) >= -0.01f )
1009 rb_capsule_manifold( p1, c1, 1.0f, r, &manifold );
1010
1011 for( int i=0; i<4; i++ )
1012 {
1013 int i0 = i,
1014 i1 = (i+1)%4;
1015
1016 v3f ca, cb;
1017 float ta, tb;
1018 closest_segment_segment( p0, p1, quad[i0], quad[i1], &ta, &tb, ca, cb );
1019 rb_capsule_manifold( ca, cb, ta, r, &manifold );
1020 }
1021
1022 /*
1023 * Create final contacts based on line manifold
1024 */
1025 m3x3_mulv( rbb->to_world, manifold.d0, manifold.d0 );
1026 m3x3_mulv( rbb->to_world, manifold.d1, manifold.d1 );
1027
1028 /*
1029 * Debugging
1030 */
1031
1032 #if 0
1033 for( int i=0; i<4; i++ )
1034 {
1035 v3f q0, q1;
1036 int i0 = i,
1037 i1 = (i+1)%4;
1038
1039 v3_add( quad[i0], centroid, q0 );
1040 v3_add( quad[i1], centroid, q1 );
1041
1042 m4x3_mulv( rbb->to_world, q0, q0 );
1043 m4x3_mulv( rbb->to_world, q1, q1 );
1044
1045 vg_line( q0, q1, 0xffffffff );
1046 }
1047 #endif
1048
1049 return rb_capsule_manifold_done( rba, rbb, &manifold, buf );
1050 }
1051
1052 VG_STATIC int rb_sphere_box( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
1053 {
1054 v3f co, delta;
1055
1056 closest_point_obb( rba->co, rbb->bbx, rbb->to_world, rbb->to_local, co );
1057 v3_sub( rba->co, co, delta );
1058
1059 float d2 = v3_length2(delta),
1060 r = rba->inf.sphere.radius;
1061
1062 if( d2 <= r*r )
1063 {
1064 float d;
1065
1066 rb_ct *ct = buf;
1067 if( d2 <= 0.0001f )
1068 {
1069 v3_sub( rba->co, rbb->co, delta );
1070
1071 /*
1072 * some extra testing is required to find the best axis to push the
1073 * object back outside the box. Since there isnt a clear seperating
1074 * vector already, especially on really high aspect boxes.
1075 */
1076 float lx = v3_dot( rbb->right, delta ),
1077 ly = v3_dot( rbb->up, delta ),
1078 lz = v3_dot( rbb->forward, delta ),
1079 px = rbb->bbx[1][0] - fabsf(lx),
1080 py = rbb->bbx[1][1] - fabsf(ly),
1081 pz = rbb->bbx[1][2] - fabsf(lz);
1082
1083 if( px < py && px < pz )
1084 v3_muls( rbb->right, vg_signf(lx), ct->n );
1085 else if( py < pz )
1086 v3_muls( rbb->up, vg_signf(ly), ct->n );
1087 else
1088 v3_muls( rbb->forward, vg_signf(lz), ct->n );
1089
1090 v3_muladds( rba->co, ct->n, -r, ct->co );
1091 ct->p = r;
1092 }
1093 else
1094 {
1095 d = sqrtf(d2);
1096 v3_muls( delta, 1.0f/d, ct->n );
1097 ct->p = r-d;
1098 v3_copy( co, ct->co );
1099 }
1100
1101 ct->rba = rba;
1102 ct->rbb = rbb;
1103 ct->type = k_contact_type_default;
1104 return 1;
1105 }
1106
1107 return 0;
1108 }
1109
1110 VG_STATIC int rb_sphere_sphere( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
1111 {
1112 v3f delta;
1113 v3_sub( rba->co, rbb->co, delta );
1114
1115 float d2 = v3_length2(delta),
1116 r = rba->inf.sphere.radius + rbb->inf.sphere.radius;
1117
1118 if( d2 < r*r )
1119 {
1120 float d = sqrtf(d2);
1121
1122 rb_ct *ct = buf;
1123 v3_muls( delta, 1.0f/d, ct->n );
1124
1125 v3f p0, p1;
1126 v3_muladds( rba->co, ct->n,-rba->inf.sphere.radius, p0 );
1127 v3_muladds( rbb->co, ct->n, rbb->inf.sphere.radius, p1 );
1128 v3_add( p0, p1, ct->co );
1129 v3_muls( ct->co, 0.5f, ct->co );
1130 ct->type = k_contact_type_default;
1131 ct->p = r-d;
1132 ct->rba = rba;
1133 ct->rbb = rbb;
1134 return 1;
1135 }
1136
1137 return 0;
1138 }
1139
1140 //#define RIGIDBODY_DYNAMIC_MESH_EDGES
1141
1142 VG_STATIC int rb_sphere_triangle( rigidbody *rba, rigidbody *rbb,
1143 v3f tri[3], rb_ct *buf )
1144 {
1145 v3f delta, co;
1146
1147 #ifdef RIGIDBODY_DYNAMIC_MESH_EDGES
1148 closest_on_triangle_1( rba->co, tri, co );
1149 #else
1150 enum contact_type type = closest_on_triangle_1( rba->co, tri, co );
1151 #endif
1152
1153 v3_sub( rba->co, co, delta );
1154
1155 float d2 = v3_length2( delta ),
1156 r = rba->inf.sphere.radius;
1157
1158 if( d2 < r*r )
1159 {
1160 rb_ct *ct = buf;
1161
1162 v3f ab, ac, tn;
1163 v3_sub( tri[2], tri[0], ab );
1164 v3_sub( tri[1], tri[0], ac );
1165 v3_cross( ac, ab, tn );
1166 v3_copy( tn, ct->n );
1167 v3_normalize( ct->n );
1168
1169 float d = sqrtf(d2);
1170
1171 v3_copy( co, ct->co );
1172 ct->type = type;
1173 ct->p = r-d;
1174 ct->rba = rba;
1175 ct->rbb = rbb;
1176 return 1;
1177 }
1178
1179 return 0;
1180 }
1181
1182
1183 VG_STATIC void rb_debug_sharp_scene_edges( rigidbody *rbb, float sharp_ang,
1184 boxf box, u32 colour )
1185 {
1186 sharp_ang = cosf( sharp_ang );
1187
1188 scene *sc = rbb->inf.scene.bh_scene->user;
1189 vg_line_boxf( box, 0xff00ff00 );
1190
1191 bh_iter it;
1192 bh_iter_init( 0, &it );
1193 int idx;
1194
1195 while( bh_next( rbb->inf.scene.bh_scene, &it, box, &idx ) )
1196 {
1197 u32 *ptri = &sc->arrindices[ idx*3 ];
1198 v3f tri[3];
1199
1200 for( int j=0; j<3; j++ )
1201 v3_copy( sc->arrvertices[ptri[j]].co, tri[j] );
1202
1203 for( int j=0; j<3; j++ )
1204 {
1205 #if 0
1206 v3f edir;
1207 v3_sub( tri[(j+1)%3], tri[j], edir );
1208
1209 if( v3_dot( edir, (v3f){ 0.5184758473652127f,
1210 0.2073903389460850f,
1211 -0.8295613557843402f } ) < 0.0f )
1212 continue;
1213 #endif
1214
1215 bh_iter jt;
1216 bh_iter_init( 0, &jt );
1217
1218 boxf region;
1219 float const k_r = 0.02f;
1220 v3_add( (v3f){ k_r, k_r, k_r }, tri[j], region[1] );
1221 v3_add( (v3f){ -k_r, -k_r, -k_r }, tri[j], region[0] );
1222
1223 int jdx;
1224 while( bh_next( rbb->inf.scene.bh_scene, &jt, region, &jdx ) )
1225 {
1226 if( idx <= jdx )
1227 continue;
1228
1229 u32 *ptrj = &sc->arrindices[ jdx*3 ];
1230 v3f trj[3];
1231
1232 for( int k=0; k<3; k++ )
1233 v3_copy( sc->arrvertices[ptrj[k]].co, trj[k] );
1234
1235 for( int k=0; k<3; k++ )
1236 {
1237 if( v3_dist2( tri[j], trj[k] ) <= k_r*k_r )
1238 {
1239 int jp1 = (j+1)%3,
1240 jp2 = (j+2)%3,
1241 km1 = (k+3-1)%3,
1242 km2 = (k+3-2)%3;
1243
1244 if( v3_dist2( tri[jp1], trj[km1] ) <= k_r*k_r )
1245 {
1246 v3f b0, b1, b2;
1247 v3_sub( tri[jp1], tri[j], b0 );
1248 v3_sub( tri[jp2], tri[j], b1 );
1249 v3_sub( trj[km2], tri[j], b2 );
1250
1251 v3f cx0, cx1;
1252 v3_cross( b0, b1, cx0 );
1253 v3_cross( b2, b0, cx1 );
1254
1255 float polarity = v3_dot( cx0, b2 );
1256
1257 if( polarity < 0.0f )
1258 {
1259 #if 0
1260 vg_line( tri[j], tri[jp1], 0xff00ff00 );
1261 float ang = v3_dot(cx0,cx1) /
1262 (v3_length(cx0)*v3_length(cx1));
1263 if( ang < sharp_ang )
1264 {
1265 vg_line( tri[j], tri[jp1], 0xff00ff00 );
1266 }
1267 #endif
1268 }
1269 }
1270 }
1271 }
1272 }
1273 }
1274 }
1275 }
1276
1277 VG_STATIC int rb_sphere_scene( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
1278 {
1279 scene *sc = rbb->inf.scene.bh_scene->user;
1280
1281 bh_iter it;
1282 bh_iter_init( 0, &it );
1283 int idx;
1284
1285 int count = 0;
1286
1287 while( bh_next( rbb->inf.scene.bh_scene, &it, rba->bbx_world, &idx ) )
1288 {
1289 u32 *ptri = &sc->arrindices[ idx*3 ];
1290 v3f tri[3];
1291
1292 for( int j=0; j<3; j++ )
1293 v3_copy( sc->arrvertices[ptri[j]].co, tri[j] );
1294
1295 buf[ count ].element_id = ptri[0];
1296
1297 vg_line( tri[0],tri[1],0x70ff6000 );
1298 vg_line( tri[1],tri[2],0x70ff6000 );
1299 vg_line( tri[2],tri[0],0x70ff6000 );
1300
1301 int contact = rb_sphere_triangle( rba, rbb, tri, buf+count );
1302 count += contact;
1303
1304 if( count == 16 )
1305 {
1306 vg_warn( "Exceeding sphere_vs_scene capacity. Geometry too dense!\n" );
1307 return count;
1308 }
1309 }
1310
1311 return count;
1312 }
1313
1314 VG_STATIC int rb_box_scene( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
1315 {
1316 scene *sc = rbb->inf.scene.bh_scene->user;
1317
1318 v3f tri[3];
1319
1320 bh_iter it;
1321 bh_iter_init( 0, &it );
1322 int idx;
1323
1324 int count = 0;
1325
1326 while( bh_next( rbb->inf.scene.bh_scene, &it, rba->bbx_world, &idx ) )
1327 {
1328 u32 *ptri = &sc->arrindices[ idx*3 ];
1329
1330 for( int j=0; j<3; j++ )
1331 v3_copy( sc->arrvertices[ptri[j]].co, tri[j] );
1332
1333 if( rb_box_triangle_sat( rba, tri ) )
1334 {
1335 vg_line(tri[0],tri[1],0xff50ff00 );
1336 vg_line(tri[1],tri[2],0xff50ff00 );
1337 vg_line(tri[2],tri[0],0xff50ff00 );
1338 }
1339 else
1340 {
1341 vg_line(tri[0],tri[1],0xff0000ff );
1342 vg_line(tri[1],tri[2],0xff0000ff );
1343 vg_line(tri[2],tri[0],0xff0000ff );
1344
1345 continue;
1346 }
1347
1348 v3f v0,v1,n;
1349 v3_sub( tri[1], tri[0], v0 );
1350 v3_sub( tri[2], tri[0], v1 );
1351 v3_cross( v0, v1, n );
1352 v3_normalize( n );
1353
1354 /* find best feature */
1355 float best = v3_dot( rba->right, n );
1356 int axis = 0;
1357
1358 float cy = v3_dot( rba->up, n );
1359 if( fabsf(cy) > fabsf(best) )
1360 {
1361 best = cy;
1362 axis = 1;
1363 }
1364
1365 float cz = -v3_dot( rba->forward, n );
1366 if( fabsf(cz) > fabsf(best) )
1367 {
1368 best = cz;
1369 axis = 2;
1370 }
1371
1372 v3f manifold[4];
1373
1374 if( axis == 0 )
1375 {
1376 float px = best > 0.0f? rba->bbx[0][0]: rba->bbx[1][0];
1377 manifold[0][0] = px;
1378 manifold[0][1] = rba->bbx[0][1];
1379 manifold[0][2] = rba->bbx[0][2];
1380 manifold[1][0] = px;
1381 manifold[1][1] = rba->bbx[1][1];
1382 manifold[1][2] = rba->bbx[0][2];
1383 manifold[2][0] = px;
1384 manifold[2][1] = rba->bbx[1][1];
1385 manifold[2][2] = rba->bbx[1][2];
1386 manifold[3][0] = px;
1387 manifold[3][1] = rba->bbx[0][1];
1388 manifold[3][2] = rba->bbx[1][2];
1389 }
1390 else if( axis == 1 )
1391 {
1392 float py = best > 0.0f? rba->bbx[0][1]: rba->bbx[1][1];
1393 manifold[0][0] = rba->bbx[0][0];
1394 manifold[0][1] = py;
1395 manifold[0][2] = rba->bbx[0][2];
1396 manifold[1][0] = rba->bbx[1][0];
1397 manifold[1][1] = py;
1398 manifold[1][2] = rba->bbx[0][2];
1399 manifold[2][0] = rba->bbx[1][0];
1400 manifold[2][1] = py;
1401 manifold[2][2] = rba->bbx[1][2];
1402 manifold[3][0] = rba->bbx[0][0];
1403 manifold[3][1] = py;
1404 manifold[3][2] = rba->bbx[1][2];
1405 }
1406 else
1407 {
1408 float pz = best > 0.0f? rba->bbx[0][2]: rba->bbx[1][2];
1409 manifold[0][0] = rba->bbx[0][0];
1410 manifold[0][1] = rba->bbx[0][1];
1411 manifold[0][2] = pz;
1412 manifold[1][0] = rba->bbx[1][0];
1413 manifold[1][1] = rba->bbx[0][1];
1414 manifold[1][2] = pz;
1415 manifold[2][0] = rba->bbx[1][0];
1416 manifold[2][1] = rba->bbx[1][1];
1417 manifold[2][2] = pz;
1418 manifold[3][0] = rba->bbx[0][0];
1419 manifold[3][1] = rba->bbx[1][1];
1420 manifold[3][2] = pz;
1421 }
1422
1423 for( int j=0; j<4; j++ )
1424 m4x3_mulv( rba->to_world, manifold[j], manifold[j] );
1425
1426 vg_line( manifold[0], manifold[1], 0xffffffff );
1427 vg_line( manifold[1], manifold[2], 0xffffffff );
1428 vg_line( manifold[2], manifold[3], 0xffffffff );
1429 vg_line( manifold[3], manifold[0], 0xffffffff );
1430
1431 for( int j=0; j<4; j++ )
1432 {
1433 rb_ct *ct = buf+count;
1434
1435 v3_copy( manifold[j], ct->co );
1436 v3_copy( n, ct->n );
1437
1438 float l0 = v3_dot( tri[0], n ),
1439 l1 = v3_dot( manifold[j], n );
1440
1441 ct->p = (l0-l1)*0.5f;
1442 if( ct->p < 0.0f )
1443 continue;
1444
1445 ct->type = k_contact_type_default;
1446 ct->rba = rba;
1447 ct->rbb = rbb;
1448 count ++;
1449
1450 if( count >= 12 )
1451 return count;
1452 }
1453 }
1454 return count;
1455 }
1456
1457 VG_STATIC int RB_MATRIX_ERROR( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
1458 {
1459 vg_error( "Collision type is unimplemented between types %d and %d\n",
1460 rba->type, rbb->type );
1461
1462 return 0;
1463 }
1464
1465 VG_STATIC int rb_sphere_capsule( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
1466 {
1467 return rb_capsule_sphere( rbb, rba, buf );
1468 }
1469
1470 VG_STATIC int rb_box_capsule( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
1471 {
1472 return rb_capsule_box( rbb, rba, buf );
1473 }
1474
1475 VG_STATIC int rb_box_sphere( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
1476 {
1477 return rb_sphere_box( rbb, rba, buf );
1478 }
1479
1480 VG_STATIC int rb_scene_box( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
1481 {
1482 return rb_box_scene( rbb, rba, buf );
1483 }
1484
1485 VG_STATIC int (*rb_jump_table[4][4])( rigidbody *a, rigidbody *b, rb_ct *buf ) =
1486 {
1487 /* box */ /* Sphere */ /* Capsule */ /* Mesh */
1488 { RB_MATRIX_ERROR, rb_box_sphere, rb_box_capsule, rb_box_scene },
1489 { rb_sphere_box, rb_sphere_sphere, rb_sphere_capsule, rb_sphere_scene },
1490 { rb_capsule_box, rb_capsule_sphere, rb_capsule_capsule, RB_MATRIX_ERROR },
1491 { rb_scene_box, RB_MATRIX_ERROR, RB_MATRIX_ERROR, RB_MATRIX_ERROR }
1492 };
1493
1494 VG_STATIC int rb_collide( rigidbody *rba, rigidbody *rbb )
1495 {
1496 int (*collider_jump)(rigidbody *rba, rigidbody *rbb, rb_ct *buf )
1497 = rb_jump_table[rba->type][rbb->type];
1498
1499 /*
1500 * 12 is the maximum manifold size we can generate, so we are forced to abort
1501 * potentially checking any more.
1502 */
1503 if( rb_contact_count + 12 > vg_list_size(rb_contact_buffer) )
1504 {
1505 vg_warn( "Too many contacts made in global collider buffer (%d of %d\n)",
1506 rb_contact_count, vg_list_size(rb_contact_buffer) );
1507 return 0;
1508 }
1509
1510 /*
1511 * FUTURE: Replace this with a more dedicated broad phase pass
1512 */
1513 if( box_overlap( rba->bbx_world, rbb->bbx_world ) )
1514 {
1515 int count = collider_jump( rba, rbb, rb_contact_buffer+rb_contact_count);
1516 rb_contact_count += count;
1517 return count;
1518 }
1519 else
1520 return 0;
1521 }
1522
1523 /*
1524 * -----------------------------------------------------------------------------
1525 * Dynamics
1526 * -----------------------------------------------------------------------------
1527 */
1528
1529 VG_STATIC void rb_solver_reset(void)
1530 {
1531 rb_contact_count = 0;
1532 }
1533
1534 VG_STATIC rb_ct *rb_global_ct(void)
1535 {
1536 return rb_contact_buffer + rb_contact_count;
1537 }
1538
1539 /*
1540 * Initializing things like tangent vectors
1541 */
1542 VG_STATIC void rb_presolve_contacts( rb_ct *buffer, int len )
1543 {
1544 for( int i=0; i<len; i++ )
1545 {
1546 rb_ct *ct = &buffer[i];
1547
1548 ct->bias = -0.2f * k_rb_rate * vg_minf( 0.0f, -ct->p+k_penetration_slop );
1549 rb_tangent_basis( ct->n, ct->t[0], ct->t[1] );
1550
1551 #if 0
1552 ct->type = k_contact_type_default;
1553 #endif
1554 ct->norm_impulse = 0.0f;
1555 ct->tangent_impulse[0] = 0.0f;
1556 ct->tangent_impulse[1] = 0.0f;
1557
1558 v3f ra, rb, raCn, rbCn, raCt, rbCt;
1559 v3_sub( ct->co, ct->rba->co, ra );
1560 v3_sub( ct->co, ct->rbb->co, rb );
1561 v3_cross( ra, ct->n, raCn );
1562 v3_cross( rb, ct->n, rbCn );
1563
1564 /* orient inverse inertia tensors */
1565 v3f raCnI, rbCnI;
1566 m3x3_mulv( ct->rba->iIw, raCn, raCnI );
1567 m3x3_mulv( ct->rbb->iIw, rbCn, rbCnI );
1568
1569 ct->normal_mass = ct->rba->inv_mass + ct->rbb->inv_mass;
1570 ct->normal_mass += v3_dot( raCn, raCnI );
1571 ct->normal_mass += v3_dot( rbCn, rbCnI );
1572 ct->normal_mass = 1.0f/ct->normal_mass;
1573
1574 for( int j=0; j<2; j++ )
1575 {
1576 v3f raCtI, rbCtI;
1577 v3_cross( ct->t[j], ra, raCt );
1578 v3_cross( ct->t[j], rb, rbCt );
1579 m3x3_mulv( ct->rba->iIw, raCt, raCtI );
1580 m3x3_mulv( ct->rbb->iIw, rbCt, rbCtI );
1581
1582 ct->tangent_mass[j] = ct->rba->inv_mass + ct->rbb->inv_mass;
1583 ct->tangent_mass[j] += v3_dot( raCt, raCtI );
1584 ct->tangent_mass[j] += v3_dot( rbCt, rbCtI );
1585 ct->tangent_mass[j] = 1.0f/ct->tangent_mass[j];
1586 }
1587
1588 rb_debug_contact( ct );
1589 }
1590 }
1591
1592 /*
1593 * Creates relative contact velocity vector, and offsets between each body
1594 */
1595 VG_STATIC void rb_rcv( rb_ct *ct, v3f rv, v3f da, v3f db )
1596 {
1597 rigidbody *rba = ct->rba,
1598 *rbb = ct->rbb;
1599
1600 v3_sub( ct->co, rba->co, da );
1601 v3_sub( ct->co, rbb->co, db );
1602
1603 v3f rva, rvb;
1604 v3_cross( rba->w, da, rva );
1605 v3_add( rba->v, rva, rva );
1606 v3_cross( rbb->w, db, rvb );
1607 v3_add( rbb->v, rvb, rvb );
1608
1609 v3_sub( rva, rvb, rv );
1610 }
1611
1612 /*
1613 * Apply impulse to object
1614 */
1615 VG_STATIC void rb_linear_impulse( rigidbody *rb, v3f delta, v3f impulse )
1616 {
1617 /* linear */
1618 v3_muladds( rb->v, impulse, rb->inv_mass, rb->v );
1619
1620 /* Angular velocity */
1621 v3f wa;
1622 v3_cross( delta, impulse, wa );
1623
1624 m3x3_mulv( rb->iIw, wa, wa );
1625 v3_add( rb->w, wa, rb->w );
1626 }
1627
1628 /*
1629 * One iteration to solve the contact constraint
1630 */
1631 VG_STATIC void rb_solve_contacts( rb_ct *buf, int len )
1632 {
1633 for( int i=0; i<len; i++ )
1634 {
1635 struct contact *ct = &buf[i];
1636
1637 rigidbody *rb = ct->rba;
1638
1639 v3f rv, da, db;
1640 rb_rcv( ct, rv, da, db );
1641
1642 /* Friction */
1643 for( int j=0; j<2; j++ )
1644 {
1645 float f = k_friction * ct->norm_impulse,
1646 vt = v3_dot( rv, ct->t[j] ),
1647 lambda = ct->tangent_mass[j] * -vt;
1648
1649 float temp = ct->tangent_impulse[j];
1650 ct->tangent_impulse[j] = vg_clampf( temp + lambda, -f, f );
1651 lambda = ct->tangent_impulse[j] - temp;
1652
1653 v3f impulse;
1654 v3_muls( ct->t[j], lambda, impulse );
1655 rb_linear_impulse( ct->rba, da, impulse );
1656
1657 v3_muls( ct->t[j], -lambda, impulse );
1658 rb_linear_impulse( ct->rbb, db, impulse );
1659 }
1660
1661 /* Normal */
1662 rb_rcv( ct, rv, da, db );
1663 float vn = v3_dot( rv, ct->n ),
1664 lambda = ct->normal_mass * (-vn + ct->bias);
1665
1666 float temp = ct->norm_impulse;
1667 ct->norm_impulse = vg_maxf( temp + lambda, 0.0f );
1668 lambda = ct->norm_impulse - temp;
1669
1670 v3f impulse;
1671 v3_muls( ct->n, lambda, impulse );
1672 rb_linear_impulse( ct->rba, da, impulse );
1673
1674 v3_muls( ct->n, -lambda, impulse );
1675 rb_linear_impulse( ct->rbb, db, impulse );
1676 }
1677 }
1678
1679 /*
1680 * -----------------------------------------------------------------------------
1681 * Constraints
1682 * -----------------------------------------------------------------------------
1683 */
1684
1685 VG_STATIC void draw_angle_limit( v3f c, v3f major, v3f minor,
1686 float amin, float amax, float measured,
1687 u32 colour )
1688 {
1689 float f = 0.05f;
1690 v3f ay, ax;
1691 v3_muls( major, f, ay );
1692 v3_muls( minor, f, ax );
1693
1694 for( int x=0; x<16; x++ )
1695 {
1696 float t0 = (float)x / 16.0f,
1697 t1 = (float)(x+1) / 16.0f,
1698 a0 = vg_lerpf( amin, amax, t0 ),
1699 a1 = vg_lerpf( amin, amax, t1 );
1700
1701 v3f p0, p1;
1702 v3_muladds( c, ay, cosf(a0), p0 );
1703 v3_muladds( p0, ax, sinf(a0), p0 );
1704 v3_muladds( c, ay, cosf(a1), p1 );
1705 v3_muladds( p1, ax, sinf(a1), p1 );
1706
1707 vg_line( p0, p1, colour );
1708
1709 if( x == 0 )
1710 vg_line( c, p0, colour );
1711 if( x == 15 )
1712 vg_line( c, p1, colour );
1713 }
1714
1715 v3f p2;
1716 v3_muladds( c, ay, cosf(measured)*1.2f, p2 );
1717 v3_muladds( p2, ax, sinf(measured)*1.2f, p2 );
1718 vg_line( c, p2, colour );
1719 }
1720
1721 VG_STATIC void rb_debug_constraint_limits( rigidbody *ra, rigidbody *rb, v3f lca,
1722 v3f limits[2] )
1723 {
1724 v3f ax, ay, az, bx, by, bz;
1725 m3x3_mulv( ra->to_world, (v3f){1.0f,0.0f,0.0f}, ax );
1726 m3x3_mulv( ra->to_world, (v3f){0.0f,1.0f,0.0f}, ay );
1727 m3x3_mulv( ra->to_world, (v3f){0.0f,0.0f,1.0f}, az );
1728 m3x3_mulv( rb->to_world, (v3f){1.0f,0.0f,0.0f}, bx );
1729 m3x3_mulv( rb->to_world, (v3f){0.0f,1.0f,0.0f}, by );
1730 m3x3_mulv( rb->to_world, (v3f){0.0f,0.0f,1.0f}, bz );
1731
1732 v2f px, py, pz;
1733 px[0] = v3_dot( ay, by );
1734 px[1] = v3_dot( az, by );
1735
1736 py[0] = v3_dot( az, bz );
1737 py[1] = v3_dot( ax, bz );
1738
1739 pz[0] = v3_dot( ax, bx );
1740 pz[1] = v3_dot( ay, bx );
1741
1742 float r0 = atan2f( px[1], px[0] ),
1743 r1 = atan2f( py[1], py[0] ),
1744 r2 = atan2f( pz[1], pz[0] );
1745
1746 v3f c;
1747 m4x3_mulv( ra->to_world, lca, c );
1748 draw_angle_limit( c, ay, az, limits[0][0], limits[1][0], r0, 0xff0000ff );
1749 draw_angle_limit( c, az, ax, limits[0][1], limits[1][1], r1, 0xff00ff00 );
1750 draw_angle_limit( c, ax, ay, limits[0][2], limits[1][2], r2, 0xffff0000 );
1751 }
1752
1753 VG_STATIC void rb_limit_cure( rigidbody *ra, rigidbody *rb, v3f axis, float d )
1754 {
1755 if( d != 0.0f )
1756 {
1757 float avx = v3_dot( ra->w, axis ) - v3_dot( rb->w, axis );
1758 float joint_mass = rb->inv_mass + ra->inv_mass;
1759 joint_mass = 1.0f/joint_mass;
1760
1761 float bias = (k_limit_bias * k_rb_rate) * d,
1762 lambda = -(avx + bias) * joint_mass;
1763
1764 /* Angular velocity */
1765 v3f wa, wb;
1766 v3_muls( axis, lambda * ra->inv_mass, wa );
1767 v3_muls( axis, -lambda * rb->inv_mass, wb );
1768
1769 v3_add( ra->w, wa, ra->w );
1770 v3_add( rb->w, wb, rb->w );
1771 }
1772 }
1773
1774 VG_STATIC void rb_constraint_limits( rigidbody *ra, v3f lca,
1775 rigidbody *rb, v3f lcb, v3f limits[2] )
1776 {
1777 v3f ax, ay, az, bx, by, bz;
1778 m3x3_mulv( ra->to_world, (v3f){1.0f,0.0f,0.0f}, ax );
1779 m3x3_mulv( ra->to_world, (v3f){0.0f,1.0f,0.0f}, ay );
1780 m3x3_mulv( ra->to_world, (v3f){0.0f,0.0f,1.0f}, az );
1781 m3x3_mulv( rb->to_world, (v3f){1.0f,0.0f,0.0f}, bx );
1782 m3x3_mulv( rb->to_world, (v3f){0.0f,1.0f,0.0f}, by );
1783 m3x3_mulv( rb->to_world, (v3f){0.0f,0.0f,1.0f}, bz );
1784
1785 v2f px, py, pz;
1786 px[0] = v3_dot( ay, by );
1787 px[1] = v3_dot( az, by );
1788
1789 py[0] = v3_dot( az, bz );
1790 py[1] = v3_dot( ax, bz );
1791
1792 pz[0] = v3_dot( ax, bx );
1793 pz[1] = v3_dot( ay, bx );
1794
1795 float r0 = atan2f( px[1], px[0] ),
1796 r1 = atan2f( py[1], py[0] ),
1797 r2 = atan2f( pz[1], pz[0] );
1798
1799 /* calculate angle deltas */
1800 float dx = 0.0f, dy = 0.0f, dz = 0.0f;
1801
1802 if( r0 < limits[0][0] ) dx = limits[0][0] - r0;
1803 if( r0 > limits[1][0] ) dx = limits[1][0] - r0;
1804 if( r1 < limits[0][1] ) dy = limits[0][1] - r1;
1805 if( r1 > limits[1][1] ) dy = limits[1][1] - r1;
1806 if( r2 < limits[0][2] ) dz = limits[0][2] - r2;
1807 if( r2 > limits[1][2] ) dz = limits[1][2] - r2;
1808
1809 v3f wca, wcb;
1810 m3x3_mulv( ra->to_world, lca, wca );
1811 m3x3_mulv( rb->to_world, lcb, wcb );
1812
1813 rb_limit_cure( ra, rb, ax, dx );
1814 rb_limit_cure( ra, rb, ay, dy );
1815 rb_limit_cure( ra, rb, az, dz );
1816 }
1817
1818 VG_STATIC void rb_debug_constraint_position( rigidbody *ra, v3f lca,
1819 rigidbody *rb, v3f lcb )
1820 {
1821 v3f wca, wcb;
1822 m3x3_mulv( ra->to_world, lca, wca );
1823 m3x3_mulv( rb->to_world, lcb, wcb );
1824
1825 v3f p0, p1;
1826 v3_add( wca, ra->co, p0 );
1827 v3_add( wcb, rb->co, p1 );
1828 vg_line_pt3( p0, 0.005f, 0xffffff00 );
1829 vg_line_pt3( p1, 0.005f, 0xffffff00 );
1830 vg_line( p0, p1, 0xffffff00 );
1831 }
1832
1833 VG_STATIC void rb_constraint_position( rigidbody *ra, v3f lca,
1834 rigidbody *rb, v3f lcb )
1835 {
1836 /* C = (COa + Ra*LCa) - (COb + Rb*LCb) = 0 */
1837 v3f wca, wcb;
1838 m3x3_mulv( ra->to_world, lca, wca );
1839 m3x3_mulv( rb->to_world, lcb, wcb );
1840
1841 v3f rcv;
1842 v3_sub( ra->v, rb->v, rcv );
1843
1844 v3f rcv_Ra, rcv_Rb;
1845 v3_cross( ra->w, wca, rcv_Ra );
1846 v3_cross( rb->w, wcb, rcv_Rb );
1847 v3_add( rcv_Ra, rcv, rcv );
1848 v3_sub( rcv, rcv_Rb, rcv );
1849
1850 v3f delta;
1851 v3f p0, p1;
1852 v3_add( wca, ra->co, p0 );
1853 v3_add( wcb, rb->co, p1 );
1854 v3_sub( p1, p0, delta );
1855
1856 float dist2 = v3_length2( delta );
1857
1858 if( dist2 > 0.00001f )
1859 {
1860 float dist = sqrtf(dist2);
1861 v3_muls( delta, 1.0f/dist, delta );
1862
1863 float joint_mass = rb->inv_mass + ra->inv_mass;
1864
1865 v3f raCn, rbCn, raCt, rbCt;
1866 v3_cross( wca, delta, raCn );
1867 v3_cross( wcb, delta, rbCn );
1868
1869 /* orient inverse inertia tensors */
1870 v3f raCnI, rbCnI;
1871 m3x3_mulv( ra->iIw, raCn, raCnI );
1872 m3x3_mulv( rb->iIw, rbCn, rbCnI );
1873 joint_mass += v3_dot( raCn, raCnI );
1874 joint_mass += v3_dot( rbCn, rbCnI );
1875 joint_mass = 1.0f/joint_mass;
1876
1877 float vd = v3_dot( rcv, delta ),
1878 bias = -(k_joint_bias * k_rb_rate) * dist,
1879 lambda = -(vd + bias) * joint_mass;
1880
1881 v3f impulse;
1882 v3_muls( delta, lambda, impulse );
1883 rb_linear_impulse( ra, wca, impulse );
1884 v3_muls( delta, -lambda, impulse );
1885 rb_linear_impulse( rb, wcb, impulse );
1886
1887 /* 'fake' snap */
1888 v3_muladds( ra->co, delta, dist * k_joint_correction, ra->co );
1889 v3_muladds( rb->co, delta, -dist * k_joint_correction, rb->co );
1890 }
1891 }
1892
1893 /*
1894 * Effectors
1895 */
1896
1897 VG_STATIC void rb_effect_simple_bouyency( rigidbody *ra, v4f plane,
1898 float amt, float drag )
1899 {
1900 /* float */
1901 float depth = v3_dot( plane, ra->co ) - plane[3],
1902 lambda = vg_clampf( -depth, 0.0f, 1.0f ) * amt;
1903
1904 v3_muladds( ra->v, plane, lambda * k_rb_delta, ra->v );
1905
1906 if( depth < 0.0f )
1907 v3_muls( ra->v, 1.0f-(drag*k_rb_delta), ra->v );
1908 }
1909
1910 /*
1911 * -----------------------------------------------------------------------------
1912 * BVH implementation, this is ONLY for VG_STATIC rigidbodies, its to slow for
1913 * realtime use.
1914 * -----------------------------------------------------------------------------
1915 */
1916
1917 VG_STATIC void rb_bh_expand_bound( void *user, boxf bound, u32 item_index )
1918 {
1919 rigidbody *rb = &((rigidbody *)user)[ item_index ];
1920 box_concat( bound, rb->bbx_world );
1921 }
1922
1923 VG_STATIC float rb_bh_centroid( void *user, u32 item_index, int axis )
1924 {
1925 rigidbody *rb = &((rigidbody *)user)[ item_index ];
1926 return (rb->bbx_world[axis][0] + rb->bbx_world[1][axis]) * 0.5f;
1927 }
1928
1929 VG_STATIC void rb_bh_swap( void *user, u32 ia, u32 ib )
1930 {
1931 rigidbody temp, *rba, *rbb;
1932 rba = &((rigidbody *)user)[ ia ];
1933 rbb = &((rigidbody *)user)[ ib ];
1934
1935 temp = *rba;
1936 *rba = *rbb;
1937 *rbb = temp;
1938 }
1939
1940 VG_STATIC void rb_bh_debug( void *user, u32 item_index )
1941 {
1942 rigidbody *rb = &((rigidbody *)user)[ item_index ];
1943 rb_debug( rb, 0xff00ffff );
1944 }
1945
1946 VG_STATIC bh_system bh_system_rigidbodies =
1947 {
1948 .expand_bound = rb_bh_expand_bound,
1949 .item_centroid = rb_bh_centroid,
1950 .item_swap = rb_bh_swap,
1951 .item_debug = rb_bh_debug,
1952 .cast_ray = NULL
1953 };
1954
1955 #endif /* RIGIDBODY_H */