f
[carveJwlIkooP6JGAAIwe30JlM.git] / rigidbody.h
1 /*
2 * Resources: Box2D - Erin Catto
3 * qu3e - Randy Gaul
4 */
5
6 #include "common.h"
7 #include "bvh.h"
8
9 static void rb_tangent_basis( v3f n, v3f tx, v3f ty );
10 static bh_system bh_system_rigidbodies;
11
12 #ifndef RIGIDBODY_H
13 #define RIGIDBODY_H
14
15 #define RB_DEPR
16 #define k_rb_rate 60.0f
17 #define k_rb_delta (1.0f/k_rb_rate)
18
19 typedef struct rigidbody rigidbody;
20 typedef struct contact rb_ct;
21
22 struct rigidbody
23 {
24 v3f co, v, w;
25 v4f q;
26
27 enum rb_shape
28 {
29 k_rb_shape_box,
30 k_rb_shape_sphere,
31 k_rb_shape_capsule
32 }
33 type;
34
35 union
36 {
37 struct rb_sphere
38 {
39 float radius;
40 }
41 sphere;
42
43 struct rb_capsule
44 {
45 float height, radius;
46 }
47 capsule;
48 }
49 inf;
50
51 v3f right, up, forward;
52
53 int is_world;
54
55 boxf bbx, bbx_world;
56 float inv_mass;
57
58 v3f delta; /* where is the origin of this in relation to a parent body */
59 m4x3f to_world, to_local;
60 };
61
62 static rigidbody rb_static_null =
63 {
64 .co={0.0f,0.0f,0.0f},
65 .q={0.0f,0.0f,0.0f,1.0f},
66 .v={0.0f,0.0f,0.0f},
67 .w={0.0f,0.0f,0.0f},
68 .is_world = 1,
69 .inv_mass = 0.0f
70 };
71
72 static void rb_debug( rigidbody *rb, u32 colour );
73
74 static struct contact
75 {
76 rigidbody *rba, *rbb;
77 v3f co, n;
78 v3f t[2];
79 float mass_total, p, bias, norm_impulse, tangent_impulse[2];
80 }
81 rb_contact_buffer[256];
82 static int rb_contact_count = 0;
83
84 static void rb_update_transform( rigidbody *rb )
85 {
86 q_normalize( rb->q );
87 q_m3x3( rb->q, rb->to_world );
88 v3_copy( rb->co, rb->to_world[3] );
89
90 m4x3_invert_affine( rb->to_world, rb->to_local );
91
92 box_copy( rb->bbx, rb->bbx_world );
93 m4x3_transform_aabb( rb->to_world, rb->bbx_world );
94
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 );
98 }
99
100 static float sphere_volume( float radius )
101 {
102 float r3 = radius*radius*radius;
103 return (4.0f/3.0f) * VG_PIf * r3;
104 }
105
106 static void rb_init( rigidbody *rb )
107 {
108 float volume = 1.0f;
109
110 if( rb->type == k_rb_shape_box )
111 {
112 v3f dims;
113 v3_sub( rb->bbx[1], rb->bbx[0], dims );
114 volume = dims[0]*dims[1]*dims[2];
115 }
116 else if( rb->type == k_rb_shape_sphere )
117 {
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 );
121 }
122 else if( rb->type == k_rb_shape_capsule )
123 {
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);
127
128 v3_fill( rb->bbx[0], -rb->inf.sphere.radius );
129 v3_fill( rb->bbx[1], rb->inf.sphere.radius );
130 rb->bbx[0][1] = -h;
131 rb->bbx[1][1] = h;
132 }
133
134 if( rb->is_world )
135 {
136 rb->inv_mass = 0.0f;
137 }
138 else
139 {
140 rb->inv_mass = 1.0f/(8.0f*volume);
141 }
142
143 v3_zero( rb->v );
144 v3_zero( rb->w );
145
146 rb_update_transform( rb );
147 }
148
149 static void rb_iter( rigidbody *rb )
150 {
151 v3f gravity = { 0.0f, -9.6f, 0.0f };
152 v3_muladds( rb->v, gravity, k_rb_delta, rb->v );
153
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 );
157
158 /* inegrate inertia */
159 if( v3_length2( rb->w ) > 0.0f )
160 {
161 v4f rotation;
162 v3f axis;
163 v3_copy( rb->w, axis );
164
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 );
169 }
170 }
171
172 static void rb_torque( rigidbody *rb, v3f axis, float mag )
173 {
174 v3_muladds( rb->w, axis, mag*k_rb_delta, rb->w );
175 }
176
177 static void rb_tangent_basis( v3f n, v3f tx, v3f ty )
178 {
179 /* Compute tangent basis (box2d) */
180 if( fabsf( n[0] ) >= 0.57735027f )
181 {
182 tx[0] = n[1];
183 tx[1] = -n[0];
184 tx[2] = 0.0f;
185 }
186 else
187 {
188 tx[0] = 0.0f;
189 tx[1] = n[2];
190 tx[2] = -n[1];
191 }
192
193 v3_normalize( tx );
194 v3_cross( n, tx, ty );
195 }
196
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( rb_ct *buf, int len );
201 static void rb_presolve_contacts( rb_ct *buffer, int len );
202
203 /*
204 * These closest point tests were learned from Real-Time Collision Detection by
205 * Christer Ericson
206 */
207 static float closest_segment_segment( v3f p1, v3f q1, v3f p2, v3f q2,
208 float *s, float *t, v3f c1, v3f c2)
209 {
210 v3f d1,d2,r;
211 v3_sub( q1, p1, d1 );
212 v3_sub( q2, p2, d2 );
213 v3_sub( p1, p2, r );
214
215 float a = v3_length2( d1 ),
216 e = v3_length2( d2 ),
217 f = v3_dot( d2, r );
218
219 const float kEpsilon = 0.0001f;
220
221 if( a <= kEpsilon && e <= kEpsilon )
222 {
223 *s = 0.0f;
224 *t = 0.0f;
225 v3_copy( p1, c1 );
226 v3_copy( p2, c2 );
227
228 v3f v0;
229 v3_sub( c1, c2, v0 );
230
231 return v3_length2( v0 );
232 }
233
234 if( a<= kEpsilon )
235 {
236 *s = 0.0f;
237 *t = vg_clampf( f / e, 0.0f, 1.0f );
238 }
239 else
240 {
241 float c = v3_dot( d1, r );
242 if( e <= kEpsilon )
243 {
244 *t = 0.0f;
245 *s = vg_clampf( -c / a, 0.0f, 1.0f );
246 }
247 else
248 {
249 float b = v3_dot(d1,d2),
250 d = a*e-b*b;
251
252 if( d != 0.0f )
253 {
254 *s = vg_clampf((b*f - c*e)/d, 0.0f, 1.0f);
255 }
256 else
257 {
258 *s = 0.0f;
259 }
260
261 *t = (b*(*s)+f) / e;
262
263 if( *t < 0.0f )
264 {
265 *t = 0.0f;
266 *s = vg_clampf( -c / a, 0.0f, 1.0f );
267 }
268 else if( *t > 1.0f )
269 {
270 *t = 1.0f;
271 *s = vg_clampf((b-c)/a,0.0f,1.0f);
272 }
273 }
274 }
275
276 v3_muladds( p1, d1, *s, c1 );
277 v3_muladds( p2, d2, *t, c2 );
278
279 v3f v0;
280 v3_sub( c1, c2, v0 );
281 return v3_length2( v0 );
282 }
283
284 static void closest_point_aabb( v3f p, boxf box, v3f dest )
285 {
286 v3_maxv( p, box[0], dest );
287 v3_minv( dest, box[1], dest );
288 }
289
290 static void closest_point_obb( v3f p, rigidbody *rb, v3f dest )
291 {
292 v3f local;
293 m4x3_mulv( rb->to_local, p, local );
294 closest_point_aabb( local, rb->bbx, local );
295 m4x3_mulv( rb->to_world, local, dest );
296 }
297
298 static void closest_point_segment( v3f a, v3f b, v3f point, v3f dest )
299 {
300 v3f v0, v1;
301 v3_sub( b, a, v0 );
302 v3_sub( point, a, v1 );
303
304 float t = v3_dot( v1, v0 ) / v3_length2(v0);
305 v3_muladds( a, v0, vg_clampf(t,0.0f,1.0f), dest );
306 }
307
308 static void closest_on_triangle( v3f p, v3f tri[3], v3f dest )
309 {
310 v3f ab, ac, ap;
311 float d1, d2;
312
313 /* Region outside A */
314 v3_sub( tri[1], tri[0], ab );
315 v3_sub( tri[2], tri[0], ac );
316 v3_sub( p, tri[0], ap );
317
318 d1 = v3_dot(ab,ap);
319 d2 = v3_dot(ac,ap);
320 if( d1 <= 0.0f && d2 <= 0.0f )
321 {
322 v3_copy( tri[0], dest );
323 v3_copy( (v3f){INFINITY,INFINITY,INFINITY}, dest );
324 return;
325 }
326
327 /* Region outside B */
328 v3f bp;
329 float d3, d4;
330
331 v3_sub( p, tri[1], bp );
332 d3 = v3_dot( ab, bp );
333 d4 = v3_dot( ac, bp );
334
335 if( d3 >= 0.0f && d4 <= d3 )
336 {
337 v3_copy( tri[1], dest );
338 v3_copy( (v3f){INFINITY,INFINITY,INFINITY}, dest );
339 return;
340 }
341
342 /* Edge region of AB */
343 float vc = d1*d4 - d3*d2;
344 if( vc <= 0.0f && d1 >= 0.0f && d3 <= 0.0f )
345 {
346 float v = d1 / (d1-d3);
347 v3_muladds( tri[0], ab, v, dest );
348 v3_copy( (v3f){INFINITY,INFINITY,INFINITY}, dest );
349 return;
350 }
351
352 /* Region outside C */
353 v3f cp;
354 float d5, d6;
355 v3_sub( p, tri[2], cp );
356 d5 = v3_dot(ab, cp);
357 d6 = v3_dot(ac, cp);
358
359 if( d6 >= 0.0f && d5 <= d6 )
360 {
361 v3_copy( tri[2], dest );
362 v3_copy( (v3f){INFINITY,INFINITY,INFINITY}, dest );
363 return;
364 }
365
366 /* Region of AC */
367 float vb = d5*d2 - d1*d6;
368 if( vb <= 0.0f && d2 >= 0.0f && d6 <= 0.0f )
369 {
370 float w = d2 / (d2-d6);
371 v3_muladds( tri[0], ac, w, dest );
372 v3_copy( (v3f){INFINITY,INFINITY,INFINITY}, dest );
373 return;
374 }
375
376 /* Region of BC */
377 float va = d3*d6 - d5*d4;
378 if( va <= 0.0f && (d4-d3) >= 0.0f && (d5-d6) >= 0.0f )
379 {
380 float w = (d4-d3) / ((d4-d3) + (d5-d6));
381 v3f bc;
382 v3_sub( tri[2], tri[1], bc );
383 v3_muladds( tri[1], bc, w, dest );
384 v3_copy( (v3f){INFINITY,INFINITY,INFINITY}, dest );
385 return;
386 }
387
388 /* P inside region, Q via barycentric coordinates uvw */
389 float d = 1.0f/(va+vb+vc),
390 v = vb*d,
391 w = vc*d;
392
393 v3_muladds( tri[0], ab, v, dest );
394 v3_muladds( dest, ac, w, dest );
395 }
396
397 /*
398 * Contact generators
399 *
400 * These do not automatically allocate contacts, an appropriately sized
401 * buffer must be supplied. The function returns the size of the manifold
402 * which was generated.
403 *
404 * The values set on the contacts are: n, co, p, rba, rbb
405 */
406
407 static void rb_debug_contact( rb_ct *ct )
408 {
409 v3f p1;
410 v3_muladds( ct->co, ct->n, 0.2f, p1 );
411 vg_line_pt3( ct->co, 0.1f, 0xff0000ff );
412 vg_line( ct->co, p1, 0xffffffff );
413 }
414
415 static void rb_box_incident_dir( v3f p, boxf box, v3f dir )
416 {
417
418 }
419
420 /*
421 * Generates up to two contacts; optimised for the most stable manifold
422 */
423 static int rb_capsule_vs_box( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
424 {
425 float h = rba->inf.capsule.height,
426 r = rba->inf.capsule.radius;
427
428 v3f p0, p1;
429 v3_muladds( rba->co, rba->up, h*0.5f-r*0.5f, p1 );
430 v3_muladds( rba->co, rba->up, -h*0.5f+r*0.5f, p0 );
431
432 m4x3_mulv( rbb->to_local, p0, p0 );
433 m4x3_mulv( rbb->to_local, p1, p1 );
434
435 /* Clip zone +y */
436
437 v3f c0, c1;
438 closest_point_aabb( p0, rbb->bbx, c0 );
439 closest_point_aabb( p1, rbb->bbx, c1 );
440
441 v3f vis0;
442 m4x3_mulv( rbb->to_world, c0, vis0 );
443 vg_line_pt3( vis0, 0.1f, 0xffff00ff );
444 m4x3_mulv( rbb->to_world, c1, vis0 );
445 vg_line_pt3( vis0, 0.1f, 0xffff00ff );
446
447 v3f d0, d1;
448 v3_sub( p0, c0, d0 );
449 v3_sub( p1, c1, d1 );
450
451 float d02 = v3_length2(d0),
452 d12 = v3_length2(d1);
453
454 int count = 0;
455
456 if( d02 <= r*r )
457 {
458 rb_ct *ct = buf+count;
459 float d = sqrtf(d02);
460
461 vg_info( "d: %.4f\n", d );
462
463 v3_muls( d0, -1.0f/d, ct->n );
464 ct->p = r-d;
465 v3_add( c0, p0, ct->co );
466 v3_muls( ct->co, 0.5f, ct->co );
467
468 m3x3_mulv( rbb->to_world, ct->n, ct->n );
469 m4x3_mulv( rbb->to_world, ct->co, ct->co );
470
471 ct->rba = rba;
472 ct->rbb = rbb;
473 count ++;
474 }
475
476 return count;
477 }
478
479 static int rb_sphere_vs_box( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
480 {
481 v3f co, delta;
482
483 closest_point_obb( rba->co, rbb, co );
484 v3_sub( rba->co, co, delta );
485
486 float d2 = v3_length2(delta),
487 r = rba->inf.sphere.radius;
488
489 if( d2 <= r*r )
490 {
491 float d;
492
493 rb_ct *ct = buf;
494 if( d2 <= 0.0001f )
495 {
496 v3_sub( rba->co, rbb->co, delta );
497
498 /*
499 * some extra testing is required to find the best axis to push the
500 * object back outside the box. Since there isnt a clear seperating
501 * vector already, especially on really high aspect boxes.
502 */
503 float lx = v3_dot( rbb->right, delta ),
504 ly = v3_dot( rbb->up, delta ),
505 lz = v3_dot( rbb->forward, delta ),
506 px = rbb->bbx[1][0] - fabsf(lx),
507 py = rbb->bbx[1][1] - fabsf(ly),
508 pz = rbb->bbx[1][2] - fabsf(lz);
509
510 if( px < py && px < pz )
511 v3_muls( rbb->right, vg_signf(lx), ct->n );
512 else if( py < pz )
513 v3_muls( rbb->up, vg_signf(ly), ct->n );
514 else
515 v3_muls( rbb->forward, vg_signf(lz), ct->n );
516
517 v3_muladds( rba->co, ct->n, -r, ct->co );
518 ct->p = r;
519 }
520 else
521 {
522 d = sqrtf(d2);
523 v3_muls( delta, 1.0f/d, ct->n );
524 ct->p = r-d;
525 v3_add( co, rba->co, ct->co );
526 v3_muls( ct->co, 0.5f, ct->co );
527 }
528
529 ct->rba = rba;
530 ct->rbb = rbb;
531 return 1;
532 }
533
534 return 0;
535 }
536
537 static int rb_sphere_vs_sphere( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
538 {
539 v3f delta;
540 v3_sub( rba->co, rbb->co, delta );
541
542 float d2 = v3_length2(delta),
543 r = rba->inf.sphere.radius + rbb->inf.sphere.radius;
544
545 if( d2 < r*r )
546 {
547 float d = sqrtf(d2);
548
549 rb_ct *ct = buf;
550 v3_muls( delta, -1.0f/d, ct->n );
551
552 v3f p0, p1;
553 v3_muladds( rba->co, ct->n, rba->inf.sphere.radius, p0 );
554 v3_muladds( rbb->co, ct->n,-rbb->inf.sphere.radius, p1 );
555 v3_add( p0, p1, ct->co );
556 v3_muls( ct->co, 0.5f, ct->co );
557 ct->p = r-d;
558 ct->rba = rba;
559 ct->rbb = rbb;
560 return 1;
561 }
562
563 return 0;
564 }
565
566 static int rb_box_vs_sphere( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
567 {
568 return rb_sphere_vs_box( rbb, rba, buf );
569 }
570
571 static int rb_box_vs_box( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
572 {
573 /* TODO: Generating a stable quad manifold, lots of clipping */
574 return 0;
575 }
576
577 /*
578 * This function does not accept triangle as a dynamic object, it is assumed
579 * to always be static.
580 *
581 * The triangle is also assumed to be one sided for better detection
582 */
583 static int rb_sphere_vs_triangle( rigidbody *rba, v3f tri[3], rb_ct *buf )
584 {
585 v3f delta, co;
586
587 closest_on_triangle( rba->co, tri, co );
588 v3_sub( rba->co, co, delta );
589
590 float d2 = v3_length2( delta ),
591 r = rba->inf.sphere.radius;
592
593 if( d2 < r*r )
594 {
595 v3f ab, ac, tn;
596 v3_sub( tri[1], tri[0], ab );
597 v3_sub( tri[2], tri[0], ac );
598 v3_cross( ac, ab, tn );
599
600 if( v3_dot( delta, tn ) > 0.0f )
601 v3_muls( delta, -1.0f, delta );
602
603 float d = sqrtf(d2);
604
605 rb_ct *ct = buf;
606 v3_muls( delta, 1.0f/d, ct->n );
607 v3_copy( co, ct->co );
608 ct->p = r-d;
609 ct->rba = rba;
610 ct->rbb = &rb_static_null;
611 return 1;
612 }
613
614 return 0;
615 }
616
617
618 /*
619 * Generic functions
620 */
621
622 RB_DEPR
623 static int sphere_vs_triangle( v3f c, float r, v3f tri[3],
624 v3f co, v3f norm, float *p )
625 {
626 v3f delta;
627 closest_on_triangle( c, tri, co );
628
629 v3_sub( c, co, delta );
630
631
632 float d = v3_length2( delta );
633 if( d < r*r )
634 {
635 v3f ab, ac, tn;
636 v3_sub( tri[1], tri[0], ab );
637 v3_sub( tri[2], tri[0], ac );
638 v3_cross( ac, ab, tn );
639
640 if( v3_dot( delta, tn ) > 0.0f )
641 v3_muls( delta, -1.0f, delta );
642
643 vg_line_pt3( co, 0.05f, 0xff00ff00 );
644
645 d = sqrtf(d);
646 v3_muls( delta, 1.0f/d, norm );
647
648 *p = r-d;
649 return 1;
650 }
651
652 return 0;
653 }
654
655 #include "world.h"
656
657 static void rb_solver_reset(void)
658 {
659 rb_contact_count = 0;
660 }
661
662 static rb_ct *rb_global_ct(void)
663 {
664 return rb_contact_buffer + rb_contact_count;
665 }
666
667 static struct contact *rb_start_contact(void)
668 {
669 if( rb_contact_count == vg_list_size(rb_contact_buffer) )
670 {
671 vg_error( "rigidbody: too many contacts generated (%u)\n",
672 rb_contact_count );
673 return NULL;
674 }
675
676 return &rb_contact_buffer[ rb_contact_count ];
677 }
678
679 static void rb_commit_contact( struct contact *ct, float p )
680 {
681 ct->bias = -0.2f*k_rb_rate*vg_minf(0.0f,-p+0.04f);
682 rb_tangent_basis( ct->n, ct->t[0], ct->t[1] );
683
684 ct->norm_impulse = 0.0f;
685 ct->tangent_impulse[0] = 0.0f;
686 ct->tangent_impulse[1] = 0.0f;
687
688 rb_contact_count ++;
689 }
690
691 static void rb_build_manifold_terrain_sphere( rigidbody *rb )
692 {
693 u32 geo[256];
694 v3f tri[3];
695 int len = bh_select( &world.geo.bhtris, rb->bbx_world, geo, 256 );
696
697 for( int i=0; i<len; i++ )
698 {
699 u32 *ptri = &world.geo.indices[ geo[i]*3 ];
700
701 for( int j=0; j<3; j++ )
702 v3_copy( world.geo.verts[ptri[j]].co, tri[j] );
703
704 vg_line(tri[0],tri[1],0xff00ff00 );
705 vg_line(tri[1],tri[2],0xff00ff00 );
706 vg_line(tri[2],tri[0],0xff00ff00 );
707
708 v3f co, norm;
709 float p;
710
711 for( int j=0; j<2; j++ )
712 {
713 if( sphere_vs_triangle( rb->co, rb->inf.sphere.radius, tri,co,norm,&p))
714 {
715 struct contact *ct = rb_start_contact();
716
717 if( !ct )
718 return;
719
720 v3f p1;
721 v3_muladds( rb->co, norm, p, p1 );
722 vg_line( rb->co, p1, 0xffffffff );
723
724 ct->rba = rb;
725 v3_copy( co, ct->co );
726 v3_copy( norm, ct->n );
727 rb_commit_contact( ct, p );
728 }
729 }
730 }
731
732 }
733
734 RB_DEPR
735 static void rb_build_manifold_terrain( rigidbody *rb )
736 {
737 v3f *box = rb->bbx;
738 v3f pts[8];
739 float *p000 = pts[0], *p001 = pts[1], *p010 = pts[2], *p011 = pts[3],
740 *p100 = pts[4], *p101 = pts[5], *p110 = pts[6], *p111 = pts[7];
741
742 p000[0]=box[0][0];p000[1]=box[0][1];p000[2]=box[0][2];
743 p001[0]=box[0][0];p001[1]=box[0][1];p001[2]=box[1][2];
744 p010[0]=box[0][0];p010[1]=box[1][1];p010[2]=box[0][2];
745 p011[0]=box[0][0];p011[1]=box[1][1];p011[2]=box[1][2];
746
747 p100[0]=box[1][0];p100[1]=box[0][1];p100[2]=box[0][2];
748 p101[0]=box[1][0];p101[1]=box[0][1];p101[2]=box[1][2];
749 p110[0]=box[1][0];p110[1]=box[1][1];p110[2]=box[0][2];
750 p111[0]=box[1][0];p111[1]=box[1][1];p111[2]=box[1][2];
751
752 m4x3_mulv( rb->to_world, p000, p000 );
753 m4x3_mulv( rb->to_world, p001, p001 );
754 m4x3_mulv( rb->to_world, p010, p010 );
755 m4x3_mulv( rb->to_world, p011, p011 );
756 m4x3_mulv( rb->to_world, p100, p100 );
757 m4x3_mulv( rb->to_world, p101, p101 );
758 m4x3_mulv( rb->to_world, p110, p110 );
759 m4x3_mulv( rb->to_world, p111, p111 );
760
761 int count = 0;
762
763 for( int i=0; i<8; i++ )
764 {
765 float *point = pts[i];
766 struct contact *ct = rb_start_contact();
767
768 if( !ct )
769 return;
770
771 ct->rba = rb;
772
773 v3f surface;
774 v3_copy( point, surface );
775 surface[1] += 4.0f;
776
777 ray_hit hit;
778 hit.dist = INFINITY;
779 if( !ray_world( surface, (v3f){0.0f,-1.0f,0.0f}, &hit ))
780 continue;
781
782 v3_copy( hit.pos, surface );
783
784 float p = vg_minf( surface[1] - point[1], 1.0f );
785
786 if( p > 0.0f )
787 {
788 v3_copy( hit.normal, ct->n );
789 v3_add( point, surface, ct->co );
790 v3_muls( ct->co, 0.5f, ct->co );
791
792 rb_commit_contact( ct, p );
793 count ++;
794 if( count == 4 )
795 break;
796 }
797 }
798 }
799
800 /*
801 * Initializing things like tangent vectors
802 */
803
804 static void rb_presolve_contacts( rb_ct *buffer, int len )
805 {
806 for( int i=0; i<len; i++ )
807 {
808 rb_ct *ct = &buffer[i];
809 ct->bias = -0.2f * k_rb_rate * vg_minf(0.0f,-ct->p+0.04f);
810 rb_tangent_basis( ct->n, ct->t[0], ct->t[1] );
811
812 ct->norm_impulse = 0.0f;
813 ct->tangent_impulse[0] = 0.0f;
814 ct->tangent_impulse[1] = 0.0f;
815 ct->mass_total = 1.0f/(ct->rba->inv_mass + ct->rbb->inv_mass);
816
817 rb_debug_contact( ct );
818 }
819 }
820
821 /*
822 * Creates relative contact velocity vector, and offsets between each body
823 */
824 static void rb_rcv( rb_ct *ct, v3f rv, v3f da, v3f db )
825 {
826 rigidbody *rba = ct->rba,
827 *rbb = ct->rbb;
828
829 v3_sub( rba->co, ct->co, da );
830 v3_sub( rbb->co, ct->co, db );
831
832 v3f rva, rvb;
833 v3_cross( rba->w, da, rva );
834 v3_add( rba->v, rva, rva );
835
836 v3_cross( rbb->w, db, rvb );
837 v3_add( rbb->v, rvb, rvb );
838 v3_add( rva, rvb, rv );
839 }
840
841 /*
842 * Apply regular and angular velocity impulses to objects involved in contact
843 */
844 static void rb_standard_impulse( rb_ct *ct, v3f da, v3f db, v3f impulse )
845 {
846 rigidbody *rba = ct->rba,
847 *rbb = ct->rbb;
848
849 /* response */
850 v3_muladds( rba->v, impulse, ct->mass_total * rba->inv_mass, rba->v );
851 v3_muladds( rbb->v, impulse, ct->mass_total * rbb->inv_mass, rbb->v );
852
853 /* Angular velocity */
854 v3f wa, wb;
855 v3_cross( da, impulse, wa );
856 v3_cross( db, impulse, wb );
857 v3_muladds( rba->w, wa, ct->mass_total * rba->inv_mass, rba->w );
858 v3_muladds( rbb->w, wb, ct->mass_total * rbb->inv_mass, rbb->w );
859 }
860
861 /*
862 * One iteration to solve the contact constraint
863 */
864 static void rb_solve_contacts( rb_ct *buf, int len )
865 {
866 float k_friction = 0.1f;
867
868 /* Friction Impulse */
869 for( int i=0; i<len; i++ )
870 {
871 struct contact *ct = &buf[i];
872 rigidbody *rb = ct->rba;
873
874 v3f rv, da, db;
875 rb_rcv( ct, rv, da, db );
876
877 for( int j=0; j<2; j++ )
878 {
879 float f = k_friction * ct->norm_impulse,
880 vt = -v3_dot( rv, ct->t[j] );
881
882 float temp = ct->tangent_impulse[j];
883 ct->tangent_impulse[j] = vg_clampf( temp+vt, -f, f );
884 vt = ct->tangent_impulse[j] - temp;
885
886 v3f impulse;
887 v3_muls( ct->t[j], vt, impulse );
888 rb_standard_impulse( ct, da, db, impulse );
889 }
890 }
891
892 /* Normal Impulse */
893 for( int i=0; i<len; i++ )
894 {
895 struct contact *ct = &buf[i];
896 rigidbody *rba = ct->rba,
897 *rbb = ct->rbb;
898
899 v3f rv, da, db;
900 rb_rcv( ct, rv, da, db );
901
902 float vn = -v3_dot( rv, ct->n );
903 vn += ct->bias;
904
905 float temp = ct->norm_impulse;
906 ct->norm_impulse = vg_maxf( temp + vn, 0.0f );
907 vn = ct->norm_impulse - temp;
908
909 v3f impulse;
910 v3_muls( ct->n, vn, impulse );
911 rb_standard_impulse( ct, da, db, impulse );
912 }
913 }
914
915 /*
916 * The following ventures into not really very sophisticated at all maths
917 */
918
919 struct rb_angle_limit
920 {
921 rigidbody *rba, *rbb;
922 v3f axis;
923 float impulse, bias;
924 };
925
926 static int rb_angle_limit_force( rigidbody *rba, v3f va,
927 rigidbody *rbb, v3f vb,
928 float max )
929 {
930 v3f wva, wvb;
931 m3x3_mulv( rba->to_world, va, wva );
932 m3x3_mulv( rbb->to_world, vb, wvb );
933
934 float dt = v3_dot(wva,wvb)*0.999f,
935 ang = fabsf(dt);
936 ang = acosf( dt );
937 if( ang > max )
938 {
939 float correction = max-ang;
940
941 v3f axis;
942 v3_cross( wva, wvb, axis );
943
944 v4f rotation;
945 q_axis_angle( rotation, axis, -correction*0.25f );
946 q_mul( rotation, rba->q, rba->q );
947
948 q_axis_angle( rotation, axis, correction*0.25f );
949 q_mul( rotation, rbb->q, rbb->q );
950
951 return 1;
952 }
953
954 return 0;
955 }
956
957 static void rb_constraint_angle_limit( struct rb_angle_limit *limit )
958 {
959
960 }
961
962 RB_DEPR
963 static void rb_constraint_angle( rigidbody *rba, v3f va,
964 rigidbody *rbb, v3f vb,
965 float max, float spring )
966 {
967 v3f wva, wvb;
968 m3x3_mulv( rba->to_world, va, wva );
969 m3x3_mulv( rbb->to_world, vb, wvb );
970
971 float dt = v3_dot(wva,wvb)*0.999f,
972 ang = fabsf(dt);
973
974 v3f axis;
975 v3_cross( wva, wvb, axis );
976 v3_muladds( rba->w, axis, ang*spring*0.5f, rba->w );
977 v3_muladds( rbb->w, axis, -ang*spring*0.5f, rbb->w );
978
979 return;
980
981 /* TODO: convert max into the dot product value so we dont have to always
982 * evaluate acosf, only if its greater than the angle specified */
983 ang = acosf( dt );
984 if( ang > max )
985 {
986 float correction = max-ang;
987
988 v4f rotation;
989 q_axis_angle( rotation, axis, -correction*0.125f );
990 q_mul( rotation, rba->q, rba->q );
991
992 q_axis_angle( rotation, axis, correction*0.125f );
993 q_mul( rotation, rbb->q, rbb->q );
994 }
995 }
996
997 static void rb_relative_velocity( rigidbody *ra, v3f lca,
998 rigidbody *rb, v3f lcb, v3f rcv )
999 {
1000 v3f wca, wcb;
1001 m3x3_mulv( ra->to_world, lca, wca );
1002 m3x3_mulv( rb->to_world, lcb, wcb );
1003
1004 v3_sub( ra->v, rb->v, rcv );
1005
1006 v3f rcv_Ra, rcv_Rb;
1007 v3_cross( ra->w, wca, rcv_Ra );
1008 v3_cross( rb->w, wcb, rcv_Rb );
1009 v3_add( rcv_Ra, rcv, rcv );
1010 v3_sub( rcv, rcv_Rb, rcv );
1011 }
1012
1013 static void rb_constraint_position( rigidbody *ra, v3f lca,
1014 rigidbody *rb, v3f lcb )
1015 {
1016 /* C = (COa + Ra*LCa) - (COb + Rb*LCb) = 0 */
1017 v3f wca, wcb;
1018 m3x3_mulv( ra->to_world, lca, wca );
1019 m3x3_mulv( rb->to_world, lcb, wcb );
1020
1021 v3f delta;
1022 v3_add( wcb, rb->co, delta );
1023 v3_sub( delta, wca, delta );
1024 v3_sub( delta, ra->co, delta );
1025
1026 v3_muladds( ra->co, delta, 0.5f, ra->co );
1027 v3_muladds( rb->co, delta, -0.5f, rb->co );
1028
1029 v3f rcv;
1030 v3_sub( ra->v, rb->v, rcv );
1031
1032 v3f rcv_Ra, rcv_Rb;
1033 v3_cross( ra->w, wca, rcv_Ra );
1034 v3_cross( rb->w, wcb, rcv_Rb );
1035 v3_add( rcv_Ra, rcv, rcv );
1036 v3_sub( rcv, rcv_Rb, rcv );
1037
1038 float nm = 0.5f/(rb->inv_mass + ra->inv_mass);
1039
1040 float mass_a = 1.0f/ra->inv_mass,
1041 mass_b = 1.0f/rb->inv_mass,
1042 total_mass = mass_a+mass_b;
1043
1044 v3f impulse;
1045 v3_muls( rcv, 1.0f, impulse );
1046 v3_muladds( rb->v, impulse, mass_b/total_mass, rb->v );
1047 v3_cross( wcb, impulse, impulse );
1048 v3_add( impulse, rb->w, rb->w );
1049
1050 v3_muls( rcv, -1.0f, impulse );
1051 v3_muladds( ra->v, impulse, mass_a/total_mass, ra->v );
1052 v3_cross( wca, impulse, impulse );
1053 v3_add( impulse, ra->w, ra->w );
1054
1055 #if 0
1056 /*
1057 * this could be used for spring joints
1058 * its not good for position constraint
1059 */
1060 v3f impulse;
1061 v3_muls( delta, 0.5f*spring, impulse );
1062
1063 v3_add( impulse, ra->v, ra->v );
1064 v3_cross( wca, impulse, impulse );
1065 v3_add( impulse, ra->w, ra->w );
1066
1067 v3_muls( delta, -0.5f*spring, impulse );
1068
1069 v3_add( impulse, rb->v, rb->v );
1070 v3_cross( wcb, impulse, impulse );
1071 v3_add( impulse, rb->w, rb->w );
1072 #endif
1073 }
1074
1075 static void debug_sphere( m4x3f m, float radius, u32 colour )
1076 {
1077 v3f ly = { 0.0f, 0.0f, radius },
1078 lx = { 0.0f, radius, 0.0f },
1079 lz = { 0.0f, 0.0f, radius };
1080
1081 for( int i=0; i<16; i++ )
1082 {
1083 float t = ((float)(i+1) * (1.0f/16.0f)) * VG_PIf * 2.0f,
1084 s = sinf(t),
1085 c = cosf(t);
1086
1087 v3f py = { s*radius, 0.0f, c*radius },
1088 px = { s*radius, c*radius, 0.0f },
1089 pz = { 0.0f, s*radius, c*radius };
1090
1091 v3f p0, p1, p2, p3, p4, p5;
1092 m4x3_mulv( m, py, p0 );
1093 m4x3_mulv( m, ly, p1 );
1094 m4x3_mulv( m, px, p2 );
1095 m4x3_mulv( m, lx, p3 );
1096 m4x3_mulv( m, pz, p4 );
1097 m4x3_mulv( m, lz, p5 );
1098
1099 vg_line( p0, p1, colour == 0x00? 0xff00ff00: colour );
1100 vg_line( p2, p3, colour == 0x00? 0xff0000ff: colour );
1101 vg_line( p4, p5, colour == 0x00? 0xffff0000: colour );
1102
1103 v3_copy( py, ly );
1104 v3_copy( px, lx );
1105 v3_copy( pz, lz );
1106 }
1107 }
1108
1109 static void rb_debug( rigidbody *rb, u32 colour )
1110 {
1111 if( rb->type == k_rb_shape_box )
1112 {
1113 v3f *box = rb->bbx;
1114 vg_line_boxf_transformed( rb->to_world, rb->bbx, colour );
1115 }
1116 else if( rb->type == k_rb_shape_sphere )
1117 {
1118 debug_sphere( rb->to_world, rb->inf.sphere.radius, colour );
1119 }
1120 else if( rb->type == k_rb_shape_capsule )
1121 {
1122 m4x3f m0, m1;
1123 float h = rb->inf.capsule.height,
1124 r = rb->inf.capsule.radius;
1125
1126 m3x3_copy( rb->to_world, m0 );
1127 m3x3_copy( rb->to_world, m1 );
1128
1129 v3_muladds( rb->co, rb->up, -h*0.5f, m0[3] );
1130 v3_muladds( rb->co, rb->up, h*0.5f, m1[3] );
1131
1132 debug_sphere( m0, r, colour );
1133 debug_sphere( m1, r, colour );
1134 vg_line( m0[3], m1[3], colour );
1135 }
1136 }
1137
1138 /*
1139 * out penetration distance, normal
1140 */
1141 static int rb_point_in_body( rigidbody *rb, v3f pos, float *pen, v3f normal )
1142 {
1143 v3f local;
1144 m4x3_mulv( rb->to_local, pos, local );
1145
1146 if( local[0] > rb->bbx[0][0] && local[0] < rb->bbx[1][0] &&
1147 local[1] > rb->bbx[0][1] && local[1] < rb->bbx[1][1] &&
1148 local[2] > rb->bbx[0][2] && local[2] < rb->bbx[1][2] )
1149 {
1150 v3f area, com, comrel;
1151 v3_add( rb->bbx[0], rb->bbx[1], com );
1152 v3_muls( com, 0.5f, com );
1153
1154 v3_sub( rb->bbx[1], rb->bbx[0], area );
1155 v3_sub( local, com, comrel );
1156 v3_div( comrel, area, comrel );
1157
1158 int axis = 0;
1159 float max_mag = fabsf(comrel[0]);
1160
1161 if( fabsf(comrel[1]) > max_mag )
1162 {
1163 axis = 1;
1164 max_mag = fabsf(comrel[1]);
1165 }
1166 if( fabsf(comrel[2]) > max_mag )
1167 {
1168 axis = 2;
1169 max_mag = fabsf(comrel[2]);
1170 }
1171
1172 v3_zero( normal );
1173 normal[axis] = vg_signf(comrel[axis]);
1174
1175 if( normal[axis] < 0.0f )
1176 *pen = local[axis] - rb->bbx[0][axis];
1177 else
1178 *pen = rb->bbx[1][axis] - local[axis];
1179
1180 m3x3_mulv( rb->to_world, normal, normal );
1181 return 1;
1182 }
1183
1184 return 0;
1185 }
1186
1187 #if 0
1188 static void rb_build_manifold_rb_static( rigidbody *ra, rigidbody *rb_static )
1189 {
1190 v3f verts[8];
1191
1192 v3f a, b;
1193 v3_copy( ra->bbx[0], a );
1194 v3_copy( ra->bbx[1], b );
1195
1196 m4x3_mulv( ra->to_world, (v3f){ a[0], a[1], a[2] }, verts[0] );
1197 m4x3_mulv( ra->to_world, (v3f){ a[0], b[1], a[2] }, verts[1] );
1198 m4x3_mulv( ra->to_world, (v3f){ b[0], b[1], a[2] }, verts[2] );
1199 m4x3_mulv( ra->to_world, (v3f){ b[0], a[1], a[2] }, verts[3] );
1200 m4x3_mulv( ra->to_world, (v3f){ a[0], a[1], b[2] }, verts[4] );
1201 m4x3_mulv( ra->to_world, (v3f){ a[0], b[1], b[2] }, verts[5] );
1202 m4x3_mulv( ra->to_world, (v3f){ b[0], b[1], b[2] }, verts[6] );
1203 m4x3_mulv( ra->to_world, (v3f){ b[0], a[1], b[2] }, verts[7] );
1204
1205 vg_line_boxf_transformed( rb_static->to_world, rb_static->bbx, 0xff0000ff );
1206
1207 int count = 0;
1208
1209 for( int i=0; i<8; i++ )
1210 {
1211 if( ra->manifold_count == vg_list_size(ra->manifold) )
1212 return;
1213
1214 struct contact *ct = &ra->manifold[ ra->manifold_count ];
1215
1216 float p;
1217 v3f normal;
1218
1219 if( rb_point_in_body( rb_static, verts[i], &p, normal ))
1220 {
1221 v3_copy( normal, ct->n );
1222 v3_muladds( verts[i], ct->n, p*0.5f, ct->co );
1223 v3_sub( ct->co, ra->co, ct->delta );
1224
1225 vg_line_pt3( ct->co, 0.0125f, 0xffff00ff );
1226
1227 ct->bias = -0.2f * (1.0f/k_rb_delta) * vg_minf( 0.0f, -p+0.04f );
1228 rb_tangent_basis( ct->n, ct->t[0], ct->t[1] );
1229
1230 ct->norm_impulse = 0.0f;
1231 ct->tangent_impulse[0] = 0.0f;
1232 ct->tangent_impulse[1] = 0.0f;
1233
1234 ra->manifold_count ++;
1235 count ++;
1236 if( count == 4 )
1237 return;
1238 }
1239 }
1240 }
1241 #endif
1242
1243 /*
1244 * Capsule phyics
1245 */
1246
1247 RB_DEPR
1248 static void debug_capsule( m4x3f m, float height, float radius, u32 colour )
1249 {
1250 v3f last = { 0.0f, 0.0f, radius };
1251 m4x3f lower, upper;
1252 m3x3_copy( m, lower );
1253 m3x3_copy( m, upper );
1254 m4x3_mulv( m, (v3f){0.0f,-height*0.5f+radius,0.0f}, lower[3] );
1255 m4x3_mulv( m, (v3f){0.0f, height*0.5f-radius,0.0f}, upper[3] );
1256
1257 for( int i=0; i<16; i++ )
1258 {
1259 float t = ((float)(i+1) * (1.0f/16.0f)) * VG_PIf * 2.0f,
1260 s = sinf(t),
1261 c = cosf(t);
1262
1263 v3f p = { s*radius, 0.0f, c*radius };
1264
1265 v3f p0, p1;
1266 m4x3_mulv( lower, p, p0 );
1267 m4x3_mulv( lower, last, p1 );
1268 vg_line( p0, p1, colour );
1269
1270 m4x3_mulv( upper, p, p0 );
1271 m4x3_mulv( upper, last, p1 );
1272 vg_line( p0, p1, colour );
1273
1274 v3_copy( p, last );
1275 }
1276
1277 for( int i=0; i<4; i++ )
1278 {
1279 float t = ((float)(i) * (1.0f/4.0f)) * VG_PIf * 2.0f,
1280 s = sinf(t),
1281 c = cosf(t);
1282
1283 v3f p = { s*radius, 0.0f, c*radius };
1284
1285 v3f p0, p1;
1286 m4x3_mulv( lower, p, p0 );
1287 m4x3_mulv( upper, p, p1 );
1288 vg_line( p0, p1, colour );
1289
1290 m4x3_mulv( lower, (v3f){0.0f,-radius,0.0f}, p0 );
1291 m4x3_mulv( upper, (v3f){0.0f, radius,0.0f}, p1 );
1292 vg_line( p0, p1, colour );
1293 }
1294 }
1295
1296 /*
1297 * BVH implementation, this is ONLY for static rigidbodies, its to slow for
1298 * realtime use.
1299 */
1300
1301 static void rb_bh_expand_bound( void *user, boxf bound, u32 item_index )
1302 {
1303 rigidbody *rb = &((rigidbody *)user)[ item_index ];
1304 box_concat( bound, rb->bbx_world );
1305 }
1306
1307 static float rb_bh_centroid( void *user, u32 item_index, int axis )
1308 {
1309 rigidbody *rb = &((rigidbody *)user)[ item_index ];
1310 return (rb->bbx_world[axis][0] + rb->bbx_world[1][axis]) * 0.5f;
1311 }
1312
1313 static void rb_bh_swap( void *user, u32 ia, u32 ib )
1314 {
1315 rigidbody temp, *rba, *rbb;
1316 rba = &((rigidbody *)user)[ ia ];
1317 rbb = &((rigidbody *)user)[ ib ];
1318
1319 temp = *rba;
1320 *rba = *rbb;
1321 *rbb = temp;
1322 }
1323
1324 static void rb_bh_debug( void *user, u32 item_index )
1325 {
1326 rigidbody *rb = &((rigidbody *)user)[ item_index ];
1327 rb_debug( rb, 0xff00ffff );
1328 }
1329
1330 static bh_system bh_system_rigidbodies =
1331 {
1332 .expand_bound = rb_bh_expand_bound,
1333 .item_centroid = rb_bh_centroid,
1334 .item_swap = rb_bh_swap,
1335 .item_debug = rb_bh_debug,
1336 .cast_ray = NULL
1337 };
1338
1339 #endif /* RIGIDBODY_H */