| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078 |
- /*
- ** Command & Conquer Renegade(tm)
- ** Copyright 2025 Electronic Arts Inc.
- **
- ** This program is free software: you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation, either version 3 of the License, or
- ** (at your option) any later version.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- /***********************************************************************************************
- *** 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 ***
- ***********************************************************************************************
- * *
- * Project Name : WWMath *
- * *
- * $Archive:: /Commando/Code/Tests/mathtest/obboxtest.cpp $*
- * *
- * Author:: Greg Hjelstrom *
- * *
- * $Modtime:: 12/06/00 9:33a $*
- * *
- * $Revision:: 8 $*
- * *
- *---------------------------------------------------------------------------------------------*
- * Functions: *
- * test_obb_tri -- performs some "hard-coded" obb-tri collision tests *
- * brute_force_cast_obb_tri -- binary-search method of finding the collision time for obb-tr *
- * brute_force_obb_tri_test -- collide random obb's into random tri's *
- * test_obb_obb -- performs some "hard-coded" obb-obb collision tests *
- * brute_force_cast_obb_obb -- brute force function to verify collision of two obb's *
- * brute_force_obb_obb_test -- collide random obb's together *
- * Test_OBBoxes -- run all of the obb-obb and obb-tri tests *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- #include "obboxtest.h"
- #include "output.h"
- #include "vector3.h"
- #include "tri.h"
- #include "obbox.h"
- #include "wwmath.h"
- #include "colmath.h"
- #include "p_timer.h"
- #include <stdio.h>
- #include <stdlib.h>
- #include <time.h>
- //#define MANUAL_DEBUGGING
- static Matrix3 _RotateZ45
- (
- (float)WWMATH_SQRT2/2.0f, -(float)WWMATH_SQRT2/2.0f, 0.0f,
- (float)WWMATH_SQRT2/2.0f, (float)WWMATH_SQRT2/2.0f, 0.0f,
- 0.0f, 0.0f, 1.0f
- );
- static Matrix3 _RotateZ90
- (
- 0.0f, -1.0f, 0.0f,
- 1.0f, 0.0f, 0.0f,
- 0.0f, 0.0f, 1.0f
- );
- /*********************************************************************
- **
- ** OBBoxTriTestClass
- ** Test Data for OBBox->Triangle collision
- **
- *********************************************************************/
- class OBBoxTriTestClass
- {
- public:
- OBBoxClass Box;
- Vector3 BoxMove;
- Vector3 V0;
- Vector3 V1;
- Vector3 V2;
- Vector3 N;
- TriClass Tri;
- float Fraction;
- bool StartBad;
-
- OBBoxTriTestClass
- (
- const Vector3 &c, // center of box
- const Vector3 &e, // extent of box
- const Matrix3 &b, // basis of box
- const Vector3 &m, // move for the box
- const Vector3 &v0, // v0 of triangle
- const Vector3 &v1, // v1 of triangle
- const Vector3 &v2, // v2 of triangle
- float frac, // expected fraction
- bool sol // expected start solid
- )
- {
- BoxMove = m;
- V0 = v0;
- V1 = v1;
- V2 = v2;
- Fraction = frac;
- StartBad = sol;
- /*
- ** Initialize the triangle
- */
- Tri.V[0] = &V0;
- Tri.V[1] = &V1;
- Tri.V[2] = &V2;
- Tri.N = & N;
- Tri.Compute_Normal();
- /*
- ** Initialize the box
- */
- Box.Center = c;
- Box.Extent = e;
- Box.Basis = b;
- }
- };
- OBBoxTriTestClass Test0
- (
- Vector3(0,0,0), // box starting at origin
- Vector3(2,1,1), // extent is 2 units along x, 1 y, 1 z
- Matrix3(1),
- Vector3(1,0,0), // moving 5 along x axis
- Vector3(6,-3,-1), // triangle crossing x and y extent but not colliding
- Vector3(8,-1,2),
- Vector3(9,0,-1),
- 1.0f,
- false
- );
- OBBoxTriTestClass Test1
- (
- Vector3(3,0,0),
- Vector3(1,2,1),
- Matrix3(1),
- Vector3(0,-2,0),
- Vector3(1,-3,0),
- Vector3(2,-3,5),
- Vector3(6,-3,1),
- 0.5f,
- false
- );
- OBBoxTriTestClass Test2
- (
- Vector3(-3.5,-1.5,0), // sweeping a 3x3 box along pos x and neg y
- Vector3(1.5,1.5,1.5),
- Matrix3(1),
- Vector3(4,-4,0),
- Vector3(-4,-4,-1), // into a polygon in y-z plane
- Vector3(-2,-4,5),
- Vector3(0,-4,1),
- 0.25f, // should only move 25%
- false
- );
- OBBoxTriTestClass Test3
- (
- Vector3(-3.5,-1.5,0) + 0.25f * Vector3(4,-4,0),
- Vector3(1.5,1.5,1.5), // starting at end of test2's move, should be 0.0 but not StartBad!
- Matrix3(1),
- Vector3(4,-4,0),
- Vector3(-4,-4,-1), // into a polygon in y-z plane
- Vector3(-2,-4,5),
- Vector3(0,-4,1),
- 0.0f,
- false
- );
- OBBoxTriTestClass Test4
- (
- Vector3(-3.5f,-1.5f,0), // Same as test 2
- Vector3(1.5f,1.5f,1.5f),
- Matrix3(1),
- Vector3(4,-4,0),
- Vector3(-9,-4,-1), // into a polygon in y-z plane *but* just barely not in the way
- Vector3(-8,-4,5),
- Vector3(-4.9f,-4,0),
- 1.0f, // should move 100%
- false
- );
- OBBoxTriTestClass Test5
- (
- Vector3(-3.5,-1.5,0), // Same as test 3 with box brushing polygon vertex.
- Vector3(1.5,1.5,1.5),
- Matrix3(1),
- Vector3(4,-4,0),
- Vector3(-9,-4,-1), // into a polygon in y-z plane just touching path of box
- Vector3(-8,-4,5),
- Vector3(-4,-4,0),
- 1.0f, // should move 100%
- false
- );
- OBBoxTriTestClass Test6
- (
- Vector3(-3.5f,-1.5f,0), // Same as test 3 with box brushing polygon vertex.
- Vector3(1.5f,1.5f,1.5f),
- Matrix3(1),
- Vector3(4,-4,0),
-
- Vector3(-9,-4,-1), // into a polygon in y-z plane just barely hitting it
- Vector3(-8,-4,5),
- Vector3(-3.999f,-4,0), // (-4,-4,0) would just "touch" (see test5)
-
- 0.25f, // should move 25%
- false
- );
- OBBoxTriTestClass Test7
- (
- Vector3(0,0,0), // This is a case where the box starts out intersecting
- Vector3(5,5,5),
- Matrix3(1),
- Vector3(4,4,0),
- Vector3(1,4,-1),
- Vector3(2,4,5),
- Vector3(5,4,0),
- 0.0f,
- true
- );
- OBBoxTriTestClass Test8
- (
- Vector3(-2.5,2,0), // center
- Vector3(1.5,1,1), // extent
- Matrix3(1), // basis
- Vector3(3,0,0), // move
-
- Vector3(1,2,0), // v0
- Vector3(3,4,5), // v1
- Vector3(4,5,-1), // v2
- 0.66666667f,
- false
- );
- OBBoxTriTestClass Test9
- (
- Vector3(0,0,0), // Box with diagonal y-z length of 1, rotated 45 about z
- Vector3(WWMATH_SQRT2/2.0,WWMATH_SQRT2/2.0,1),
- _RotateZ45,
- Vector3(4,0,0),
- Vector3(3,2,-1), // triangle blocking the move at x=3 (hitting back side)
- Vector3(3,0,1),
- Vector3(3,-2,-1),
- 0.5f, // hitting another box edge-to-face halfway through the move
- false
- );
- OBBoxTriTestClass * OBBoxTriTestCases[] =
- {
- &Test0,
- &Test1,
- &Test2,
- &Test3,
- &Test4,
- &Test5,
- &Test6,
- &Test7,
- &Test8,
- &Test9
- };
- /***********************************************************************************************
- * test_obb_tri -- performs some "hard-coded" obb-tri collision tests *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 4/8/99 GTH : Created. *
- *=============================================================================================*/
- void test_obb_tri(void)
- {
- Print_Title("Testing OBBox->Triangle collision.");
- /*
- ** Test the sweep function with a bunch of boxes and triangles
- */
- CastResultStruct result;
- result.ComputeContactPoint = true;
- int numtests = sizeof(OBBoxTriTestCases)/sizeof(OBBoxTriTestClass *);
- unsigned cycles;
- unsigned totalcycles = 0;
- // prime the cache
- OBBoxTriTestClass * testcase = OBBoxTriTestCases[9];
- cycles = Get_CPU_Clock();
- CollisionMath::Collide( testcase->Box,
- testcase->BoxMove,
- testcase->Tri,
- Vector3(0,0,0),
- &result);
- cycles = Get_CPU_Clock() - cycles;
- // now time and test the routine
- for (int i=0; i<numtests; i++) {
-
- testcase = OBBoxTriTestCases[i];
- result.Fraction = 1.0;
- result.StartBad = false;
- result.Normal.Set(0,0,0);
- cycles = Get_CPU_Clock();
- CollisionMath::Collide( testcase->Box,
- testcase->BoxMove,
- testcase->Tri,
- Vector3(0,0,0),
- &result);
-
- cycles = Get_CPU_Clock() - cycles;
- totalcycles += cycles;
- if ((WWMath::Fabs(testcase->Fraction - result.Fraction) > WWMATH_EPSILON) ||
- (testcase->StartBad != result.StartBad))
- {
- printf("test: %3d fraction: %8.6f cycles: %12d \tfailed!\n",i,result.Fraction,cycles);
- } else {
- printf("test: %3d fraction: %8.6f cycles: %12d \tpassed...\n",i,result.Fraction,cycles);
- }
- }
- printf("average cycles: %d\n",totalcycles / numtests);
- printf("\n");
- /*
- ** Test a box moving down the z-axis to a polygon, then moving along
- ** the x-axis along the surface of the polygon.
- */
- OBBoxClass testbox;
- Vector3 move;
- Vector3 v0,v1,v2,n;
- TriClass testtri;
- v0.Set(0,1,0);
- v1.Set(-1,-1,0);
- v2.Set(1,1,0);
-
- testtri.V[0] = &v0;
- testtri.V[1] = &v1;
- testtri.V[2] = &v2;
- testtri.N = &n;
- testtri.Compute_Normal();
- testbox.Center.Set(0,0,2.363f);
- testbox.Extent.Set(1,1,1);
- move.Set(0,0,-5.0f);
- CastResultStruct cres;
- cres.StartBad = 0;
- cres.Fraction = 1.0f;
- CollisionMath::Collide(testbox,move,testtri,Vector3(0,0,0),&cres);
- printf("fraction = %f\n",cres.Fraction);
- testbox.Center += cres.Fraction * move;
- move.Set(1.0f,1.0f,0.0f);
- cres.StartBad = 0;
- cres.Fraction = 1.0f;
- CollisionMath::Collide(testbox,move,testtri,Vector3(0,0,0),&cres);
- printf("fraction = %f\n",cres.Fraction);
- testbox.Center += cres.Fraction * move;
- /*
- ** Try to get a timing of Oriented_Box_Intersects_Tri versus
- ** CollisionMath::Intersect
- */
- const int REPEAT = 50;
- cycles = Get_CPU_Clock();
- for (int j=0;j<REPEAT;j++) {
- testcase = OBBoxTriTestCases[7];
- CollisionMath::Intersection_Test(testcase->Box,testcase->Tri);
- }
- cycles = Get_CPU_Clock() - cycles;
- printf("CollisionMath::Intersect - average cycles: %d\n",cycles / REPEAT);
- printf("\n");
- cycles = Get_CPU_Clock();
- for (j=0;j<REPEAT;j++) {
- testcase = OBBoxTriTestCases[7];
- Oriented_Box_Intersects_Tri(testcase->Box,testcase->Tri);
- }
- cycles = Get_CPU_Clock() - cycles;
- printf("Oriented_Box_Intersects_Tri - average cycles: %d\n",cycles / REPEAT);
- printf("\n");
- }
- /***********************************************************************************************
- * brute_force_cast_obb_tri -- binary-search method of finding the collision time for obb-tri *
- * *
- * This function doesn't really work in the general case. Only when the endpoint of the move *
- * is guaranteed to be inside the triangle *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 4/8/99 GTH : Created. *
- *=============================================================================================*/
- float brute_force_cast_obb_tri
- (
- const OBBoxClass & box,
- const Vector3 & move,
- const TriClass & tri
- )
- {
- float istart = 0.0f;
- float iend = 1.0f;
-
- while (iend - istart > WWMATH_EPSILON/2.0f) {
- float icenter = (iend + istart) / 2.0f;
- OBBoxClass testbox = box;
- testbox.Center = box.Center + icenter*move;
- if (Oriented_Box_Intersects_Tri(testbox,tri)) {
- iend = icenter;
- } else {
- istart = icenter;
- }
- }
- return (iend + istart) / 2.0f;
- }
- /***********************************************************************************************
- * brute_force_obb_tri_test -- collide random obb's into random tri's *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 4/8/99 GTH : Created. *
- *=============================================================================================*/
- void brute_force_obb_tri_test(int test_count)
- {
- Print_Title("Brute Force Testing OBBox->Tri collision.");
-
- Vector3 v[3];
- Vector3 n;
- OBBoxClass box;
- TriClass tri;
- Vector3 move;
- tri.V[0] = &v[0];
- tri.V[1] = &v[1];
- tri.V[2] = &v[2];
- tri.N = &n;
-
- int fail_count = 0;
- int startbad_count = 0;
- int startbad_fail_count = 0;
- int bad_points = 0;
- float min_fraction = 1.0f;
- float max_fraction = 0.0f;
- float avg_fraction = 0.0f;
- float avg_fraction_error = 0.0f;
- int fraction_error_count = 0;
- float max_error = 0.0f;
- for (int i=0; i<test_count; i++) {
- // v0 is always in positive quadrant
- v[0].X = WWMath::Random_Float(0,5);
- v[0].Y = WWMath::Random_Float(0,5);
- v[0].Z = WWMath::Random_Float(0,5);
- // v1 is always +x,+y,-z
- v[1].X = WWMath::Random_Float(0,5);
- v[1].Y = WWMath::Random_Float(0,5);
- v[1].Z = -WWMath::Random_Float(0,5);
- // v2 is always -x,-y,-z
- v[2].X = -WWMath::Random_Float(0,5);
- v[2].Y = -WWMath::Random_Float(0,5);
- v[2].Z = -WWMath::Random_Float(0,5);
- tri.Compute_Normal();
- // make a random box
- box.Init_Random(0.25f,3.0f);
- // put it in a random position in a 20x20x20 cube
- box.Center.X = WWMath::Random_Float(-10.0f,10.0f);
- box.Center.Y = WWMath::Random_Float(-10.0f,10.0f);
- box.Center.Z = WWMath::Random_Float(-10.0f,10.0f);
- // make a move vector that will move the box's center to the centroid of the tri
- Vector3 new_center;
- new_center.X = (v[0].X + v[1].X + v[2].X) / 3.0f;
- new_center.Y = (v[0].Y + v[1].Y + v[2].Y) / 3.0f;
- new_center.Z = (v[0].Z + v[1].Z + v[2].Z) / 3.0f;
- move = new_center - box.Center;
-
- // sweep box into tri!
- CastResultStruct result;
- result.ComputeContactPoint = true;
- CollisionMath::Collide(box,move,tri,Vector3(0,0,0),&result);
- // if they started out intersecting, this test doesn't count
- if (result.StartBad) {
- startbad_count++;
- if (!Oriented_Box_Intersects_Tri(box,tri)) {
- startbad_fail_count++;
- printf("False startbad!");
- }
- }
- // if they were intersecting, never mind
- if (!result.StartBad) {
- printf(".");
- bool success = true;
- // add the fraction into the total so we get an idea
- // how far our tests are going (hopefully a good mix)
- avg_fraction += result.Fraction;
- if (result.Fraction < min_fraction) min_fraction = result.Fraction;
- if (result.Fraction > max_fraction) max_fraction = result.Fraction;
- // verify that the fraction is correct
- float realfrac = brute_force_cast_obb_tri(box,move,tri);
- if (fabs(realfrac - result.Fraction) > WWMATH_EPSILON) {
- success = false;
- float error = fabs(realfrac - result.Fraction);
- avg_fraction_error += error;
- fraction_error_count++;
- if (error > max_error) max_error = error;
- }
- // verify that they are not intersecting at the end of the move
- // if the allowed move is smaller than epsilon, we skip this and don't move
- if (result.Fraction > WWMATH_EPSILON) {
- OBBoxClass box2 = box;
- CastResultStruct second_result;
- box2.Center += /*0.9999f **/ result.Fraction * move;
- CollisionMath::Collide(box2,move,tri,Vector3(0,0,0),&second_result);
- if (second_result.StartBad) success = false;
- if ((result.Fraction < 1.0f) && (second_result.Fraction > 0.01f)) success = false;
- }
- // if something failed, do the test again to let the programmer step through...
- if (!success) {
- fail_count++;
- CastResultStruct redo_result;
- redo_result.ComputeContactPoint = true;
- CollisionMath::Collide(box,move,tri,Vector3(0,0,0),&redo_result);
- }
- }
- }
- printf("\n");
- int passes = test_count - (startbad_fail_count + fail_count);
- printf("Passed %d tests out of %d tests.\n",passes,test_count);
- printf("StartBad tests: %d failures: %d\n",startbad_count,startbad_fail_count);
- if (fraction_error_count > 0) {
- avg_fraction_error /= (float)fraction_error_count;
- }
- avg_fraction /= (float)(test_count - startbad_count);
- printf("Largest Fraction: %f\n",max_fraction);
- printf("Smallest Fraction: %f\n",min_fraction);
- printf("Average Fraction: %f\n",avg_fraction);
- printf("Average Error: %f\n",avg_fraction_error);
- printf("Biggest Error: %f\n",max_error);
- }
- /*********************************************************************
- **
- ** OBBoxTestClass
- ** Data for testing OBBox->OBBox collision detection
- **
- *********************************************************************/
- class OBBoxTestClass
- {
- public:
- OBBoxClass Box0;
- Vector3 Move0;
- OBBoxClass Box1;
- Vector3 Move1;
- float Fraction;
- bool StartBad;
-
- OBBoxTestClass
- (
- const Vector3 & c0, // center of box0
- const Vector3 & e0, // extent of box0
- const Matrix3 & b0, // basis of box0
- const Vector3 & m0, // move for box0
- const Vector3 & c1, // center of box1
- const Vector3 & e1, // extent of box1
- const Matrix3 & b1, // basis of box1
- const Vector3 & m1, // move for box1
- float frac, // expected fraction
- bool sol // expected start solid
- ) :
- Box0(c0,e0,b0),
- Move0(m0),
- Box1(c1,e1,b1),
- Move1(m1),
- Fraction(frac),
- StartBad(sol)
- {
- }
- };
- OBBoxTestClass BTest0
- (
- Vector3(0,0,0), // center
- Vector3(4,0,0), // extent
- Matrix3(1), // basis
- Vector3(4,0,0), // move
- Vector3(6,0,0), // center
- Vector3(1,1,1), // extent
- Matrix3(1), // basis
- Vector3(0,0,0), // move
- 0.25f,
- false
- );
- OBBoxTestClass BTest1
- (
- Vector3(-3.5f,-1.5f,0.0f),
- Vector3(1.5f,1.5f,1.5f),
- Matrix3(1),
- Vector3(4,-4,0),
- Vector3(-5.1,-5,0),
- Vector3(1,1,1),
- Matrix3(1),
- Vector3(0,0,0),
- 1.0f, // should just barely go by (touches)
- false
- );
- OBBoxTestClass BTest2
- (
- Vector3(3,0,0),
- Vector3(7,1,1),
- Matrix3(1),
- Vector3(4,-4,0),
- Vector3(9.5,0,0),
- Vector3(1,6,1),
- Matrix3(1),
- Vector3(0,0,0),
- 0.0f, // startbad
- true
- );
- OBBoxTestClass BTest3
- (
- Vector3(0,0,0), // Box with diagonal y-z length of 1, rotated 45 about z
- Vector3(WWMATH_SQRT2/2.0,WWMATH_SQRT2/2.0,1),
- _RotateZ45,
- Vector3(4,0,0),
- Vector3(4,0,0), // axis-aligned box blocking the move along the x-axis
- Vector3(1,3,1),
- Matrix3(1),
- Vector3(0,0,0),
- 0.5f, // hitting another box edge-to-face halfway through the move
- false
- );
- OBBoxTestClass BTest4
- (
- Vector3(0,0,0), // Box with diagonal y-z length of 1, rotated 45 about z
- Vector3(WWMATH_SQRT2/2.0,WWMATH_SQRT2/2.0,1),
- _RotateZ45,
- Vector3(0,4,0),
- Vector3(0,4,0), // axis-aligned box blocking the move along the x-axis
- Vector3(3,1,1),
- Matrix3(1),
- Vector3(0,0,0),
- 0.5f, // hitting another box edge-to-face halfway through the move
- false
- );
- OBBoxTestClass BTest5
- (
- Vector3(0,0,0), // Box with diagonal y-z length of 1, rotated 45 about z
- Vector3(WWMATH_SQRT2/2.0,WWMATH_SQRT2/2.0,1),
- _RotateZ45,
- Vector3(0,-4,0),
- Vector3(0,-4,0), // axis-aligned box blocking the move along the x-axis
- Vector3(3,1,1),
- Matrix3(1),
- Vector3(0,0,0),
- 0.5f, // hitting another box edge-to-face halfway through the move
- false
- );
- OBBoxTestClass * OBBoxTestCases[] =
- {
- &BTest0,
- &BTest1,
- &BTest2,
- &BTest3,
- &BTest4,
- &BTest5
- };
- /***********************************************************************************************
- * test_obb_obb -- performs some "hard-coded" obb-obb collision tests *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 4/8/99 GTH : Created. *
- *=============================================================================================*/
- void test_obb_obb(void)
- {
- Print_Title("Testing OBBox->OBBox collision.");
- CastResultStruct result;
- result.ComputeContactPoint = true;
- int numtests = sizeof(OBBoxTestCases)/sizeof(OBBoxTestClass *);
- unsigned cycles;
- unsigned totalcycles = 0;
- // prime the cache
- OBBoxTestClass * testcase = OBBoxTestCases[4];
- cycles = Get_CPU_Clock();
- CollisionMath::Collide( testcase->Box0,
- testcase->Move0,
- testcase->Box1,
- testcase->Move1,
- &result);
- cycles = Get_CPU_Clock() - cycles;
- // now time and test the routine
- for (int i=0; i<numtests; i++) {
-
- testcase = OBBoxTestCases[i];
- result.Fraction = 1.0;
- result.StartBad = false;
- result.Normal.Set(0,0,0);
- cycles = Get_CPU_Clock();
- CollisionMath::Collide( testcase->Box0,
- testcase->Move0,
- testcase->Box1,
- testcase->Move1,
- &result);
-
- cycles = Get_CPU_Clock() - cycles;
- totalcycles += cycles;
-
- if ((WWMath::Fabs(testcase->Fraction - result.Fraction) > WWMATH_EPSILON) ||
- (testcase->StartBad != result.StartBad))
- {
- printf("test: %5d\tcycles: %12d \t\tfailed!\n",i,cycles);
- } else {
- printf("test: %5d\tcycles: %12d \t\tpassed...\n",i,cycles);
- }
- }
- printf("average cycles: %d\n",totalcycles / numtests);
- printf("\n");
- /*
- ** Try to get an accurate timing, run the same (startbad) test
- ** 100 times...
- */
- const int REPEAT=50;
- cycles = Get_CPU_Clock();
- for (int j=0;j<REPEAT;j++) {
- testcase = OBBoxTestCases[0];
- result.Fraction = 1.0;
- result.StartBad = false;
- result.Normal.Set(0,0,0);
- CollisionMath::Collide( testcase->Box0,
- testcase->Move0,
- testcase->Box1,
- testcase->Move1,
- &result);
- }
- cycles = Get_CPU_Clock() - cycles;
- printf("average cycles: %d\n",cycles / REPEAT);
- printf("\n");
- /*
- ** Now, comparing Oriented_Boxes_Intersect with CollisionMath::Intersect
- */
- cycles = Get_CPU_Clock();
- for (j=0;j<REPEAT;j++) {
- testcase = OBBoxTestCases[2];
- CollisionMath::Intersection_Test(testcase->Box0,testcase->Box1);
- }
- cycles = Get_CPU_Clock() - cycles;
- printf("CollisionMath::Intersect - average cycles: %d\n",cycles / REPEAT);
- printf("\n");
- cycles = Get_CPU_Clock();
- for (j=0;j<REPEAT;j++) {
- testcase = OBBoxTestCases[2];
- Oriented_Boxes_Intersect(testcase->Box0,testcase->Box1);
- }
- cycles = Get_CPU_Clock() - cycles;
- printf("Oriented_Boxes_Intersect - average cycles: %d\n",cycles / REPEAT);
- printf("\n");
- }
- /***********************************************************************************************
- * brute_force_cast_obb_obb -- brute force function to verify collision of two obb's *
- * *
- * This function doesn't really work in the general case. Only when the endpoint of the move *
- * is guaranteed to be inside the other box... *
- * *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 4/8/99 GTH : Created. *
- *=============================================================================================*/
- float brute_force_cast_obb_obb
- (
- const OBBoxClass & box0,
- const Vector3 & move0,
- const OBBoxClass & box1
- )
- {
- float istart = 0.0f;
- float iend = 1.0f;
-
- while (iend - istart > WWMATH_EPSILON) {
- float icenter = (iend + istart) / 2.0f;
- OBBoxClass testbox = box0;
- testbox.Center = box0.Center + icenter*move0;
- if (Oriented_Boxes_Intersect(testbox,box1)) {
- iend = icenter;
- } else {
- istart = icenter;
- }
- }
- return (iend + istart) / 2.0f;
- }
- /***********************************************************************************************
- * brute_force_obb_obb_test -- collide random obb's together *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 4/8/99 GTH : Created. *
- *=============================================================================================*/
- void brute_force_obb_obb_test(int test_count)
- {
- Print_Title("Brute Force Testing OBBox->OBBox collision.");
-
- OBBoxClass box0;
- OBBoxClass box1;
- Vector3 move0;
- int fail_count = 0;
- int startbad_count = 0;
- int startbad_fail_count = 0;
- float avg_fraction = 0.0f;
- float avg_fraction_error = 0.0f;
- int fraction_error_count = 0;
- float max_error = 0.0f;
- float min_fraction = 1.0f;
- float max_fraction = 0.0f;
- for (int i=0; i<test_count; i++) {
- box0.Init_Random(0.25f,3.0f);
- box1.Init_Random(0.25f,3.0f);
-
- box0.Center.X = WWMath::Random_Float(-10.0f,10.0f);
- box0.Center.Y = WWMath::Random_Float(-10.0f,10.0f);
- box0.Center.Z = WWMath::Random_Float(-10.0f,10.0f);
- box1.Center.Set(0,0,0);
- Vector3 newcenter;
- newcenter.X = WWMath::Random_Float(-0.12f,0.12f); // new center must be inside other box
- newcenter.Y = WWMath::Random_Float(-0.12f,0.12f);
- newcenter.Z = WWMath::Random_Float(-0.12f,0.12f);
- move0 = newcenter - box0.Center;
- // sweep box0 into box1
- CastResultStruct result;
- result.ComputeContactPoint = true;
- CollisionMath::Collide(box0,move0,box1,Vector3(0,0,0),&result);
- // if they were intersecting, verify that
- if (result.StartBad) {
- startbad_count++;
- if (!Oriented_Boxes_Intersect(box0,box1)) {
- startbad_fail_count++;
- printf("False startbad!");
- }
- }
- // if they weren't intersecting, verify the allowed move
- if (!result.StartBad) {
- bool success = true;
- // add the fraction into the total so we get an idea
- // how far our tests are going (hopefully a good mix)
- avg_fraction += result.Fraction;
- if (result.Fraction < min_fraction) min_fraction = result.Fraction;
- if (result.Fraction > max_fraction) max_fraction = result.Fraction;
- // verify that the fraction is correct
- float realfrac = brute_force_cast_obb_obb(box0,move0,box1);
- if (fabs(realfrac - result.Fraction) > WWMATH_EPSILON) {
- success = false;
- float error = fabs(realfrac - result.Fraction);
- avg_fraction_error += error;
- fraction_error_count++;
- if (error > max_error) max_error = error;
- }
-
- // verify that they are not intersecting now
- // if the allowed move is smaller than epsilon, we skip this and don't move
- if (result.Fraction > WWMATH_EPSILON) {
- OBBoxClass box2 = box0;
- box2.Center += (1.0f - WWMATH_EPSILON) * result.Fraction * move0;
- CastResultStruct second_result;
- CollisionMath::Collide(box2,move0,box1,Vector3(0,0,0),&second_result);
- if (second_result.StartBad) {
- success = false;
- #ifdef MANUAL_DEBUGGING
- _asm int 0x03;
- while (!success) {
- CastResultStruct move_result;
- CollisionMath::Collide(box0,move0,box1,Vector3(0,0,0),&move_result);
- second_result.Reset();
- CollisionMath::Collide(box2,move0,box1,Vector3(0,0,0),&second_result);
- }
- #endif
- }
- if ((result.Fraction < 1.0f) && (second_result.Fraction > 0.01f)) success = false;
- }
- // if something failed, do the test again to let the programmer step through...
- if (!success) {
- #ifdef MANUAL_DEBUGGING
- _asm int 0x03;
- while (!success) {
- fail_count++;
- CastResultStruct redo_result;
- redo_result.ComputePoint = true;
- CollisionMath::Collide(box0,move0,box1,Vector3(0,0,0),&redo_result);
- }
- #endif
- printf("x");
- } else {
- printf(".");
- }
- }
- }
- printf("\n");
- int passes = test_count - (startbad_fail_count + fail_count);
- printf("Passed %d tests out of %d tests.\n",passes,test_count);
- printf("StartBad tests: %d failures: %d\n",startbad_count,startbad_fail_count);
- if (fraction_error_count) {
- avg_fraction_error /= (float)fraction_error_count;
- }
- avg_fraction /= (float)(test_count - startbad_count);
- printf("Largest Fraction: %f\n",max_fraction);
- printf("Smallest Fraction: %f\n",min_fraction);
- printf("Average Fraction: %f\n",avg_fraction);
- printf("Average Error: %f\n",avg_fraction_error);
- printf("Biggest Error: %f\n",max_error);
- }
- /***********************************************************************************************
- * Test_OBBoxes -- run all of the obb-obb and obb-tri tests *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 4/8/99 GTH : Created. *
- *=============================================================================================*/
- void Test_OBBoxes(void)
- {
- const int TESTCOUNT = 100;
- srand(time(NULL));
- test_obb_tri();
- test_obb_obb();
- brute_force_obb_tri_test(TESTCOUNT);
- brute_force_obb_obb_test(TESTCOUNT);
- }
|