Richard Boegli's CnC_Generals_Zero_Hour Fork WIP
This is documentation of Richard Boegil's Zero Hour Fork
 
Loading...
Searching...
No Matches
colmathobbtri.cpp
Go to the documentation of this file.
1/*
2** Command & Conquer Generals Zero Hour(tm)
3** Copyright 2025 Electronic Arts Inc.
4**
5** This program is free software: you can redistribute it and/or modify
6** it under the terms of the GNU General Public License as published by
7** the Free Software Foundation, either version 3 of the License, or
8** (at your option) any later version.
9**
10** This program is distributed in the hope that it will be useful,
11** but WITHOUT ANY WARRANTY; without even the implied warranty of
12** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13** GNU General Public License for more details.
14**
15** You should have received a copy of the GNU General Public License
16** along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/***********************************************************************************************
20 *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
21 ***********************************************************************************************
22 * *
23 * Project Name : WWMath *
24 * *
25 * $Archive:: /Commando/Code/wwmath/colmathobbtri.cpp $*
26 * *
27 * Author:: Greg Hjelstrom *
28 * *
29 * $Modtime:: 11/28/01 5:56p $*
30 * *
31 * $Revision:: 16 $*
32 * *
33 *---------------------------------------------------------------------------------------------*
34 * Functions: *
35 * obbtri_collision_separation_test -- test the projected extents for separation *
36 * obbtri_check_collision_axis -- project the obb and tri onto an arbitrary axis *
37 * obbtri_check_collision_cross_axis -- intersection check for a "cross-product" axis *
38 * obbtri_check_collision_basis_axis -- intersection check for a basis axis *
39 * obbtri_check_collision_normal_axis -- intersection check for the triangle normal *
40 * eval_side -- returns -1,0,+1 depending on the signe of val and side *
41 * obbtri_compute_contact_normal -- computes the normal of the collision *
42 * eval_A0_point -- contact point parameters for A0xEx *
43 * eval_A1_point -- contact point parameters for A1xEx *
44 * eval_A2_point -- contact point parameters for A2xEx *
45 * obbtri_compute_contact_point -- compute the contact point *
46 * CollisionMath::Collide -- collide an obbox into a triangle *
47 * obbtri_intersection_separation_test -- test the projected extents for intersection *
48 * obbtri_check_intersection_cross_axis -- intersection check for a "cross-product" axis *
49 * obbtri_check_intersection_basis_axis -- intersection check for a basis axis *
50 * obbtri_check_intersection_normal_axis -- intersection check for the triangle normal *
51 * CollisionMath::Intersection_Test -- Intersection check for an OBBox and a triangle *
52 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
53
54#include "colmath.h"
55#include "obbox.h"
56#include "tri.h"
57#include "wwdebug.h"
58
59
60/*
61** Separating Axes have to be rejected if their length is smaller than some epsilon.
62** Otherwise, erroneous results can be reported.
63*/
64#define AXISLEN_EPSILON2 WWMATH_EPSILON * WWMATH_EPSILON // squared length of a separating axis must be larger than this
65
66/*
67** Axes used in Box-Tri intersection tests
68** The axes of the box are A0,A1,A2. N is the normal of the triangle,
69** E0,E1,E2 are direction vectors for the edges of the triangle.
70** (the box axes are labeled A0,A1,A2 as a holdover from the obbox-obbox
71** collision code which this was derived from where there are two boxes
72** A and B)
73*/
74enum
75{
77 AXIS_N, // normal of the triangle
78 AXIS_A0, // first basis vector of the box
79 AXIS_A1, // second basis vector of the box
80 AXIS_A2, // third basis vector of the box
81
82 AXIS_A0E0, // box0 x edge0...
91};
92
93
94/******************************************************************************************
95
96 OBBox->Triangle collision
97
98 As with most of the collision detection functions, this code is based on the theorem
99 that given any two non-intersecting convex polyhedra, a separating plane/axis
100 can be found that will be defined by one of the face normals of one of the polyhedra
101 or the cross product of an edge from each polyhedra. The key optimization for
102 boxes is that many of these axes are the same. The normal to a face is the same
103 as the axis for four of the edges of the box, etc.
104
105 This test must be done using the tri normal, the three basis vectors
106 for the box, and three vectors defined by the cross products of the basis
107 and edge vectors. When testing the basis vectors, there will be two extents for
108 the tri (the other two vectors projected onto the axis being tested).
109 The appropriate extent must be used in the test (largest value which is pointing
110 towards the direction of the box). In addition, I've found that I must test axes
111 defined by the cross products of the move vector and the box axes. These tests
112 catch "false collisions" where the box passes very close to the triangle but does
113 not actually hit it.
114
115 Each axis test will use the following logic:
116 Project D onto the axis being used, it is the separation distance. If the
117 projection of the extent of the box + the projection of the extent of the
118 tri is greater than D*axis then the two intersect
119
120******************************************************************************************/
121
138{
139 BTCollisionStruct(const OBBoxClass &box,const Vector3 &move,const TriClass &tri,const Vector3 &trimove) :
140 Box(box),
141 Tri(tri),
142 BoxMove(move),
143 TriMove(trimove)
144 {
145 Reset();
146 }
147
148 void Reset(void)
149 {
150 StartBad = true; // true until an axis clears it
151 MaxFrac = -1.0f; // maximum move allowed so far (accept slightly negative but clamp to zero at end)
152 AxisId = INTERSECTION; // axis that allowed the longest move
153 Point = 0; // index of triangle point that was closest to the box
154 Side = 0; // side of the interval
155
156 Vector3::Subtract(*Tri.V[0],Box.Center,&D); // vector from center of box to vertex 0
157 Vector3::Subtract(BoxMove,TriMove,&Move); // move vector relative to stationary triangle
158
159 Vector3::Subtract(*Tri.V[1],*Tri.V[0],&E[0]);
160 Vector3::Subtract(*Tri.V[2],*Tri.V[0],&E[1]);
161 Vector3::Subtract(E[1],E[0],&E[2]);
162
163 A[0].Set(Box.Basis[0][0],Box.Basis[1][0],Box.Basis[2][0]);
164 A[1].Set(Box.Basis[0][1],Box.Basis[1][1],Box.Basis[2][1]);
165 A[2].Set(Box.Basis[0][2],Box.Basis[1][2],Box.Basis[2][2]);
166
167 Vector3::Cross_Product(E[0],E[1],&N);
168 }
169
170 bool StartBad; // Inital configuration is intersecting?
171 float MaxFrac; // Longest move allowed so far
172 int AxisId; // Last separating axis
173 int Point; // Index of the "closest" triangle point (or one of them)
174 int Side; // which side of the interval
175
176 int TestSide; // Was the axis we're working on flipped
177 int TestAxisId; // Axis 'id' we're working on
178 int TestPoint; // Index of the closest vertex
179 Vector3 TestAxis; // Axis we're working on
180
181 Vector3 D; // Vector from the center of the box to v0
182 Vector3 Move; // Move vector relative to stationary triangle
183 float AE[3][3]; // Dot products of the Basis vectors and edges
184 float AN[3]; // Dot products of the Basis vectors and the normal
185 Vector3 AxE[3][3]; // Cross produts of the Basis vectors and edges
186
187 Vector3 A[3]; // basis vectors for the box
188 Vector3 E[3]; // edge vectors for the triangle
189 Vector3 N; // normal (NOT normalized!!!)
190 Vector3 FinalD; // Vector from center of box to v0 at end of move
191
193 const TriClass & Tri;
196
197private:
198
199 // not implemented
201 BTCollisionStruct & operator = (const BTCollisionStruct &);
202};
203
204
205
206
207
208/***********************************************************************************************
209 * obbtri_collision_separation_test -- test the projected extents for separation *
210 * *
211 * Once the extents are projected onto the axis, this function contains *
212 * the logic that determines the allowed fraction. *
213 * *
214 * INPUT: *
215 * *
216 * OUTPUT: *
217 * true = objects are SEPARATED *
218 * *
219 * WARNINGS: *
220 * *
221 * HISTORY: *
222 * 4/8/99 GTH : Created. *
223 *=============================================================================================*/
224static inline bool obbtri_collision_separation_test
225(
226 BTCollisionStruct & context,
227 float lp,float leb0,float leb1
228)
229{
230 /*
231 ** - compute 'EPSILON' normalized to the length of the axis
232 ** - If (I'm no more than 'EPSILON' embedded in the polygon)
233 ** - not startbad
234 ** - If (I'm moving towards)
235 ** - fraction = How far I can move before embedding (can be negative if started embedded)
236 ** - If (I can take entire move)
237 ** - accept entire move
238 ** - Else If (I can move more than I could have before; *negative always fails!)
239 ** - update fraction
240 ** - Else
241 ** - Accept entire move since I'm not moving towards the polygon
242 */
243 float eps = 0.0f;
244 if (lp - leb0 <= 0.0f) {
245 eps = COLLISION_EPSILON * context.TestAxis.Length(); // trying to only compute epsilon if I have to
246 }
247
248 if (lp - leb0 > -eps) {
249 context.StartBad = false;
250 if (leb1 - leb0 > 0.0f) {
251 float frac = (lp-leb0)/(leb1-leb0);
252 if (frac >= 1.0f) {
253 /* moving toward but not hitting triangle */
254 context.AxisId = context.TestAxisId;
255 context.MaxFrac = 1.0f;
256 return true;
257 } else {
258 /* moving toward, hitting triangle */
259 if (frac > context.MaxFrac) {
260 context.MaxFrac = frac;
261 context.AxisId = context.TestAxisId;
262 context.Side = context.TestSide;
263 context.Point = context.TestPoint;
264 }
265 }
266 } else {
267 /* moving away or not moving */
268 context.AxisId = context.TestAxisId;
269 context.MaxFrac = 1.0f;
270 return true;
271 }
272 }
273 return false;
274}
275
276
277/***********************************************************************************************
278 * obbtri_check_collision_axis -- project the obb and tri onto an arbitrary axis *
279 * *
280 * projects the box and the triangle onto the given axis and calls *
281 * obbtri_separation_test. return true if separation was detected *
282 * *
283 * INPUT: *
284 * *
285 * OUTPUT: *
286 * true = objects are SEPARATED *
287 * *
288 * WARNINGS: *
289 * *
290 * HISTORY: *
291 * 4/8/99 GTH : Created. *
292 *=============================================================================================*/
293static inline bool obbtri_check_collision_axis(BTCollisionStruct & context)
294{
295 float dist; // separation along the axis
296 float axismove; // size of the move along the axis.
297 float leb0; // initial coordinate of the leading edge of the box
298 float leb1; // final coordinate of the leading edge of the box
299 float lp; // leading edge of the polygon.
300 float tmp; // temporary
301
302 dist = Vector3::Dot_Product(context.D,context.TestAxis);
303 axismove = Vector3::Dot_Product(context.Move,context.TestAxis);
304
305 // I want the axis centered at the box, pointing towards the triangle
306 if (dist < 0) {
307 dist = -dist;
308 axismove = -axismove;
309 context.TestAxis = -context.TestAxis;
310 context.TestSide = -1.0f;
311 } else {
312 context.TestSide = 1.0f;
313 }
314
315 // compute coordinates of the leading edge of the box at t0 and t1
316 leb0 = context.Box.Extent.X * WWMath::Fabs(Vector3::Dot_Product(context.TestAxis,context.A[0])) +
317 context.Box.Extent.Y * WWMath::Fabs(Vector3::Dot_Product(context.TestAxis,context.A[1])) +
318 context.Box.Extent.Z * WWMath::Fabs(Vector3::Dot_Product(context.TestAxis,context.A[2]));
319 leb1 = leb0 + axismove;
320
321 // compute coordinate of "leading edge of the triangle" relative to the box center.
322 lp = 0;
323 tmp = Vector3::Dot_Product(context.E[0],context.TestAxis); if (tmp < lp) lp = tmp;
324 tmp = Vector3::Dot_Product(context.E[1],context.TestAxis); if (tmp < lp) lp = tmp;
325 lp = dist + lp;
326
327 return obbtri_collision_separation_test(context,lp,leb0,leb1);
328}
329
330
331/***********************************************************************************************
332 * obbtri_check_collision_cross_axis -- projects obb and tri onto a "cross" axis *
333 * *
334 * Assumes that the axis given is one generated from a cross product of one of the edge and *
335 * basis vectors. In this case, the box extent can be optimized and only two triangle verts *
336 * need to be checked. *
337 * *
338 * INPUT: *
339 * *
340 * OUTPUT: *
341 * true = objects are SEPARATED *
342 * *
343 * WARNINGS: *
344 * *
345 * HISTORY: *
346 * 4/8/99 GTH : Created. *
347 *=============================================================================================*/
348static inline bool obbtri_check_collision_cross_axis
349(
350 BTCollisionStruct & context,
351 float dp,
352 int dpi,
353 float leb0
354)
355{
356 float p0; // distance from box center to vertex 0
357 float axismove; // size of the move along the axis.
358 float leb1; // final coordinate of the leading edge of the box
359 float lp; // leading edge of the polygon.
360
361 p0 = Vector3::Dot_Product(context.D,context.TestAxis);
362 axismove = Vector3::Dot_Product(context.Move,context.TestAxis);
363
364 // I want the axis centered at the box, pointing towards the triangle
365 if (p0 < 0) {
366 p0 = -p0;
367 axismove = -axismove;
368 dp = -dp;
369 context.TestAxis = -context.TestAxis;
370 context.TestSide = -1.0f;
371 } else {
372 context.TestSide = 1.0f;
373 }
374
375 // compute coordinates of the leading edge of the box at t1
376 leb1 = leb0 + axismove;
377
378 // compute coordinate of "leading edge of the triangle" relative to the box center.
379 lp = 0; context.TestPoint = 0;
380 if (dp < 0) { lp = dp; context.TestPoint = dpi; }
381 lp = p0 + lp;
382
383 return obbtri_collision_separation_test(context,lp,leb0,leb1);
384}
385
386
387/***********************************************************************************************
388 * obbtri_check_collision_basis_axis -- projects the obb and tri onto a basis axis *
389 * *
390 * Projects the box and triangle onto an axis that is assumed to be a basis *
391 * vector from the box. In this case, we can skip a dot-product and use the *
392 * corresponding extent of the box (which is passed in as leb0). *
393 * *
394 * INPUT: *
395 * *
396 * OUTPUT: *
397 * true = objects are SEPARATED *
398 * *
399 * WARNINGS: *
400 * *
401 * HISTORY: *
402 * 4/8/99 GTH : Created. *
403 *=============================================================================================*/
404static inline bool obbtri_check_collision_basis_axis
405(
406 BTCollisionStruct & context,
407 float leb0,
408 float dp1,
409 float dp2
410)
411{
412 float dist; // separation along the axis
413 float axismove; // size of the move along the axis.
414 float leb1; // final coordinate of the leading edge of the box
415 float lp; // leading edge of the polygon.
416
417 dist = Vector3::Dot_Product(context.D,context.TestAxis);
418 axismove = Vector3::Dot_Product(context.Move,context.TestAxis);
419
420 // we want the axis centered at the box, pointing towards the triangle
421 if (dist < 0) {
422 dist = -dist;
423 axismove = -axismove;
424 dp1 = -dp1;
425 dp2 = -dp2;
426 context.TestAxis = -context.TestAxis;
427 context.TestSide = -1.0f;
428 } else {
429 context.TestSide = 1.0f;
430 }
431
432 // this is the "optimization", leb0 = one of the extents
433 leb1 = leb0 + axismove;
434
435 // compute coordinate of "leading edge of the polygon" relative to the box center.
436 lp = 0; context.TestPoint = 0;
437 if (dp1 < lp) { lp = dp1; context.TestPoint = 1; }
438 if (dp2 < lp) { lp = dp2; context.TestPoint = 2; }
439 lp = dist + lp;
440
441 return obbtri_collision_separation_test(context,lp,leb0,leb1);
442}
443
444
445/***********************************************************************************************
446 * obbtri_check_collision_normal_axis -- project the box and tri onto the tri-normal *
447 * *
448 * Projects the box and triangle onto an axis that is assumed to be the normal *
449 * vector from the triangle. In this case, the triangle extents are zero. *
450 * *
451 * INPUT: *
452 * *
453 * OUTPUT: *
454 * true = objects are SEPARATED *
455 * *
456 * WARNINGS: *
457 * *
458 * HISTORY: *
459 * 4/8/99 GTH : Created. *
460 *=============================================================================================*/
461static inline bool obbtri_check_collision_normal_axis(BTCollisionStruct & context)
462{
463 float dist; // separation along the axis
464 float axismove; // size of the move along the axis.
465 float leb0; // initial coordinate of the leading edge of the box
466 float leb1; // final coordinate of the leading edge of the box
467 float lp; // leading edge of the polygon.
468
469 dist = Vector3::Dot_Product(context.D,context.TestAxis);
470 axismove = Vector3::Dot_Product(context.Move,context.TestAxis);
471
472 // we want the axis centered at the box, pointing towards the triangle
473 if (dist < 0) {
474 dist = -dist;
475 axismove = -axismove;
476 context.TestAxis = -context.TestAxis;
477 context.TestSide = -1.0f;
478 } else {
479 context.TestSide = 1.0f;
480 }
481
482 leb0 = context.Box.Extent.X * WWMath::Fabs(context.AN[0]) +
483 context.Box.Extent.Y * WWMath::Fabs(context.AN[1]) +
484 context.Box.Extent.Z * WWMath::Fabs(context.AN[2]);
485 leb1 = leb0 + axismove;
486 context.TestPoint = 0;
487 lp = dist; // this is the "optimization", don't have to find lp
488
489 return obbtri_collision_separation_test(context,lp,leb0,leb1);
490}
491
492/***********************************************************************************************
493 * eval_side -- returns -1,0,+1 depending on the sign of val and side *
494 * *
495 * INPUT: *
496 * *
497 * OUTPUT: *
498 * *
499 * WARNINGS: *
500 * *
501 * HISTORY: *
502 * 4/8/99 GTH : Created. *
503 *=============================================================================================*/
504static inline float eval_side(float val,int side)
505{
506 if (val > 0.0f) {
507 return side;
508 } else if (val < 0.0f) {
509 return -side;
510 } else {
511 return 0.0f;
512 }
513}
514
515/***********************************************************************************************
516 * obbtri_compute_contact_normal -- computes the normal of the collision *
517 * *
518 * INPUT: *
519 * *
520 * OUTPUT: *
521 * *
522 * WARNINGS: *
523 * *
524 * HISTORY: *
525 * 4/8/99 GTH : Created. *
526 *=============================================================================================*/
527static inline void obbtri_compute_contact_normal
528(
529 const BTCollisionStruct & context,
530 Vector3 * set_normal
531)
532{
533 switch(context.AxisId)
534 {
535 case INTERSECTION:
536// WWASSERT(0);
537 break;
538 case AXIS_N:
539 *set_normal = -context.Side * *context.Tri.N;
540 break;
541 case AXIS_A0:
542 *set_normal = -context.Side * context.A[0];
543 break;
544 case AXIS_A1:
545 *set_normal = -context.Side * context.A[1];
546 break;
547 case AXIS_A2:
548 *set_normal = -context.Side * context.A[2];
549 break;
550 case AXIS_A0E0:
551 *set_normal = -context.Side * context.AxE[0][0];
552 set_normal->Normalize();
553 break;
554 case AXIS_A1E0:
555 *set_normal = -context.Side * context.AxE[1][0];
556 set_normal->Normalize();
557 break;
558 case AXIS_A2E0:
559 *set_normal = -context.Side * context.AxE[2][0];
560 set_normal->Normalize();
561 break;
562 case AXIS_A0E1:
563 *set_normal = -context.Side * context.AxE[0][1];
564 set_normal->Normalize();
565 break;
566 case AXIS_A1E1:
567 *set_normal = -context.Side * context.AxE[1][1];
568 set_normal->Normalize();
569 break;
570 case AXIS_A2E1:
571 *set_normal = -context.Side * context.AxE[2][1];
572 set_normal->Normalize();
573 break;
574 case AXIS_A0E2:
575 *set_normal = -context.Side * context.AxE[0][2];
576 set_normal->Normalize();
577 break;
578 case AXIS_A1E2:
579 *set_normal = -context.Side * context.AxE[1][2];
580 set_normal->Normalize();
581 break;
582 case AXIS_A2E2:
583 *set_normal = -context.Side * context.AxE[2][2];
584 set_normal->Normalize();
585 break;
586 }
587 WWASSERT(set_normal->Length2() > 0.0f);
588}
589
590
591/***********************************************************************************************
592 * eval_A0_point -- contact point parameters for A0xEx *
593 * *
594 * INPUT: *
595 * *
596 * OUTPUT: *
597 * *
598 * WARNINGS: *
599 * *
600 * HISTORY: *
601 * 4/8/99 GTH : Created. *
602 *=============================================================================================*/
603static inline void eval_A0_point(const BTCollisionStruct & context,float * x,int edge)
604{
605 float yval,den;
606 Vector3 DxE;
607
608 x[1] = -eval_side(context.AE[2][edge],context.Side) * context.Box.Extent[1];
609 x[2] = eval_side(context.AE[1][edge],context.Side) * context.Box.Extent[2];
610 if (context.Point == 0) { yval = 0.0f; } else { yval = 1.0f; }
611
612 den = Vector3::Dot_Product(context.N,context.AxE[0][edge]);
613 if (WWMath::Fabs(den) > 0.0f) {
614
615 Vector3::Cross_Product(context.FinalD,context.E[edge],&DxE);
616 x[0] = Vector3::Dot_Product(context.N,DxE);
617 if (edge == 0) {
618 x[0] -= context.N.Length2() * yval;
619 } else {
620 x[0] += context.N.Length2() * yval;
621 }
622 x[0] -= Vector3::Dot_Product(context.N,context.AxE[1][edge]) * x[1];
623 x[0] -= Vector3::Dot_Product(context.N,context.AxE[2][edge]) * x[2];
624 x[0] /= den;
625
626 } else {
627
628 x[0] = 0.0f;
629
630 }
631}
632
633
634/***********************************************************************************************
635 * eval_A1_point -- contact point parameters for A1xEx *
636 * *
637 * INPUT: *
638 * *
639 * OUTPUT: *
640 * *
641 * WARNINGS: *
642 * *
643 * HISTORY: *
644 * 4/8/99 GTH : Created. *
645 *=============================================================================================*/
646static inline void eval_A1_point(const BTCollisionStruct & context,float * x,int edge)
647{
648 float yval,den;
649 Vector3 DxE;
650
651 x[0] = eval_side(context.AE[2][edge],context.Side) * context.Box.Extent[0];
652 x[2] = -eval_side(context.AE[0][edge],context.Side) * context.Box.Extent[2];
653 if (context.Point == 0) { yval = 0.0f; } else { yval = 1.0f; }
654
655 den = Vector3::Dot_Product(context.N,context.AxE[1][edge]);
656 if (WWMath::Fabs(den) > 0.0f) {
657
658 Vector3::Cross_Product(context.FinalD,context.E[edge],&DxE);
659 x[1] = Vector3::Dot_Product(context.N,DxE);
660 if (edge == 0) {
661 x[1] -= context.N.Length2() * yval;
662 } else {
663 x[1] += context.N.Length2() * yval;
664 }
665 x[1] -= Vector3::Dot_Product(context.N,context.AxE[0][edge]) * x[0];
666 x[1] -= Vector3::Dot_Product(context.N,context.AxE[2][edge]) * x[2];
667 x[1] /= den;
668
669 } else {
670
671 x[1] = 0.0f;
672
673 }
674}
675
676/***********************************************************************************************
677 * eval_A2_point -- contact point parameters for A2xEx *
678 * *
679 * INPUT: *
680 * *
681 * OUTPUT: *
682 * *
683 * WARNINGS: *
684 * *
685 * HISTORY: *
686 * 4/8/99 GTH : Created. *
687 *=============================================================================================*/
688static inline void eval_A2_point(const BTCollisionStruct & context,float * x,int edge)
689{
690 float yval,den;
691 Vector3 DxE;
692
693 x[0] = -eval_side(context.AE[1][edge],context.Side) * context.Box.Extent[0];
694 x[1] = eval_side(context.AE[0][edge],context.Side) * context.Box.Extent[1];
695 if (context.Point == 0) { yval = 0.0f; } else { yval = 1.0f; }
696
697 den = Vector3::Dot_Product(context.N,context.AxE[2][edge]);
698 if (WWMath::Fabs(den) > 0.0f) {
699
700 Vector3::Cross_Product(context.FinalD,context.E[edge],&DxE);
701 x[2] = Vector3::Dot_Product(context.N,DxE);
702 if (edge == 0) {
703 x[2] -= context.N.Length2() * yval;
704 } else {
705 x[2] += context.N.Length2() * yval;
706 }
707 x[2] -= Vector3::Dot_Product(context.N,context.AxE[0][edge]) * x[0];
708 x[2] -= Vector3::Dot_Product(context.N,context.AxE[1][edge]) * x[1];
709 x[2] /= den;
710
711 } else {
712
713 x[2] = 0.0f;
714
715 }
716}
717
718
719/***********************************************************************************************
720 * obbtri_compute_contact_point -- compute the contact point *
721 * *
722 * INPUT: *
723 * *
724 * OUTPUT: *
725 * *
726 * WARNINGS: *
727 * *
728 * HISTORY: *
729 * 4/8/99 GTH : Created. *
730 *=============================================================================================*/
731static inline void obbtri_compute_contact_point
732(
733 BTCollisionStruct & context,
734 CastResultStruct * result
735)
736{
737 int i;
738 float x[3];
739
740 if (context.AxisId >= AXIS_A0E0) {
741 Vector3 newc = context.Box.Center + result->Fraction * context.BoxMove;
742 Vector3 newv0 = *context.Tri.V[0] + result->Fraction * context.TriMove;
743 context.FinalD = newv0 - newc;
744 }
745
746 switch (context.AxisId)
747 {
748
749 case INTERSECTION:
750 WWASSERT(0);
751 return;
752
753 case AXIS_N: // part of the box is touching the face of the triangle
754
755 for (i = 0; i < 3; i++) {
756 x[i] = eval_side(context.AN[i],context.Side) * context.Box.Extent[i];
757 }
758 break;
759
760 case AXIS_A0: // part of the triangle is touching a face of the box
761 case AXIS_A1:
762 case AXIS_A2:
763
764 if (context.Point == 0) {
765 result->ContactPoint = *context.Tri.V[0];
766 } else if (context.Point == 1) {
767 result->ContactPoint = *context.Tri.V[1];
768 } else {
769 result->ContactPoint = *context.Tri.V[2];
770 }
771 Vector3::Add(result->ContactPoint,result->Fraction * context.TriMove,&(result->ContactPoint));
772 return;
773
774 case AXIS_A0E0: // one of the x-aligned edges of the box is contacting edge0
775 eval_A0_point(context,x,0);
776 break;
777
778 case AXIS_A0E1: // one of the x-aligned edges of the box is contacting edge1
779 eval_A0_point(context,x,1);
780 break;
781
782 case AXIS_A0E2: // one of the x-aligned edges of the box is contacting edge2
783 eval_A0_point(context,x,2);
784 break;
785
786 case AXIS_A1E0: // one of the y-aligned edges of the box is contacting edge0
787 eval_A1_point(context,x,0);
788 break;
789
790 case AXIS_A1E1: // one of the y-aligned edges of the box is contacting edge1
791 eval_A1_point(context,x,1);
792 break;
793
794 case AXIS_A1E2: // one of the y-aligned edges of the box is contacting edge2
795 eval_A1_point(context,x,2);
796 break;
797
798 case AXIS_A2E0: // one of the z-aligned edges of the box is contacting edge0
799 eval_A2_point(context,x,0);
800 break;
801
802 case AXIS_A2E1: // one of the z-aligned edges of the box is contacting edge1
803 eval_A2_point(context,x,1);
804 break;
805
806 case AXIS_A2E2: // one of the z-aligned edges of the box is contacting edge3
807 eval_A2_point(context,x,2);
808 break;
809
810 }
811
812 /*
813 ** In certain circumstances, the x's computed above are outside the size of
814 ** the box. I have tracked at least one of these cases to a situation where the
815 ** separating axis is the triangle normal but one of the AxE axes also lines up
816 ** with the normal. In this case, the Normal was 0,0,25 and the A0xE0 axis
817 ** was 0,0,5. When the fraction was calculated for both of these, they were
818 ** the same up to the six decimal places that MSVC will show me in the debugger.
819 ** However, the fraction computed for the 0,0,5 axis was larger by some very small
820 ** amount. This causes it to be used as the "separating axis". Looks like floating
821 ** point roundoff error to me. The problem is that since the axis was perpendicular
822 ** to the triangle, the "nearest-point" logic chose V0 which resulted in the
823 ** calculation for x[0] being way off. The equations for finding the contact point
824 ** in the AxE axis case assume that the axis is not normal to the triangle since
825 ** that should be handled in the simpler routine for the N separating axis...
826 ** Since I am at a loss for how to deal with this problem, I'm going to clamp all
827 ** of the x's to be within the box here...
828 */
829 if (x[0] > context.Box.Extent.X) {
830 x[0] = context.Box.Extent.X;
831 } else if (x[0] < -context.Box.Extent.X) {
832 x[0] = -context.Box.Extent.X;
833 }
834
835 if (x[1] > context.Box.Extent.Y) {
836 x[1] = context.Box.Extent.Y;
837 } else if (x[1] < -context.Box.Extent.Y) {
838 x[1] = -context.Box.Extent.Y;
839 }
840
841 if (x[2] > context.Box.Extent.Z) {
842 x[2] = context.Box.Extent.Z;
843 } else if (x[2] < -context.Box.Extent.Z) {
844 x[2] = -context.Box.Extent.Z;
845 }
846
847 /*
848 ** Now, compute the point
849 */
850 result->ContactPoint.X = context.Box.Center.X +
851 x[0]*context.A[0].X +
852 x[1]*context.A[1].X +
853 x[2]*context.A[2].X;
854
855 result->ContactPoint.Y = context.Box.Center.Y +
856 x[0]*context.A[0].Y +
857 x[1]*context.A[1].Y +
858 x[2]*context.A[2].Y;
859
860 result->ContactPoint.Z = context.Box.Center.Z +
861 x[0]*context.A[0].Z +
862 x[1]*context.A[1].Z +
863 x[2]*context.A[2].Z;
864
865 Vector3::Add(result->ContactPoint,result->Fraction * context.BoxMove,&(result->ContactPoint));
866}
867
868
869
870/***********************************************************************************************
871 * CollisionMath::Collide -- collide an obbox into a triangle *
872 * *
873 * INPUT: *
874 * *
875 * OUTPUT: *
876 * *
877 * WARNINGS: *
878 * *
879 * HISTORY: *
880 * 4/8/99 GTH : Created. *
881 *=============================================================================================*/
883(
884 const OBBoxClass & box,
885 const Vector3 & move,
886 const TriClass & tri,
887 const Vector3 & trimove,
888 CastResultStruct * result
889)
890{
892 float dp,leb0;
893 BTCollisionStruct context(box,move,tri,trimove);
894
895 /*
896 ** AXIS_N
897 */
898 context.TestAxis = context.N;
899 context.TestAxisId = AXIS_N;
900 context.AN[0] = Vector3::Dot_Product(context.A[0],context.N);
901 context.AN[1] = Vector3::Dot_Product(context.A[1],context.N);
902 context.AN[2] = Vector3::Dot_Product(context.A[2],context.N);
903 if (obbtri_check_collision_normal_axis(context)) goto exit;
904
905 /*
906 ** AXIS_A0
907 */
908 context.TestAxis = context.A[0];
909 context.TestAxisId = AXIS_A0;
910 context.AE[0][0] = Vector3::Dot_Product(context.A[0],context.E[0]);
911 context.AE[0][1] = Vector3::Dot_Product(context.A[0],context.E[1]);
912 if (obbtri_check_collision_basis_axis(context,box.Extent.X,context.AE[0][0],context.AE[0][1])) goto exit;
913
914 /*
915 ** AXIS_A1
916 */
917 context.TestAxis = context.A[1];
918 context.TestAxisId = AXIS_A1;
919 context.AE[1][0] = Vector3::Dot_Product(context.A[1],context.E[0]);
920 context.AE[1][1] = Vector3::Dot_Product(context.A[1],context.E[1]);
921 if (obbtri_check_collision_basis_axis(context,box.Extent.Y,context.AE[1][0],context.AE[1][1])) goto exit;
922
923 /*
924 ** AXIS_A2
925 */
926 context.TestAxis = context.A[2];
927 context.TestAxisId = AXIS_A2;
928 context.AE[2][0] = Vector3::Dot_Product(context.A[2],context.E[0]);
929 context.AE[2][1] = Vector3::Dot_Product(context.A[2],context.E[1]);
930 if (obbtri_check_collision_basis_axis(context,box.Extent.Z,context.AE[2][0],context.AE[2][1])) goto exit;
931
932 /*
933 ** AXIS_A0xE0
934 */
935 Vector3::Cross_Product(context.A[0],context.E[0],&context.AxE[0][0]);
936 context.TestAxis = context.AxE[0][0];
937 context.TestAxisId = AXIS_A0E0;
938 if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
939 dp = context.AN[0];
940 leb0 = box.Extent[1]*WWMath::Fabs(context.AE[2][0]) + box.Extent[2]*WWMath::Fabs(context.AE[1][0]);
941 if (obbtri_check_collision_cross_axis(context,dp,2,leb0)) goto exit;
942 }
943
944 /*
945 ** AXIS_A0xE1
946 */
947 Vector3::Cross_Product(context.A[0],context.E[1],&context.AxE[0][1]);
948 context.TestAxis = context.AxE[0][1];
949 context.TestAxisId = AXIS_A0E1;
950 if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
951 dp = -context.AN[0];
952 leb0 = box.Extent[1]*WWMath::Fabs(context.AE[2][1]) + box.Extent[2]*WWMath::Fabs(context.AE[1][1]);
953 if (obbtri_check_collision_cross_axis(context,dp,1,leb0)) goto exit;
954 }
955
956 /*
957 ** AXIS_A0xE2
958 */
959 Vector3::Cross_Product(context.A[0],context.E[2],&context.AxE[0][2]);
960 context.TestAxis = context.AxE[0][2];
961 context.TestAxisId = AXIS_A0E2;
962 context.AE[1][2] = Vector3::Dot_Product(context.A[1],context.E[2]);
963 context.AE[2][2] = Vector3::Dot_Product(context.A[2],context.E[2]);
964 if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
965 dp = -context.AN[0];
966 leb0 = box.Extent[1]*WWMath::Fabs(context.AE[2][2]) + box.Extent[2]*WWMath::Fabs(context.AE[1][2]);
967 if (obbtri_check_collision_cross_axis(context,dp,1,leb0)) goto exit;
968 }
969
970 /*
971 ** AXIS_A1xE0
972 */
973 Vector3::Cross_Product(context.A[1],context.E[0],&context.AxE[1][0]);
974 context.TestAxis = context.AxE[1][0];
975 context.TestAxisId = AXIS_A1E0;
976 if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
977 dp = context.AN[1];
978 leb0 = box.Extent[0]*WWMath::Fabs(context.AE[2][0]) + box.Extent[2]*WWMath::Fabs(context.AE[0][0]);
979 if (obbtri_check_collision_cross_axis(context,dp,2,leb0)) goto exit;
980 }
981
982 /*
983 ** AXIS_A1xE1
984 */
985 Vector3::Cross_Product(context.A[1],context.E[1],&context.AxE[1][1]);
986 context.TestAxis = context.AxE[1][1];
987 context.TestAxisId = AXIS_A1E1;
988 if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
989 dp = -context.AN[1];
990 leb0 = box.Extent[0]*WWMath::Fabs(context.AE[2][1]) + box.Extent[2]*WWMath::Fabs(context.AE[0][1]);
991 if (obbtri_check_collision_cross_axis(context,dp,1,leb0)) goto exit;
992 }
993
994 /*
995 ** AXIS_A1xE2
996 */
997 Vector3::Cross_Product(context.A[1],context.E[2],&context.AxE[1][2]);
998 context.TestAxis = context.AxE[1][2];
999 context.TestAxisId = AXIS_A1E2;
1000 context.AE[0][2] = Vector3::Dot_Product(context.A[0],context.E[2]);
1001 if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
1002 dp = -context.AN[1];
1003 leb0 = box.Extent[0]*WWMath::Fabs(context.AE[2][2]) + box.Extent[2]*WWMath::Fabs(context.AE[0][2]);
1004 if (obbtri_check_collision_cross_axis(context,dp,1,leb0)) goto exit;
1005 }
1006
1007 /*
1008 ** AXIS_A2xE0
1009 */
1010 Vector3::Cross_Product(context.A[2],context.E[0],&context.AxE[2][0]);
1011 context.TestAxis = context.AxE[2][0];
1012 context.TestAxisId = AXIS_A2E0;
1013 if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
1014 dp = context.AN[2];
1015 leb0 = box.Extent[0]*WWMath::Fabs(context.AE[1][0]) + box.Extent[1]*WWMath::Fabs(context.AE[0][0]);
1016 if (obbtri_check_collision_cross_axis(context,dp,2,leb0)) goto exit;
1017 }
1018
1019 /*
1020 ** AXIS_A2xE1
1021 */
1022 Vector3::Cross_Product(context.A[2],context.E[1],&context.AxE[2][1]);
1023 context.TestAxis = context.AxE[2][1];
1024 context.TestAxisId = AXIS_A2E1;
1025 if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
1026 dp = -context.AN[2];
1027 leb0 = box.Extent[0]*WWMath::Fabs(context.AE[1][1]) + box.Extent[1]*WWMath::Fabs(context.AE[0][1]);
1028 if (obbtri_check_collision_cross_axis(context,dp,1,leb0)) goto exit;
1029 }
1030
1031 /*
1032 ** AXIS_A2xE2
1033 */
1034 Vector3::Cross_Product(context.A[2],context.E[2],&context.AxE[2][2]);
1035 context.TestAxis = context.AxE[2][2];
1036 context.TestAxisId = AXIS_A2E2;
1037 if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
1038 dp = -context.AN[2];
1039 leb0 = box.Extent[0]*WWMath::Fabs(context.AE[1][2]) + box.Extent[1]*WWMath::Fabs(context.AE[0][2]);
1040 if (obbtri_check_collision_cross_axis(context,dp,1,leb0)) goto exit;
1041 }
1042
1043 /*
1044 ** Last ditch effort, check an axis based on the move vector
1045 */
1046 if (!context.StartBad) {
1047 context.TestPoint = context.Point;
1048 context.TestAxisId = context.AxisId;
1049
1050 Vector3::Cross_Product(context.Move,context.A[0],&context.TestAxis);
1051 if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
1052 if (obbtri_check_collision_axis(context)) goto exit;
1053 }
1054 Vector3::Cross_Product(context.Move,context.A[1],&context.TestAxis);
1055 if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
1056 if (obbtri_check_collision_axis(context)) goto exit;
1057 }
1058 Vector3::Cross_Product(context.Move,context.A[2],&context.TestAxis);
1059 if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
1060 if (obbtri_check_collision_axis(context)) goto exit;
1061 }
1062 }
1063
1064exit:
1065
1066#pragma message ("(gth) disabling an assert in obb->tri collision, investigate later\n")
1067#if 0
1068 WWASSERT((context.AxisId != INTERSECTION) || (context.StartBad));
1069#else
1070 if (context.AxisId == INTERSECTION) {
1071 context.StartBad = true;
1072 }
1073#endif
1074
1075 /*
1076 ** If the triangle and box are intersecting before the move, return that
1077 ** result.
1078 */
1079 if (context.StartBad) {
1080 result->StartBad = true;
1081 result->Fraction = 0.0f;
1082 result->Normal = *tri.N;
1084 return true;
1085 }
1086
1087 /*
1088 ** If the fraction allowed is basically equal to the fraction allowed by
1089 ** another polygon, try to pick the polygon which is least "edge-on" to the
1090 ** move.
1091 */
1092 if (context.MaxFrac < 0.0f) {
1093 context.MaxFrac = 0.0f;
1094 }
1095
1096 if ((context.MaxFrac < 1.0f) && (context.MaxFrac <= result->Fraction)) {
1097
1098 Vector3 normal;
1099 obbtri_compute_contact_normal(context,&normal);
1100
1101 if ( (WWMath::Fabs(context.MaxFrac - result->Fraction) > WWMATH_EPSILON) ||
1102 (Vector3::Dot_Product(normal,move) < Vector3::Dot_Product(result->Normal,move)) )
1103 {
1104 result->Normal = normal; //obbtri_compute_contact_normal(context,result);
1105 }
1106
1107 result->Fraction = context.MaxFrac;
1108
1109 if (result->ComputeContactPoint) {
1110 obbtri_compute_contact_point(context,result);
1111 }
1113 return true;
1114 }
1115
1116 return false;
1117}
1118
1119
1120/***********************************************************************************************
1121
1122 OBBox-Triangle Intersection
1123
1124 The following code implements a simple boolean intersection check. It uses the same
1125 algorithm as the collision function but can avoid some of the calculations. For a very
1126 simple implementation of this algorithm, see Oriented_Box_Intersects_Tri in obbox.h
1127
1128***********************************************************************************************/
1129
1140{
1141 BTIntersectStruct(const OBBoxClass &box,const TriClass &tri) :
1142 Box(box),
1143 Tri(tri)
1144 {
1145 Vector3::Subtract(*tri.V[0],box.Center,&D); // vector from center of box to vertex 0
1146 Vector3::Subtract(*tri.V[1],*tri.V[0],&E[0]);
1147 Vector3::Subtract(*tri.V[2],*tri.V[0],&E[1]);
1148 Vector3::Subtract(E[1],E[0],&E[2]);
1149
1150 A[0].Set(box.Basis[0][0],box.Basis[1][0],box.Basis[2][0]);
1151 A[1].Set(box.Basis[0][1],box.Basis[1][1],box.Basis[2][1]);
1152 A[2].Set(box.Basis[0][2],box.Basis[1][2],box.Basis[2][2]);
1153
1154 Vector3::Cross_Product(E[0],E[1],&N);
1155 }
1156
1157 Vector3 D; // Vector from the center of the box to v0
1158 float AE[3][3]; // Dot products of the Basis vectors and edges
1159 float AN[3]; // Dot products of the Basis vectors and the normal
1160 Vector3 AxE[3][3]; // Cross produts of the Basis vectors and edges
1161
1162 Vector3 A[3]; // basis vectors for the box
1163 Vector3 E[3]; // edge vectors for the triangle
1164 Vector3 N; // normal (NOT normalized!!!)
1165
1166 Vector3 TestAxis; // separating axis currently being tested
1167
1169 const TriClass & Tri;
1170
1171private:
1172
1173 // not implemented
1175 BTIntersectStruct & operator = (const BTIntersectStruct &);
1176};
1177
1178
1179/***********************************************************************************************
1180 * obbtri_intersection_separation_test -- test the projected extents for intersection *
1181 * *
1182 * Once the extents are projected onto the axis, this function contains *
1183 * the logic that determines whether the box and triangle intersect. *
1184 * *
1185 * INPUT: *
1186 * context - the BTIntersectStruct containing the data for this intersection test *
1187 * lp - the leading edge of the polygon projected onto the axis *
1188 * leb0 - the leading edge of the box projected onto the axis *
1189 * *
1190 * OUTPUT: *
1191 * true = objects are separated *
1192 * *
1193 * WARNINGS: *
1194 * *
1195 * HISTORY: *
1196 * 2/3/2000 gth : Created. *
1197 *=============================================================================================*/
1198static inline bool obbtri_intersection_separation_test
1199(
1200 BTIntersectStruct & context,
1201 float lp,
1202 float leb0
1203)
1204{
1205 /*
1206 ** Only compute the normalized epsilon if we need to.
1207 ** - compute 'EPSILON' normalized to the length of the axis
1208 ** - If (I'm no more than 'EPSILON' embedded in the polygon) then the box and tri are separated
1209 */
1210 float eps = 0.0f;
1211 if (lp - leb0 <= 0.0f) {
1212 eps = COLLISION_EPSILON * context.TestAxis.Length(); // trying to only compute epsilon if I have to
1213 }
1214
1215 return (lp - leb0 > -eps);
1216}
1217
1218
1219/***********************************************************************************************
1220 * obbtri_check_intersection_cross_axis -- intersection check for a "cross-product" axis *
1221 * *
1222 * axis being checked is a cross product between a triangle edge and a box basis vector *
1223 * *
1224 * INPUT: *
1225 * *
1226 * OUTPUT: *
1227 * *
1228 * WARNINGS: *
1229 * true = the objects are SEPARATED *
1230 * *
1231 * HISTORY: *
1232 * 5/4/99 GTH : Created. *
1233 *=============================================================================================*/
1234static inline bool obbtri_check_intersection_cross_axis
1235(
1236 BTIntersectStruct & context,
1237 float dp,
1238 float leb0
1239)
1240{
1241 float p0; // distance from box center to vertex 0
1242 float lp; // leading edge of the polygon.
1243
1244 p0 = Vector3::Dot_Product(context.D,context.TestAxis);
1245
1246 // I want the axis centered at the box, pointing towards the triangle
1247 if (p0 < 0) {
1248 context.TestAxis = -context.TestAxis;
1249 p0 = -p0;
1250 dp = -dp;
1251 }
1252
1253 // compute coordinate of "leading edge of the triangle" relative to the box center.
1254 lp = 0;
1255 if (dp < 0) { lp = dp; }
1256 lp = p0 + lp;
1257
1258 return obbtri_intersection_separation_test(context,lp,leb0);
1259}
1260
1261
1262/***********************************************************************************************
1263 * obbtri_check_intersection_basis_axis -- intersection check for a basis axis *
1264 * *
1265 * axis being checked is one of the basis vectors for the box *
1266 * *
1267 * INPUT: *
1268 * *
1269 * OUTPUT: *
1270 * true = the objects are SEPARATED *
1271 * *
1272 * WARNINGS: *
1273 * *
1274 * HISTORY: *
1275 * 5/4/99 GTH : Created. *
1276 *=============================================================================================*/
1277static inline bool obbtri_check_intersection_basis_axis
1278(
1279 BTIntersectStruct & context,
1280 float leb0,
1281 float dp1,
1282 float dp2
1283)
1284{
1285 float dist; // separation along the axis
1286 float lp; // leading edge of the polygon.
1287
1288 dist = Vector3::Dot_Product(context.D,context.TestAxis);
1289
1290 // we want the axis centered at the box, pointing towards the triangle
1291 if (dist < 0) {
1292 context.TestAxis = -context.TestAxis;
1293 dist = -dist;
1294 dp1 = -dp1;
1295 dp2 = -dp2;
1296 }
1297
1298 // compute coordinate of "leading edge of the polygon" relative to the box center.
1299 lp = 0;
1300 if (dp1 < lp) { lp = dp1; }
1301 if (dp2 < lp) { lp = dp2; }
1302 lp = dist + lp;
1303
1304 return obbtri_intersection_separation_test(context,lp,leb0);
1305}
1306
1307
1308/***********************************************************************************************
1309 * obbtri_check_intersection_normal_axis -- intersection check for the triangle normal *
1310 * *
1311 * axis being checked is the triangle's normal *
1312 * *
1313 * INPUT: *
1314 * *
1315 * OUTPUT: *
1316 * true = the objects are SEPARATED *
1317 * *
1318 * WARNINGS: *
1319 * *
1320 * HISTORY: *
1321 * 5/4/99 GTH : Created. *
1322 *=============================================================================================*/
1323static inline bool obbtri_check_intersection_normal_axis
1324(
1325 BTIntersectStruct & context
1326)
1327{
1328 float dist; // separation along the axis
1329 float leb0; // initial coordinate of the leading edge of the box
1330 float lp; // leading edge of the polygon.
1331
1332 dist = Vector3::Dot_Product(context.D,context.TestAxis);
1333
1334 // we want the axis centered at the box, pointing towards the triangle
1335 if (dist < 0) {
1336 context.TestAxis = -context.TestAxis;
1337 dist = -dist;
1338 }
1339
1340 leb0 = context.Box.Extent.X * WWMath::Fabs(context.AN[0]) +
1341 context.Box.Extent.Y * WWMath::Fabs(context.AN[1]) +
1342 context.Box.Extent.Z * WWMath::Fabs(context.AN[2]);
1343 lp = dist; // this is the "optimization", don't have to find lp
1344
1345 return obbtri_intersection_separation_test(context,lp,leb0);
1346}
1347
1348
1349/***********************************************************************************************
1350 * CollisionMath::Intersection_Test -- Intersection check for an OBBox and a triangle *
1351 * *
1352 * INPUT: *
1353 * box - obbox to be tested *
1354 * tri - triangle to be tested *
1355 * *
1356 * OUTPUT: *
1357 * true = objects INTERSECT *
1358 * *
1359 * WARNINGS: *
1360 * note that the other inline functions are "quick-reject" functions which return true when *
1361 * the objects are separated. *
1362 * *
1363 * HISTORY: *
1364 * 5/4/99 GTH : Created. *
1365 *=============================================================================================*/
1367{
1368 float dp,leb0;
1369 BTIntersectStruct context(box,tri);
1370
1371 /*
1372 ** AXIS_N
1373 */
1374 context.TestAxis = context.N;
1375 context.AN[0] = Vector3::Dot_Product(context.A[0],context.N);
1376 context.AN[1] = Vector3::Dot_Product(context.A[1],context.N);
1377 context.AN[2] = Vector3::Dot_Product(context.A[2],context.N);
1378 if (obbtri_check_intersection_normal_axis(context)) return false;
1379
1380 /*
1381 ** AXIS_A0
1382 */
1383 context.TestAxis = context.A[0];
1384 context.AE[0][0] = Vector3::Dot_Product(context.A[0],context.E[0]);
1385 context.AE[0][1] = Vector3::Dot_Product(context.A[0],context.E[1]);
1386 if (obbtri_check_intersection_basis_axis(context,box.Extent.X,context.AE[0][0],context.AE[0][1])) return false;
1387
1388 /*
1389 ** AXIS_A1
1390 */
1391 context.TestAxis = context.A[1];
1392 context.AE[1][0] = Vector3::Dot_Product(context.A[1],context.E[0]);
1393 context.AE[1][1] = Vector3::Dot_Product(context.A[1],context.E[1]);
1394 if (obbtri_check_intersection_basis_axis(context,box.Extent.Y,context.AE[1][0],context.AE[1][1])) return false;
1395
1396 /*
1397 ** AXIS_A2
1398 */
1399 context.TestAxis = context.A[2];
1400 context.AE[2][0] = Vector3::Dot_Product(context.A[2],context.E[0]);
1401 context.AE[2][1] = Vector3::Dot_Product(context.A[2],context.E[1]);
1402 if (obbtri_check_intersection_basis_axis(context,box.Extent.Z,context.AE[2][0],context.AE[2][1])) return false;
1403
1404 /*
1405 ** AXIS_A0xE0
1406 */
1407 Vector3::Cross_Product(context.A[0],context.E[0],&context.AxE[0][0]);
1408 context.TestAxis = context.AxE[0][0];
1409 if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
1410 dp = context.AN[0];
1411 leb0 = box.Extent[1]*WWMath::Fabs(context.AE[2][0]) + box.Extent[2]*WWMath::Fabs(context.AE[1][0]);
1412 if (obbtri_check_intersection_cross_axis(context,dp,leb0)) return false;
1413 }
1414
1415 /*
1416 ** AXIS_A0xE1
1417 */
1418 Vector3::Cross_Product(context.A[0],context.E[1],&context.AxE[0][1]);
1419 context.TestAxis = context.AxE[0][1];
1420 if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
1421 dp = -context.AN[0];
1422 leb0 = box.Extent[1]*WWMath::Fabs(context.AE[2][1]) + box.Extent[2]*WWMath::Fabs(context.AE[1][1]);
1423 if (obbtri_check_intersection_cross_axis(context,dp,leb0)) return false;
1424 }
1425
1426 /*
1427 ** AXIS_A0xE2
1428 */
1429 Vector3::Cross_Product(context.A[0],context.E[2],&context.AxE[0][2]);
1430 context.TestAxis = context.AxE[0][2];
1431 context.AE[1][2] = Vector3::Dot_Product(context.A[1],context.E[2]);
1432 context.AE[2][2] = Vector3::Dot_Product(context.A[2],context.E[2]);
1433 if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
1434 dp = -context.AN[0];
1435 leb0 = box.Extent[1]*WWMath::Fabs(context.AE[2][2]) + box.Extent[2]*WWMath::Fabs(context.AE[1][2]);
1436 if (obbtri_check_intersection_cross_axis(context,dp,leb0)) return false;
1437 }
1438
1439 /*
1440 ** AXIS_A1xE0
1441 */
1442 Vector3::Cross_Product(context.A[1],context.E[0],&context.AxE[1][0]);
1443 context.TestAxis = context.AxE[1][0];
1444 if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
1445 dp = context.AN[1];
1446 leb0 = box.Extent[0]*WWMath::Fabs(context.AE[2][0]) + box.Extent[2]*WWMath::Fabs(context.AE[0][0]);
1447 if (obbtri_check_intersection_cross_axis(context,dp,leb0)) return false;
1448 }
1449
1450 /*
1451 ** AXIS_A1xE1
1452 */
1453 Vector3::Cross_Product(context.A[1],context.E[1],&context.AxE[1][1]);
1454 context.TestAxis = context.AxE[1][1];
1455 if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
1456 dp = -context.AN[1];
1457 leb0 = box.Extent[0]*WWMath::Fabs(context.AE[2][1]) + box.Extent[2]*WWMath::Fabs(context.AE[0][1]);
1458 if (obbtri_check_intersection_cross_axis(context,dp,leb0)) return false;
1459 }
1460
1461 /*
1462 ** AXIS_A1xE2
1463 */
1464 Vector3::Cross_Product(context.A[1],context.E[2],&context.AxE[1][2]);
1465 context.TestAxis = context.AxE[1][2];
1466 context.AE[0][2] = Vector3::Dot_Product(context.A[0],context.E[2]);
1467 if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
1468 dp = -context.AN[1];
1469 leb0 = box.Extent[0]*WWMath::Fabs(context.AE[2][2]) + box.Extent[2]*WWMath::Fabs(context.AE[0][2]);
1470 if (obbtri_check_intersection_cross_axis(context,dp,leb0)) return false;
1471 }
1472
1473 /*
1474 ** AXIS_A2xE0
1475 */
1476 Vector3::Cross_Product(context.A[2],context.E[0],&context.AxE[2][0]);
1477 context.TestAxis = context.AxE[2][0];
1478 if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
1479 dp = context.AN[2];
1480 leb0 = box.Extent[0]*WWMath::Fabs(context.AE[1][0]) + box.Extent[1]*WWMath::Fabs(context.AE[0][0]);
1481 if (obbtri_check_intersection_cross_axis(context,dp,leb0)) return false;
1482 }
1483
1484 /*
1485 ** AXIS_A2xE1
1486 */
1487 Vector3::Cross_Product(context.A[2],context.E[1],&context.AxE[2][1]);
1488 context.TestAxis = context.AxE[2][1];
1489 if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
1490 dp = -context.AN[2];
1491 leb0 = box.Extent[0]*WWMath::Fabs(context.AE[1][1]) + box.Extent[1]*WWMath::Fabs(context.AE[0][1]);
1492 if (obbtri_check_intersection_cross_axis(context,dp,leb0)) return false;
1493 }
1494
1495 /*
1496 ** AXIS_A2xE2
1497 */
1498 Vector3::Cross_Product(context.A[2],context.E[2],&context.AxE[2][2]);
1499 context.TestAxis = context.AxE[2][2];
1500 if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
1501 dp = -context.AN[2];
1502 leb0 = box.Extent[0]*WWMath::Fabs(context.AE[1][2]) + box.Extent[1]*WWMath::Fabs(context.AE[0][2]);
1503 if (obbtri_check_intersection_cross_axis(context,dp,leb0)) return false;
1504 }
1505
1506 return true;
1507}
1508
1509
1510
#define WWASSERT
#define WWMATH_EPSILON
Definition wwmath.h:54
Vector3 Center
Definition aabox.h:123
Vector3 Extent
Definition aabox.h:124
static bool Collide(const LineSegClass &line, const AAPlaneClass &plane, CastResultStruct *result)
static bool Intersection_Test(const AABoxClass &box, const TriClass &tri)
Vector3 Extent
Definition obbox.h:114
Matrix3x3 Basis
Definition obbox.h:112
Vector3 Center
Definition obbox.h:113
Definition tri.h:61
const Vector3 * N
Definition tri.h:64
const Vector3 * V[3]
Definition tri.h:65
static WWINLINE float Dot_Product(const Vector3 &a, const Vector3 &b)
Definition vector3.h:293
float X
Definition vector3.h:90
WWINLINE float Length2(void) const
Definition vector3.h:469
float Z
Definition vector3.h:92
float Y
Definition vector3.h:91
WWINLINE float Length(void) const
Definition vector3.h:453
static WWINLINE void Subtract(const Vector3 &a, const Vector3 &b, Vector3 *c)
Definition vector3.h:576
void Normalize(void)
Definition vector3.h:417
static WWINLINE void Add(const Vector3 &a, const Vector3 &b, Vector3 *c)
Definition vector3.h:555
static WWINLINE void Cross_Product(const Vector3 &a, const Vector3 &b, Vector3 *result)
Definition vector3.h:374
static WWINLINE float Fabs(float val)
Definition wwmath.h:113
#define TRACK_COLLISION_OBBOX_TRI
Definition colmath.h:304
#define TRACK_COLLISION_OBBOX_TRI_HIT
Definition colmath.h:305
const float COLLISION_EPSILON
Definition colmath.h:65
@ AXIS_A1
@ AXIS_A1E0
@ AXIS_A2E0
@ AXIS_A1E2
@ AXIS_A0E1
@ AXIS_A2E1
@ INTERSECTION
@ AXIS_N
@ AXIS_A1E1
@ AXIS_A2E2
@ AXIS_A0
@ AXIS_A2
@ AXIS_A0E2
@ AXIS_A0E0
#define AXISLEN_EPSILON2
@ INTERSECTION
BTCollisionStruct(const OBBoxClass &box, const Vector3 &move, const TriClass &tri, const Vector3 &trimove)
const Vector3 * BoxMove
const AABoxClass * Box
const TriClass * Tri
const Vector3 * TriMove
BTIntersectStruct(const OBBoxClass &box, const TriClass &tri)
const TriClass & Tri
const OBBoxClass & Box
Vector3 ContactPoint
Definition castres.h:70
bool ComputeContactPoint
Definition castres.h:69
Vector3 Normal
Definition castres.h:66