c08baa536a5e55714d98fd7a39393d8e2098ed7f
[vg.git] / vg_rigidbody_collision.h
1 #pragma once
2 #include "vg_rigidbody.h"
3
4 #ifndef VG_MAX_CONTACTS
5 #define VG_MAX_CONTACTS 256
6 #endif
7
8 typedef struct rb_ct rb_ct;
9 static struct rb_ct{
10 rigidbody *rba, *rbb;
11 v3f co, n;
12 v3f t[2];
13 float p, bias, norm_impulse, tangent_impulse[2],
14 normal_mass, tangent_mass[2];
15
16 u32 element_id;
17
18 enum contact_type type;
19 }
20 rb_contact_buffer[VG_MAX_CONTACTS];
21 static int rb_contact_count = 0;
22
23 /*
24 * Contact generators
25 *
26 * These do not automatically allocate contacts, an appropriately sized
27 * buffer must be supplied. The function returns the size of the manifold
28 * which was generated.
29 *
30 * The values set on the contacts are: n, co, p, rba, rbb
31 */
32
33 /*
34 * By collecting the minimum(time) and maximum(time) pairs of points, we
35 * build a reduced and stable exact manifold.
36 *
37 * tx: time at point
38 * rx: minimum distance of these points
39 * dx: the delta between the two points
40 *
41 * pairs will only ammend these if they are creating a collision
42 */
43 typedef struct capsule_manifold capsule_manifold;
44 struct capsule_manifold{
45 f32 t0, t1;
46 f32 r0, r1;
47 v3f d0, d1;
48 };
49
50 /*
51 * Expand a line manifold with a new pair. t value is the time along segment
52 * on the oriented object which created this pair.
53 */
54 static void rb_capsule_manifold( v3f pa, v3f pb, f32 t, f32 r,
55 capsule_manifold *manifold ){
56 v3f delta;
57 v3_sub( pa, pb, delta );
58
59 if( v3_length2(delta) < r*r ){
60 if( t < manifold->t0 ){
61 v3_copy( delta, manifold->d0 );
62 manifold->t0 = t;
63 manifold->r0 = r;
64 }
65
66 if( t > manifold->t1 ){
67 v3_copy( delta, manifold->d1 );
68 manifold->t1 = t;
69 manifold->r1 = r;
70 }
71 }
72 }
73
74 static void rb_capsule_manifold_init( capsule_manifold *manifold ){
75 manifold->t0 = INFINITY;
76 manifold->t1 = -INFINITY;
77 }
78
79 static int rb_capsule__manifold_done( m4x3f mtx, rb_capsule *c,
80 capsule_manifold *manifold,
81 rb_ct *buf ){
82 v3f p0, p1;
83 v3_muladds( mtx[3], mtx[1], -c->h*0.5f+c->r, p0 );
84 v3_muladds( mtx[3], mtx[1], c->h*0.5f-c->r, p1 );
85
86 int count = 0;
87 if( manifold->t0 <= 1.0f ){
88 rb_ct *ct = buf;
89
90 v3f pa;
91 v3_muls( p0, 1.0f-manifold->t0, pa );
92 v3_muladds( pa, p1, manifold->t0, pa );
93
94 f32 d = v3_length( manifold->d0 );
95 v3_muls( manifold->d0, 1.0f/d, ct->n );
96 v3_muladds( pa, ct->n, -c->r, ct->co );
97
98 ct->p = manifold->r0 - d;
99 ct->type = k_contact_type_default;
100 count ++;
101 }
102
103 if( (manifold->t1 >= 0.0f) && (manifold->t0 != manifold->t1) ){
104 rb_ct *ct = buf+count;
105
106 v3f pa;
107 v3_muls( p0, 1.0f-manifold->t1, pa );
108 v3_muladds( pa, p1, manifold->t1, pa );
109
110 f32 d = v3_length( manifold->d1 );
111 v3_muls( manifold->d1, 1.0f/d, ct->n );
112 v3_muladds( pa, ct->n, -c->r, ct->co );
113
114 ct->p = manifold->r1 - d;
115 ct->type = k_contact_type_default;
116
117 count ++;
118 }
119
120 /*
121 * Debugging
122 */
123
124 #if 0
125 if( count == 2 )
126 vg_line( buf[0].co, buf[1].co, 0xff0000ff );
127 #endif
128
129 return count;
130 }
131
132 static int rb_capsule__sphere( m4x3f mtxA, rb_capsule *ca,
133 v3f coB, f32 rb, rb_ct *buf ){
134 f32 ha = ca->h,
135 ra = ca->r,
136 r = ra + rb;
137
138 v3f p0, p1;
139 v3_muladds( mtxA[3], mtxA[1], -ha*0.5f+ra, p0 );
140 v3_muladds( mtxA[3], mtxA[1], ha*0.5f-ra, p1 );
141
142 v3f c, delta;
143 closest_point_segment( p0, p1, coB, c );
144 v3_sub( c, coB, delta );
145 f32 d2 = v3_length2(delta);
146
147 if( d2 < r*r ){
148 f32 d = sqrtf(d2);
149
150 rb_ct *ct = buf;
151 v3_muls( delta, 1.0f/d, ct->n );
152 ct->p = r-d;
153
154 v3f p0, p1;
155 v3_muladds( c, ct->n, -ra, p0 );
156 v3_muladds( coB, ct->n, rb, p1 );
157 v3_add( p0, p1, ct->co );
158 v3_muls( ct->co, 0.5f, ct->co );
159 ct->type = k_contact_type_default;
160 return 1;
161 }
162 else return 0;
163 }
164
165 static int rb_capsule__capsule( m4x3f mtxA, rb_capsule *ca,
166 m4x3f mtxB, rb_capsule *cb, rb_ct *buf ){
167 f32 ha = ca->h,
168 hb = cb->h,
169 ra = ca->r,
170 rb = cb->r,
171 r = ra+rb;
172
173 v3f p0, p1, p2, p3;
174 v3_muladds( mtxA[3], mtxA[1], -ha*0.5f+ra, p0 );
175 v3_muladds( mtxA[3], mtxA[1], ha*0.5f-ra, p1 );
176 v3_muladds( mtxB[3], mtxB[1], -hb*0.5f+rb, p2 );
177 v3_muladds( mtxB[3], mtxB[1], hb*0.5f-rb, p3 );
178
179 capsule_manifold manifold;
180 rb_capsule_manifold_init( &manifold );
181
182 v3f pa, pb;
183 f32 ta, tb;
184 closest_segment_segment( p0, p1, p2, p3, &ta, &tb, pa, pb );
185 rb_capsule_manifold( pa, pb, ta, r, &manifold );
186
187 ta = closest_point_segment( p0, p1, p2, pa );
188 tb = closest_point_segment( p0, p1, p3, pb );
189 rb_capsule_manifold( pa, p2, ta, r, &manifold );
190 rb_capsule_manifold( pb, p3, tb, r, &manifold );
191
192 closest_point_segment( p2, p3, p0, pa );
193 closest_point_segment( p2, p3, p1, pb );
194 rb_capsule_manifold( p0, pa, 0.0f, r, &manifold );
195 rb_capsule_manifold( p1, pb, 1.0f, r, &manifold );
196
197 return rb_capsule__manifold_done( mtxA, ca, &manifold, buf );
198 }
199
200 /*
201 * Generates up to two contacts; optimised for the most stable manifold
202 */
203 static int rb_capsule__box( m4x3f mtxA, rb_capsule *ca,
204 m4x3f mtxB, m4x3f mtxB_inverse, boxf box,
205 rb_ct *buf ){
206 f32 h = ca->h, r = ca->r;
207
208 /*
209 * Solving this in symetric local space of the cube saves us some time and a
210 * couple branches when it comes to the quad stage.
211 */
212 v3f centroid;
213 v3_add( box[0], box[1], centroid );
214 v3_muls( centroid, 0.5f, centroid );
215
216 boxf bbx;
217 v3_sub( box[0], centroid, bbx[0] );
218 v3_sub( box[1], centroid, bbx[1] );
219
220 v3f pc, p0w, p1w, p0, p1;
221 v3_muladds( mtxA[3], mtxA[1], -h*0.5f+r, p0w );
222 v3_muladds( mtxA[3], mtxA[1], h*0.5f-r, p1w );
223
224 m4x3_mulv( mtxB_inverse, p0w, p0 );
225 m4x3_mulv( mtxB_inverse, p1w, p1 );
226 v3_sub( p0, centroid, p0 );
227 v3_sub( p1, centroid, p1 );
228 v3_add( p0, p1, pc );
229 v3_muls( pc, 0.5f, pc );
230
231 /*
232 * Finding an appropriate quad to collide lines with
233 */
234 v3f region;
235 v3_div( pc, bbx[1], region );
236
237 v3f quad[4];
238 if( (fabsf(region[0]) > fabsf(region[1])) &&
239 (fabsf(region[0]) > fabsf(region[2])) )
240 {
241 f32 px = vg_signf(region[0]) * bbx[1][0];
242 v3_copy( (v3f){ px, bbx[0][1], bbx[0][2] }, quad[0] );
243 v3_copy( (v3f){ px, bbx[1][1], bbx[0][2] }, quad[1] );
244 v3_copy( (v3f){ px, bbx[1][1], bbx[1][2] }, quad[2] );
245 v3_copy( (v3f){ px, bbx[0][1], bbx[1][2] }, quad[3] );
246 }
247 else if( fabsf(region[1]) > fabsf(region[2]) )
248 {
249 f32 py = vg_signf(region[1]) * bbx[1][1];
250 v3_copy( (v3f){ bbx[0][0], py, bbx[0][2] }, quad[0] );
251 v3_copy( (v3f){ bbx[1][0], py, bbx[0][2] }, quad[1] );
252 v3_copy( (v3f){ bbx[1][0], py, bbx[1][2] }, quad[2] );
253 v3_copy( (v3f){ bbx[0][0], py, bbx[1][2] }, quad[3] );
254 }
255 else
256 {
257 f32 pz = vg_signf(region[2]) * bbx[1][2];
258 v3_copy( (v3f){ bbx[0][0], bbx[0][1], pz }, quad[0] );
259 v3_copy( (v3f){ bbx[1][0], bbx[0][1], pz }, quad[1] );
260 v3_copy( (v3f){ bbx[1][0], bbx[1][1], pz }, quad[2] );
261 v3_copy( (v3f){ bbx[0][0], bbx[1][1], pz }, quad[3] );
262 }
263
264 capsule_manifold manifold;
265 rb_capsule_manifold_init( &manifold );
266
267 v3f c0, c1;
268 closest_point_aabb( p0, bbx, c0 );
269 closest_point_aabb( p1, bbx, c1 );
270
271 v3f d0, d1, da;
272 v3_sub( c0, p0, d0 );
273 v3_sub( c1, p1, d1 );
274 v3_sub( p1, p0, da );
275
276 /* TODO: ? */
277 v3_normalize(d0);
278 v3_normalize(d1);
279 v3_normalize(da);
280
281 if( v3_dot( da, d0 ) <= 0.01f )
282 rb_capsule_manifold( p0, c0, 0.0f, r, &manifold );
283
284 if( v3_dot( da, d1 ) >= -0.01f )
285 rb_capsule_manifold( p1, c1, 1.0f, r, &manifold );
286
287 for( i32 i=0; i<4; i++ ){
288 i32 i0 = i,
289 i1 = (i+1)%4;
290
291 v3f ca, cb;
292 f32 ta, tb;
293 closest_segment_segment( p0, p1, quad[i0], quad[i1], &ta, &tb, ca, cb );
294 rb_capsule_manifold( ca, cb, ta, r, &manifold );
295 }
296
297 /*
298 * Create final contacts based on line manifold
299 */
300 m3x3_mulv( mtxB, manifold.d0, manifold.d0 );
301 m3x3_mulv( mtxB, manifold.d1, manifold.d1 );
302 return rb_capsule__manifold_done( mtxA, ca, &manifold, buf );
303 }
304
305 static int rb_sphere__box( v3f coA, f32 ra,
306 m4x3f mtxB, m4x3f mtxB_inverse, boxf box,
307 rb_ct *buf ){
308 v3f co, delta;
309 closest_point_obb( coA, box, mtxB, mtxB_inverse, co );
310 v3_sub( coA, co, delta );
311
312 f32 d2 = v3_length2(delta);
313
314 if( d2 <= ra*ra ){
315 f32 d;
316
317 rb_ct *ct = buf;
318 if( d2 <= 0.0001f ){
319 v3f e, coB;
320 v3_sub( box[1], box[0], e );
321 v3_muls( e, 0.5f, e );
322 v3_add( box[0], e, coB );
323 v3_sub( coA, coB, delta );
324
325 /*
326 * some extra testing is required to find the best axis to push the
327 * object back outside the box. Since there isnt a clear seperating
328 * vector already, especially on really high aspect boxes.
329 */
330 f32 lx = v3_dot( mtxB[0], delta ),
331 ly = v3_dot( mtxB[1], delta ),
332 lz = v3_dot( mtxB[2], delta ),
333 px = e[0] - fabsf(lx),
334 py = e[1] - fabsf(ly),
335 pz = e[2] - fabsf(lz);
336
337 if( px < py && px < pz ) v3_muls( mtxB[0], vg_signf(lx), ct->n );
338 else if( py < pz ) v3_muls( mtxB[1], vg_signf(ly), ct->n );
339 else v3_muls( mtxB[2], vg_signf(lz), ct->n );
340
341 v3_muladds( coA, ct->n, -ra, ct->co );
342 ct->p = ra;
343 }
344 else{
345 d = sqrtf(d2);
346 v3_muls( delta, 1.0f/d, ct->n );
347 ct->p = ra-d;
348 v3_copy( co, ct->co );
349 }
350
351 ct->type = k_contact_type_default;
352 return 1;
353 }
354 else return 0;
355 }
356
357 static int rb_sphere__sphere( v3f coA, f32 ra,
358 v3f coB, f32 rb, rb_ct *buf ){
359 v3f delta;
360 v3_sub( coA, coB, delta );
361
362 f32 d2 = v3_length2(delta),
363 r = ra+rb;
364
365 if( d2 < r*r ){
366 f32 d = sqrtf(d2);
367
368 rb_ct *ct = buf;
369 v3_muls( delta, 1.0f/d, ct->n );
370
371 v3f p0, p1;
372 v3_muladds( coA, ct->n,-ra, p0 );
373 v3_muladds( coB, ct->n, rb, p1 );
374 v3_add( p0, p1, ct->co );
375 v3_muls( ct->co, 0.5f, ct->co );
376 ct->type = k_contact_type_default;
377 ct->p = r-d;
378 return 1;
379 }
380 else return 0;
381 }
382
383 static int rb_sphere__triangle( m4x3f mtxA, f32 r,
384 v3f tri[3], rb_ct *buf ){
385 v3f delta, co;
386 enum contact_type type = closest_on_triangle_1( mtxA[3], tri, co );
387 v3_sub( mtxA[3], co, delta );
388 f32 d2 = v3_length2( delta );
389
390 if( d2 <= r*r ){
391 rb_ct *ct = buf;
392
393 v3f ab, ac, tn;
394 v3_sub( tri[2], tri[0], ab );
395 v3_sub( tri[1], tri[0], ac );
396 v3_cross( ac, ab, tn );
397 v3_copy( tn, ct->n );
398
399 if( v3_length2( ct->n ) <= 0.00001f ){
400 #ifdef RIGIDBODY_CRY_ABOUT_EVERYTHING
401 vg_error( "Zero area triangle!\n" );
402 #endif
403 return 0;
404 }
405
406 v3_normalize( ct->n );
407
408 f32 d = sqrtf(d2);
409
410 v3_copy( co, ct->co );
411 ct->type = type;
412 ct->p = r-d;
413 return 1;
414 }
415
416 return 0;
417 }
418
419 static int rb_capsule__triangle( m4x3f mtxA, rb_capsule *c,
420 v3f tri[3], rb_ct *buf ){
421 v3f pc, p0w, p1w;
422 v3_muladds( mtxA[3], mtxA[1], -c->h*0.5f+c->r, p0w );
423 v3_muladds( mtxA[3], mtxA[1], c->h*0.5f-c->r, p1w );
424
425 capsule_manifold manifold;
426 rb_capsule_manifold_init( &manifold );
427
428 v3f v0, v1, n;
429 v3_sub( tri[1], tri[0], v0 );
430 v3_sub( tri[2], tri[0], v1 );
431 v3_cross( v0, v1, n );
432
433 if( v3_length2( n ) <= 0.00001f ){
434 #ifdef RIGIDBODY_CRY_ABOUT_EVERYTHING
435 vg_error( "Zero area triangle!\n" );
436 #endif
437 return 0;
438 }
439
440 v3_normalize( n );
441
442 #if 1
443 /* deep penetration recovery. for when we clip through the triangles. so its
444 * not very 'correct' */
445 f32 dist;
446 if( ray_tri( tri, p0w, mtxA[1], &dist, 1 ) ){
447 f32 l = c->h - c->r*2.0f;
448 if( (dist >= 0.0f) && (dist < l) ){
449 v3f co;
450 v3_muladds( p0w, mtxA[1], dist, co );
451 vg_line_point( co, 0.02f, 0xffffff00 );
452
453 v3f d0, d1;
454 v3_sub( p0w, co, d0 );
455 v3_sub( p1w, co, d1 );
456
457 f32 p = vg_minf( v3_dot( n, d0 ), v3_dot( n, d1 ) ) - c->r;
458
459 rb_ct *ct = buf;
460 ct->p = -p;
461 ct->type = k_contact_type_default;
462 v3_copy( n, ct->n );
463 v3_muladds( co, n, p, ct->co );
464
465 return 1;
466 }
467 }
468 #endif
469
470 v3f c0, c1;
471 closest_on_triangle_1( p0w, tri, c0 );
472 closest_on_triangle_1( p1w, tri, c1 );
473
474 v3f d0, d1, da;
475 v3_sub( c0, p0w, d0 );
476 v3_sub( c1, p1w, d1 );
477 v3_sub( p1w, p0w, da );
478
479 v3_normalize(d0);
480 v3_normalize(d1);
481 v3_normalize(da);
482
483 /* the two balls at the ends */
484 if( v3_dot( da, d0 ) <= 0.01f )
485 rb_capsule_manifold( p0w, c0, 0.0f, c->r, &manifold );
486 if( v3_dot( da, d1 ) >= -0.01f )
487 rb_capsule_manifold( p1w, c1, 1.0f, c->r, &manifold );
488
489 /* the edges to edges */
490 for( int i=0; i<3; i++ ){
491 int i0 = i,
492 i1 = (i+1)%3;
493
494 v3f ca, cb;
495 f32 ta, tb;
496 closest_segment_segment( p0w, p1w, tri[i0], tri[i1], &ta, &tb, ca, cb );
497 rb_capsule_manifold( ca, cb, ta, c->r, &manifold );
498 }
499
500 int count = rb_capsule__manifold_done( mtxA, c, &manifold, buf );
501 for( int i=0; i<count; i++ )
502 v3_copy( n, buf[i].n );
503
504 return count;
505 }
506
507 static int rb_global_has_space( void ){
508 if( rb_contact_count + 16 > vg_list_size(rb_contact_buffer) )
509 return 0;
510
511 return 1;
512 }
513
514 static rb_ct *rb_global_buffer( void ){
515 return &rb_contact_buffer[ rb_contact_count ];
516 }
517
518 /*
519 * -----------------------------------------------------------------------------
520 * Boolean shape overlap functions
521 * -----------------------------------------------------------------------------
522 */
523
524 /*
525 * Project AABB, and triangle interval onto axis to check if they overlap
526 */
527 static int rb_box_triangle_interval( v3f extent, v3f axis, v3f tri[3] ){
528 float
529
530 r = extent[0] * fabsf(axis[0]) +
531 extent[1] * fabsf(axis[1]) +
532 extent[2] * fabsf(axis[2]),
533
534 p0 = v3_dot( axis, tri[0] ),
535 p1 = v3_dot( axis, tri[1] ),
536 p2 = v3_dot( axis, tri[2] ),
537
538 e = vg_maxf(-vg_maxf(p0,vg_maxf(p1,p2)), vg_minf(p0,vg_minf(p1,p2)));
539
540 if( e > r ) return 0;
541 else return 1;
542 }
543
544 /*
545 * Seperating axis test box vs triangle
546 */
547 static int rb_box_triangle_sat( v3f extent, v3f center,
548 m4x3f to_local, v3f tri_src[3] ){
549 v3f tri[3];
550
551 for( int i=0; i<3; i++ ){
552 m4x3_mulv( to_local, tri_src[i], tri[i] );
553 v3_sub( tri[i], center, tri[i] );
554 }
555
556 v3f f0,f1,f2,n;
557 v3_sub( tri[1], tri[0], f0 );
558 v3_sub( tri[2], tri[1], f1 );
559 v3_sub( tri[0], tri[2], f2 );
560
561
562 v3f axis[9];
563 v3_cross( (v3f){1.0f,0.0f,0.0f}, f0, axis[0] );
564 v3_cross( (v3f){1.0f,0.0f,0.0f}, f1, axis[1] );
565 v3_cross( (v3f){1.0f,0.0f,0.0f}, f2, axis[2] );
566 v3_cross( (v3f){0.0f,1.0f,0.0f}, f0, axis[3] );
567 v3_cross( (v3f){0.0f,1.0f,0.0f}, f1, axis[4] );
568 v3_cross( (v3f){0.0f,1.0f,0.0f}, f2, axis[5] );
569 v3_cross( (v3f){0.0f,0.0f,1.0f}, f0, axis[6] );
570 v3_cross( (v3f){0.0f,0.0f,1.0f}, f1, axis[7] );
571 v3_cross( (v3f){0.0f,0.0f,1.0f}, f2, axis[8] );
572
573 for( int i=0; i<9; i++ )
574 if(!rb_box_triangle_interval( extent, axis[i], tri )) return 0;
575
576 /* u0, u1, u2 */
577 if(!rb_box_triangle_interval( extent, (v3f){1.0f,0.0f,0.0f}, tri )) return 0;
578 if(!rb_box_triangle_interval( extent, (v3f){0.0f,1.0f,0.0f}, tri )) return 0;
579 if(!rb_box_triangle_interval( extent, (v3f){0.0f,0.0f,1.0f}, tri )) return 0;
580
581 /* normal */
582 v3_cross( f0, f1, n );
583 if(!rb_box_triangle_interval( extent, n, tri )) return 0;
584
585 return 1;
586 }
587
588 /*
589 * -----------------------------------------------------------------------------
590 * Manifold
591 * -----------------------------------------------------------------------------
592 */
593
594 static int rb_manifold_apply_filtered( rb_ct *man, int len ){
595 int k = 0;
596
597 for( int i=0; i<len; i++ ){
598 rb_ct *ct = &man[i];
599
600 if( ct->type == k_contact_type_disabled )
601 continue;
602
603 man[k ++] = man[i];
604 }
605
606 return k;
607 }
608
609 /*
610 * Merge two contacts if they are within radius(r) of eachother
611 */
612 static void rb_manifold_contact_weld( rb_ct *ci, rb_ct *cj, float r ){
613 if( v3_dist2( ci->co, cj->co ) < r*r ){
614 cj->type = k_contact_type_disabled;
615 ci->p = (ci->p + cj->p) * 0.5f;
616
617 v3_add( ci->co, cj->co, ci->co );
618 v3_muls( ci->co, 0.5f, ci->co );
619
620 v3f delta;
621 v3_sub( ci->rba->co, ci->co, delta );
622
623 float c0 = v3_dot( ci->n, delta ),
624 c1 = v3_dot( cj->n, delta );
625
626 if( c0 < 0.0f || c1 < 0.0f ){
627 /* error */
628 ci->type = k_contact_type_disabled;
629 }
630 else{
631 v3f n;
632 v3_muls( ci->n, c0, n );
633 v3_muladds( n, cj->n, c1, n );
634 v3_normalize( n );
635 v3_copy( n, ci->n );
636 }
637 }
638 }
639
640 /*
641 *
642 */
643 static void rb_manifold_filter_joint_edges( rb_ct *man, int len, float r ){
644 for( int i=0; i<len-1; i++ ){
645 rb_ct *ci = &man[i];
646 if( ci->type != k_contact_type_edge )
647 continue;
648
649 for( int j=i+1; j<len; j++ ){
650 rb_ct *cj = &man[j];
651 if( cj->type != k_contact_type_edge )
652 continue;
653
654 rb_manifold_contact_weld( ci, cj, r );
655 }
656 }
657 }
658
659 /*
660 * Resolve overlapping pairs
661 */
662 static void rb_manifold_filter_pairs( rb_ct *man, int len, float r ){
663 for( int i=0; i<len-1; i++ ){
664 rb_ct *ci = &man[i];
665 int similar = 0;
666
667 if( ci->type == k_contact_type_disabled ) continue;
668
669 for( int j=i+1; j<len; j++ ){
670 rb_ct *cj = &man[j];
671
672 if( cj->type == k_contact_type_disabled ) continue;
673
674 if( v3_dist2( ci->co, cj->co ) < r*r ){
675 cj->type = k_contact_type_disabled;
676 v3_add( cj->n, ci->n, ci->n );
677 ci->p += cj->p;
678 similar ++;
679 }
680 }
681
682 if( similar ){
683 float n = 1.0f/((float)similar+1.0f);
684 v3_muls( ci->n, n, ci->n );
685 ci->p *= n;
686
687 if( v3_length2(ci->n) < 0.1f*0.1f )
688 ci->type = k_contact_type_disabled;
689 else
690 v3_normalize( ci->n );
691 }
692 }
693 }
694
695 /*
696 * Remove contacts that are facing away from A
697 */
698 static void rb_manifold_filter_backface( rb_ct *man, int len ){
699 for( int i=0; i<len; i++ ){
700 rb_ct *ct = &man[i];
701 if( ct->type == k_contact_type_disabled )
702 continue;
703
704 v3f delta;
705 v3_sub( ct->co, ct->rba->co, delta );
706
707 if( v3_dot( delta, ct->n ) > -0.001f )
708 ct->type = k_contact_type_disabled;
709 }
710 }
711
712 /*
713 * Filter out duplicate coplanar results. Good for spheres.
714 */
715 static void rb_manifold_filter_coplanar( rb_ct *man, int len, float w ){
716 for( int i=0; i<len; i++ ){
717 rb_ct *ci = &man[i];
718 if( ci->type == k_contact_type_disabled ||
719 ci->type == k_contact_type_edge )
720 continue;
721
722 float d1 = v3_dot( ci->co, ci->n );
723
724 for( int j=0; j<len; j++ ){
725 if( j == i )
726 continue;
727
728 rb_ct *cj = &man[j];
729 if( cj->type == k_contact_type_disabled )
730 continue;
731
732 float d2 = v3_dot( cj->co, ci->n ),
733 d = d2-d1;
734
735 if( fabsf( d ) <= w ){
736 cj->type = k_contact_type_disabled;
737 }
738 }
739 }
740 }
741
742 static void rb_debug_contact( rb_ct *ct ){
743 v3f p1;
744 v3_muladds( ct->co, ct->n, 0.05f, p1 );
745
746 if( ct->type == k_contact_type_default ){
747 vg_line_point( ct->co, 0.0125f, 0xff0000ff );
748 vg_line( ct->co, p1, 0xffffffff );
749 }
750 else if( ct->type == k_contact_type_edge ){
751 vg_line_point( ct->co, 0.0125f, 0xff00ffc0 );
752 vg_line( ct->co, p1, 0xffffffff );
753 }
754 }
755
756 static void rb_solver_reset(void){
757 rb_contact_count = 0;
758 }
759
760 static rb_ct *rb_global_ct(void){
761 return rb_contact_buffer + rb_contact_count;
762 }
763
764 static void rb_prepare_contact( rb_ct *ct ){
765 ct->bias = -k_phys_baumgarte * (vg.time_fixed_delta*3600.0f)
766 * vg_minf( 0.0f, -ct->p+k_penetration_slop );
767
768 v3_tangent_basis( ct->n, ct->t[0], ct->t[1] );
769 ct->norm_impulse = 0.0f;
770 ct->tangent_impulse[0] = 0.0f;
771 ct->tangent_impulse[1] = 0.0f;
772 }
773
774 /*
775 * calculate total move to depenetrate object from contacts.
776 * manifold should belong to ONE object only
777 */
778 static void rb_depenetrate( rb_ct *manifold, int len, v3f dt ){
779 v3_zero( dt );
780
781 for( int j=0; j<7; j++ ){
782 for( int i=0; i<len; i++ ){
783 rb_ct *ct = &manifold[i];
784
785 float resolved_amt = v3_dot( ct->n, dt ),
786 remaining = (ct->p-k_penetration_slop) - resolved_amt,
787 apply = vg_maxf( remaining, 0.0f ) * 0.4f;
788
789 v3_muladds( dt, ct->n, apply, dt );
790 }
791 }
792 }
793
794 /*
795 * Initializing things like tangent vectors
796 */
797 static void rb_presolve_contacts( rb_ct *buffer, int len ){
798 for( int i=0; i<len; i++ ){
799 rb_ct *ct = &buffer[i];
800 rb_prepare_contact( ct );
801
802 v3f ra, rb, raCn, rbCn, raCt, rbCt;
803 v3_sub( ct->co, ct->rba->co, ra );
804 v3_sub( ct->co, ct->rbb->co, rb );
805 v3_cross( ra, ct->n, raCn );
806 v3_cross( rb, ct->n, rbCn );
807
808 /* orient inverse inertia tensors */
809 v3f raCnI, rbCnI;
810 m3x3_mulv( ct->rba->iIw, raCn, raCnI );
811 m3x3_mulv( ct->rbb->iIw, rbCn, rbCnI );
812
813 ct->normal_mass = ct->rba->inv_mass + ct->rbb->inv_mass;
814 ct->normal_mass += v3_dot( raCn, raCnI );
815 ct->normal_mass += v3_dot( rbCn, rbCnI );
816 ct->normal_mass = 1.0f/ct->normal_mass;
817
818 for( int j=0; j<2; j++ ){
819 v3f raCtI, rbCtI;
820 v3_cross( ct->t[j], ra, raCt );
821 v3_cross( ct->t[j], rb, rbCt );
822 m3x3_mulv( ct->rba->iIw, raCt, raCtI );
823 m3x3_mulv( ct->rbb->iIw, rbCt, rbCtI );
824
825 ct->tangent_mass[j] = ct->rba->inv_mass + ct->rbb->inv_mass;
826 ct->tangent_mass[j] += v3_dot( raCt, raCtI );
827 ct->tangent_mass[j] += v3_dot( rbCt, rbCtI );
828 ct->tangent_mass[j] = 1.0f/ct->tangent_mass[j];
829 }
830 }
831 }
832
833 static void rb_contact_restitution( rb_ct *ct, float cr ){
834 v3f rv, ra, rb;
835 v3_sub( ct->co, ct->rba->co, ra );
836 v3_sub( ct->co, ct->rbb->co, rb );
837 rb_rcv( ct->rba, ct->rbb, ra, rb, rv );
838
839 float v = v3_dot( rv, ct->n );
840
841 if( v < -1.0f ){
842 ct->bias += -cr * v;
843 }
844 }
845
846 /*
847 * One iteration to solve the contact constraint
848 */
849 static void rb_solve_contacts( rb_ct *buf, int len ){
850 for( int i=0; i<len; i++ ){
851 rb_ct *ct = &buf[i];
852
853 v3f rv, ra, rb;
854 v3_sub( ct->co, ct->rba->co, ra );
855 v3_sub( ct->co, ct->rbb->co, rb );
856 rb_rcv( ct->rba, ct->rbb, ra, rb, rv );
857
858 /* Friction */
859 for( int j=0; j<2; j++ ){
860 float f = k_friction * ct->norm_impulse,
861 vt = v3_dot( rv, ct->t[j] ),
862 lambda = ct->tangent_mass[j] * -vt;
863
864 float temp = ct->tangent_impulse[j];
865 ct->tangent_impulse[j] = vg_clampf( temp + lambda, -f, f );
866 lambda = ct->tangent_impulse[j] - temp;
867
868 v3f impulse;
869 v3_muls( ct->t[j], lambda, impulse );
870 rb_linear_impulse( ct->rba, ra, impulse );
871
872 v3_muls( ct->t[j], -lambda, impulse );
873 rb_linear_impulse( ct->rbb, rb, impulse );
874 }
875
876 /* Normal */
877 rb_rcv( ct->rba, ct->rbb, ra, rb, rv );
878 float vn = v3_dot( rv, ct->n ),
879 lambda = ct->normal_mass * (-vn + ct->bias);
880
881 float temp = ct->norm_impulse;
882 ct->norm_impulse = vg_maxf( temp + lambda, 0.0f );
883 lambda = ct->norm_impulse - temp;
884
885 v3f impulse;
886 v3_muls( ct->n, lambda, impulse );
887 rb_linear_impulse( ct->rba, ra, impulse );
888
889 v3_muls( ct->n, -lambda, impulse );
890 rb_linear_impulse( ct->rbb, rb, impulse );
891 }
892 }
893