/* ================ SampleHighMesh Find the best surface normal in the high poly mesh for a ray coming from the surface of the low poly mesh Returns false if the trace doesn't hit anything ================ */ static bool SampleHighMesh( const renderBump_t *rb, const idVec3 &point, const idVec3 &direction, idVec3 &sampledNormal, byte sampledColor[4] ) { idVec3 p; binLink_t *bl; int linkNum; int faceNum; float dist, bestDist; int block[3]; float maxDist; int c_hits; int i; idVec3 normal; // we allow non-normalized directions on input normal = direction; normal.Normalize(); // increment our uniqueness counter (FIXME: make thread safe?) rayNumber++; // the max distance will be the traceFrac times the longest axis of the high poly model bestDist = -rb->traceDist; maxDist = rb->traceDist; sampledNormal = vec3_origin; c_hits = 0; // this is a pretty damn lazy way to walk through a 3D grid, and has a (very slight) // chance of missing a triangle in a corner crossing case #define RAY_STEPS 100 for ( i = 0 ; i < RAY_STEPS ; i++ ) { p = point - rb->hash->bounds[0] + normal * ( -1.0 + 2.0 * i / RAY_STEPS ) * rb->traceDist; block[0] = floor( p[0] / rb->hash->binSize[0] ); block[1] = floor( p[1] / rb->hash->binSize[1] ); block[2] = floor( p[2] / rb->hash->binSize[2] ); if ( block[0] < 0 || block[0] >= HASH_AXIS_BINS ) { continue; } if ( block[1] < 0 || block[1] >= HASH_AXIS_BINS ) { continue; } if ( block[2] < 0 || block[2] >= HASH_AXIS_BINS ) { continue; } // FIXME: casting away const bl = (binLink_t *)&rb->hash->binLinks[block[0]][block[1]][block[2]]; if ( bl->rayNumber == rayNumber ) { continue; // already tested this block } bl->rayNumber = rayNumber; linkNum = bl->triLink; triLink_t *link; for ( ; linkNum != -1 ; linkNum = link->nextLink ) { link = &rb->hash->linkBlocks[ linkNum / MAX_LINKS_PER_BLOCK ][ linkNum % MAX_LINKS_PER_BLOCK ]; faceNum = link->faceNum; dist = TraceToMeshFace( rb->mesh, faceNum, bestDist, maxDist, point, normal, sampledNormal, sampledColor ); if ( dist == DIST_NO_INTERSECTION ) { continue; } c_hits++; // continue looking for a better match bestDist = dist; } } return (bool)( bestDist > -rb->traceDist ); }
/* ==================== sdTraceSurface::RayIntersection ==================== */ bool sdTraceSurface::RayIntersection( const idVec3& start, const idVec3& end, idDrawVert& dv ) const { idVec3 p; int linkNum; unsigned int i; unsigned int maxTraceBins; int hashBin[3]; int separatorAxis; float faceDist, traceDist; float separatorDist; idVec3 normal, invNormal; // clear the result in case nothing is hit dv.Clear(); if ( numLinkBlocks == 0 ) { return false; } // get trace normal and normalize normal = end - start; faceDist = traceDist = normal.Normalize(); // inverse normal invNormal[0] = ( normal[0] != 0.0f ) ? 1.0f / normal[0] : 1.0f; invNormal[1] = ( normal[1] != 0.0f ) ? 1.0f / normal[1] : 1.0f; invNormal[2] = ( normal[2] != 0.0f ) ? 1.0f / normal[2] : 1.0f; // maximum number of hash bins the trace can go through maxTraceBins = 1 + idMath::Ftoi( traceDist * ( fabs( normal[0] ) * invBinSize[0] + fabs( normal[1] ) * invBinSize[1] + fabs( normal[2] ) * invBinSize[2] ) ); // get the first hash bin for the trace p = start - _bounds[0]; hashBin[0] = idMath::Ftoi( idMath::Floor( p[0] * invBinSize[0] ) ); hashBin[1] = idMath::Ftoi( idMath::Floor( p[1] * invBinSize[1] ) ); hashBin[2] = idMath::Ftoi( idMath::Floor( p[2] * invBinSize[2] ) ); separatorAxis = 0; separatorDist = 0.0f; bool insideHash = false; for ( i = 0; i < maxTraceBins; i++, GetNextHashBin( start, normal, hashBin, separatorAxis, separatorDist ) ) { // if this bin is outside the valid hash space if ( ( hashBin[0] | hashBin[1] | hashBin[2] ) & ~( binsPerAxis - 1 ) ) { if ( insideHash ) { break; // left valid hash space } continue; // not yet in valid hash space } insideHash = true; // if a triangle was hit before the plane that separates this hash bin from the previous hash bin if ( faceDist < traceDist && faceDist < separatorDist * invNormal[separatorAxis] ) { break; } const triLink_t *link; // test all the triangles in this hash bin for ( linkNum = binLinks[hashBin[0]][hashBin[1]][hashBin[2]]; linkNum != -1; linkNum = link->nextLink ) { link = &linkBlocks[ linkNum / MAX_LINKS_PER_BLOCK ][ linkNum % MAX_LINKS_PER_BLOCK ]; faceDist = TraceToMeshFace( link->faceNum, start, normal, faceDist, traceDist, dv ); } } // FIXME: SD_USE_DRAWVERT_SIZE_32 #if defined( SD_USE_DRAWVERT_SIZE_32 ) idVec3 n = dv.GetNormal(); n.Normalize(); dv.SetNormal( n ); #else dv._normal.Normalize(); #endif return ( faceDist < traceDist ); }