Пример #1
0
/*
================
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 );
}
Пример #2
0
/*
====================
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 );
}