1
0
Fork 0

Latest version of hitlist.cxx from Norman Vine:

- Addresses some ot the recent profiling results.
- Added a 'lazy evaluation' in IntersectBranch and inlined a couple
  of HEAVILY called functions.
This commit is contained in:
curt 2002-02-28 23:59:28 +00:00
parent 03b9ecf039
commit 9bae80d94a

View file

@ -39,15 +39,20 @@ static bool pointInTriangle( sgdVec3 point, sgdVec3 tri[3] )
// punt if outside bouding cube // punt if outside bouding cube
if ( point[0] < (xmin = SG_MIN3 (tri[0][0], tri[1][0], tri[2][0])) ) { if ( point[0] < (xmin = SG_MIN3 (tri[0][0], tri[1][0], tri[2][0])) ) {
return false; return false;
} else if ( point[0] > (xmax = SG_MAX3 (tri[0][0], tri[1][0], tri[2][0])) ) { } else if ( point[0] > (xmax = SG_MAX3 (tri[0][0], tri[1][0], tri[2][0])) )
{
return false; return false;
} else if ( point[1] < (ymin = SG_MIN3 (tri[0][1], tri[1][1], tri[2][1])) ) { } else if ( point[1] < (ymin = SG_MIN3 (tri[0][1], tri[1][1], tri[2][1])) )
{
return false; return false;
} else if ( point[1] > (ymax = SG_MAX3 (tri[0][1], tri[1][1], tri[2][1])) ) { } else if ( point[1] > (ymax = SG_MAX3 (tri[0][1], tri[1][1], tri[2][1])) )
{
return false; return false;
} else if ( point[2] < (zmin = SG_MIN3 (tri[0][2], tri[1][2], tri[2][2])) ) { } else if ( point[2] < (zmin = SG_MIN3 (tri[0][2], tri[1][2], tri[2][2])) )
{
return false; return false;
} else if ( point[2] > (zmax = SG_MAX3 (tri[0][2], tri[1][2], tri[2][2])) ) { } else if ( point[2] > (zmax = SG_MAX3 (tri[0][2], tri[1][2], tri[2][2])) )
{
return false; return false;
} }
@ -190,7 +195,7 @@ int sgdIsectInfLinePlane( sgdVec3 dst, sgdVec3 l_org,
return FALSE ; return FALSE ;
sgdScaleVec3 ( dst, l_vec, -( sgdScalarProductVec3 ( l_org, plane ) sgdScaleVec3 ( dst, l_vec, -( sgdScalarProductVec3 ( l_org, plane )
+ plane[3] ) / tmp ) ; + plane[3] ) / tmp ) ;
sgdAddVec3 ( dst, l_org ) ; sgdAddVec3 ( dst, l_org ) ;
return TRUE ; return TRUE ;
@ -203,85 +208,92 @@ int sgdIsectInfLinePlane( sgdVec3 dst, sgdVec3 l_org,
*/ */
bool sgdPointInTriangle( sgdVec3 point, sgdVec3 tri[3] ) bool sgdPointInTriangle( sgdVec3 point, sgdVec3 tri[3] )
{ {
sgdVec3 dif; sgdVec3 dif;
int i; SGDfloat min, max;
for( i=0; i<3; i++ ) { // punt if outside bouding cube
SGDfloat min, max; SG_MIN_MAX3 ( min, max, tri[0][0], tri[1][0], tri[2][0] );
SG_MIN_MAX3 ( min, max, tri[0][i], tri[1][i], tri[2][i] ); if( (point[0] < min) || (point[0] > max) )
// punt if outside bouding cube return false;
if( (point[i] < min) || (point[i] > max) ) dif[0] = max - min;
return false;
dif[i] = max - min;
}
// drop the smallest dimension so we only have to work in 2d. SG_MIN_MAX3 ( min, max, tri[0][1], tri[1][1], tri[2][1] );
SGDfloat min_dim = SG_MIN3 (dif[0], dif[1], dif[2]); if( (point[1] < min) || (point[1] > max) )
SGDfloat x1, y1, x2, y2, x3, y3, rx, ry; return false;
if ( fabs(min_dim-dif[0]) <= DBL_EPSILON ) { dif[1] = max - min;
// x is the smallest dimension
x1 = point[1];
y1 = point[2];
x2 = tri[0][1];
y2 = tri[0][2];
x3 = tri[1][1];
y3 = tri[1][2];
rx = tri[2][1];
ry = tri[2][2];
} else if ( fabs(min_dim-dif[1]) <= DBL_EPSILON ) {
// y is the smallest dimension
x1 = point[0];
y1 = point[2];
x2 = tri[0][0];
y2 = tri[0][2];
x3 = tri[1][0];
y3 = tri[1][2];
rx = tri[2][0];
ry = tri[2][2];
} else if ( fabs(min_dim-dif[2]) <= DBL_EPSILON ) {
// z is the smallest dimension
x1 = point[0];
y1 = point[1];
x2 = tri[0][0];
y2 = tri[0][1];
x3 = tri[1][0];
y3 = tri[1][1];
rx = tri[2][0];
ry = tri[2][1];
} else {
// all dimensions are really small so lets call it close
// enough and return a successful match
return true;
}
// check if intersection point is on the same side of p1 <-> p2 as p3 SG_MIN_MAX3 ( min, max, tri[0][2], tri[1][2], tri[2][2] );
SGDfloat tmp = (y2 - y3) / (x2 - x3); if( (point[2] < min) || (point[2] > max) )
int side1 = SG_SIGN (tmp * (rx - x3) + y3 - ry); return false;
int side2 = SG_SIGN (tmp * (x1 - x3) + y3 - y1); dif[2] = max - min;
if ( side1 != side2 ) {
// printf("failed side 1 check\n"); // drop the smallest dimension so we only have to work in 2d.
return false; SGDfloat min_dim = SG_MIN3 (dif[0], dif[1], dif[2]);
} SGDfloat x1, y1, x2, y2, x3, y3, rx, ry;
if ( fabs(min_dim-dif[0]) <= DBL_EPSILON ) {
// x is the smallest dimension
x1 = point[1];
y1 = point[2];
x2 = tri[0][1];
y2 = tri[0][2];
x3 = tri[1][1];
y3 = tri[1][2];
rx = tri[2][1];
ry = tri[2][2];
} else if ( fabs(min_dim-dif[1]) <= DBL_EPSILON ) {
// y is the smallest dimension
x1 = point[0];
y1 = point[2];
x2 = tri[0][0];
y2 = tri[0][2];
x3 = tri[1][0];
y3 = tri[1][2];
rx = tri[2][0];
ry = tri[2][2];
} else if ( fabs(min_dim-dif[2]) <= DBL_EPSILON ) {
// z is the smallest dimension
x1 = point[0];
y1 = point[1];
x2 = tri[0][0];
y2 = tri[0][1];
x3 = tri[1][0];
y3 = tri[1][1];
rx = tri[2][0];
ry = tri[2][1];
} else {
// all dimensions are really small so lets call it close
// enough and return a successful match
return true;
}
// check if intersection point is on correct side of p2 <-> p3 as p1 // check if intersection point is on the same side of p1 <-> p2 as p3
tmp = (y3 - ry) / (x3 - rx); SGDfloat tmp = (y2 - y3) / (x2 - x3);
side1 = SG_SIGN (tmp * (x2 - rx) + ry - y2); int side1 = SG_SIGN (tmp * (rx - x3) + y3 - ry);
side2 = SG_SIGN (tmp * (x1 - rx) + ry - y1); int side2 = SG_SIGN (tmp * (x1 - x3) + y3 - y1);
if ( side1 != side2 ) { if ( side1 != side2 ) {
// printf("failed side 2 check\n"); // printf("failed side 1 check\n");
return false; return false;
} }
// check if intersection point is on correct side of p1 <-> p3 as p2 // check if intersection point is on correct side of p2 <-> p3 as p1
tmp = (y2 - ry) / (x2 - rx); tmp = (y3 - ry) / (x3 - rx);
side1 = SG_SIGN (tmp * (x3 - rx) + ry - y3); side1 = SG_SIGN (tmp * (x2 - rx) + ry - y2);
side2 = SG_SIGN (tmp * (x1 - rx) + ry - y1); side2 = SG_SIGN (tmp * (x1 - rx) + ry - y1);
if ( side1 != side2 ) { if ( side1 != side2 ) {
// printf("failed side 3 check\n"); // printf("failed side 2 check\n");
return false; return false;
} }
return true; // check if intersection point is on correct side of p1 <-> p3 as p2
tmp = (y2 - ry) / (x2 - rx);
side1 = SG_SIGN (tmp * (x3 - rx) + ry - y3);
side2 = SG_SIGN (tmp * (x1 - rx) + ry - y1);
if ( side1 != side2 ) {
// printf("failed side 3 check\n");
return false;
}
return true;
} }
@ -327,35 +339,50 @@ int FGHitList::IntersectLeaf( ssgLeaf *leaf, sgdMat4 m,
sgdMakePlane( plane, tri[0], tri[1], tri[2] ); sgdMakePlane( plane, tri[0], tri[1], tri[2] );
sgdVec3 point; sgdVec3 point;
if( sgdIsectInfLinePlane( point, orig, dir, plane ) ) {
#if 0 //inlined IsectInfLinePlane( point dst, orig, dir, plane )
if( pointInTriangle( point, tri ) ) { SGDfloat tmp = sgdScalarProductVec3 ( dir, plane ) ;
add(leaf,i,point,plane);
num_hits++; /* Is line parallel to plane? */
} if ( sgdAbs ( tmp ) < DBL_EPSILON )
continue ;
sgdScaleVec3 ( point, dir,
-( sgdScalarProductVec3 ( orig, plane ) + plane[3] )
/ tmp ) ;
sgdAddVec3 ( point, orig ) ;
// end of inlined intersection
#if 0
if( pointInTriangle( point, tri ) ) {
add(leaf,i,point,plane);
num_hits++;
}
#endif // 0 #endif // 0
if( sgdPointInTriangle( point, tri ) ) { if( sgdPointInTriangle( point, tri ) ) {
// transform point into passed into desired coordinate frame // transform point into passed into desired coordinate frame
sgdXformPnt3( point, point, m ); sgdXformPnt3( point, point, m );
add(leaf,i,point,plane); add(leaf,i,point,plane);
num_hits++; num_hits++;
}
} }
} }
return num_hits; return num_hits;
} }
void FGHitList::IntersectBranch( ssgBranch *branch, sgdMat4 m, void FGHitList::IntersectBranch( ssgBranch *branch, sgdMat4 m,
sgdVec3 orig, sgdVec3 dir ) sgdVec3 orig, sgdVec3 dir )
{ {
sgSphere *bsphere; sgSphere *bsphere;
// lookat vector in branch's coordinate frame /* the lookat vector and matrix in branch's coordinate frame
* but we won't determine these unless needed to,
* This 'lazy evaluation' is a result of profiling data */
sgdVec3 _orig, _dir; sgdVec3 _orig, _dir;
sgdMat4 _m; sgdMat4 _m;
sgdTransposeNegateMat4( _m, m);
sgdXformPnt3( _orig, orig, _m ); // 'lazy evaluation' flag
sgdXformPnt3( _dir, dir, _m ); int first_time = 1;
for ( ssgEntity *kid = branch->getKid( 0 ); for ( ssgEntity *kid = branch->getKid( 0 );
kid != NULL; kid != NULL;
@ -363,36 +390,54 @@ void FGHitList::IntersectBranch( ssgBranch *branch, sgdMat4 m,
{ {
if ( kid->getTraversalMask() & SSGTRAV_HOT ) { if ( kid->getTraversalMask() & SSGTRAV_HOT ) {
bsphere = kid->getBSphere(); bsphere = kid->getBSphere();
sgVec3 fcenter; sgdVec3 center;
sgCopyVec3( fcenter, bsphere->getCenter() ); sgdSetVec3( center,
sgdVec3 center; bsphere->getCenter()[0],
sgdSetVec3( center, fcenter ); bsphere->getCenter()[1],
sgdXformPnt3( center, m ) ; bsphere->getCenter()[2] );
// watch out for overflow sgdXformPnt3( center, m ) ;
if ( sgdClosestPointToLineDistSquared( center, orig, dir ) <
double(bsphere->getRadius() * bsphere->getRadius()) ) // sgdClosestPointToLineDistSquared( center, orig, dir )
{ // inlined here because because of profiling results
// possible intersections sgdVec3 u, u1, v;
if ( kid->isAKindOf ( ssgTypeBranch() ) ) { sgdSubVec3(u, center, orig);
sgdMat4 m_new; sgdScaleVec3( u1, dir, sgdScalarProductVec3(u,dir)
sgdCopyMat4(m_new, m); / sgdScalarProductVec3(dir,dir) );
if ( kid->isA( ssgTypeTransform() ) ) { sgdSubVec3(v, u, u1);
// doubles because of possible overflow
#define SQUARE(x) (x*x)
if( sgdScalarProductVec3(v, v)
< SQUARE( double(bsphere->getRadius()) ) )
{
// possible intersections
if ( kid->isAKindOf ( ssgTypeBranch() ) ) {
sgdMat4 m_new;
sgdCopyMat4(m_new, m);
if ( kid->isA( ssgTypeTransform() ) ) {
sgMat4 fxform; sgMat4 fxform;
((ssgTransform *)kid)->getTransform( fxform ); ((ssgTransform *)kid)->getTransform( fxform );
sgdMat4 xform; sgdMat4 xform;
sgdSetMat4( xform, fxform ); sgdSetMat4( xform, fxform );
sgdPreMultMat4( m_new, xform ); sgdPreMultMat4( m_new, xform );
} }
IntersectBranch( (ssgBranch *)kid, m_new, orig, dir ); IntersectBranch( (ssgBranch *)kid, m_new, orig, dir );
} else if ( kid->isAKindOf( ssgTypeLeaf() ) ) { } else if ( kid->isAKindOf( ssgTypeLeaf() ) ) {
IntersectLeaf( (ssgLeaf *)kid, m, _orig, _dir ); if( first_time) {
} // OK we need these
} else { sgdTransposeNegateMat4( _m, m);
// end of the line for this branch sgdXformPnt3( _orig, orig, _m );
} sgdXformPnt3( _dir, dir, _m );
} else { first_time = 0;
// branch requested not to be traversed }
} IntersectLeaf( (ssgLeaf *)kid, m, _orig, _dir );
}
} else {
// end of the line for this branch
}
} else {
// branch requested not to be traversed
}
} }
} }