Example #1
0
/*
============
idSurface_Patch::LerpVert
============
*/
void idSurface_Patch::LerpVert( const idDrawVert& a, const idDrawVert& b, idDrawVert& out ) const
{
	out.xyz[0] = 0.5f * ( a.xyz[0] + b.xyz[0] );
	out.xyz[1] = 0.5f * ( a.xyz[1] + b.xyz[1] );
	out.xyz[2] = 0.5f * ( a.xyz[2] + b.xyz[2] );
	out.SetNormal( ( a.GetNormal() + b.GetNormal() ) * 0.5f );
	out.SetTexCoord( ( a.GetTexCoord() + b.GetTexCoord() ) * 0.5f );
}
Example #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 );
}
Example #3
0
ID_INLINE float sdTraceSurface::TraceToMeshFace( const int faceNum, const idVec3& point, const idVec3 &normal, const float faceDist, const float traceDist, idDrawVert& dv ) const {
	int				i;
	float			dist;
	const idPlane*	plane;
	idVec3			edge;
	float			d, t;
	idVec3			dir[3];
	float			baseArea;
	float			bary[3];
	idVec3			testVert;

	plane = facePlanes + faceNum;

	// only test against planes facing the opposite direction as our trace normal
	d = -( plane->Normal() * normal );
	if ( d <= TRIANGLE_NORMAL_EPSILON ) {
		return faceDist;
	}

	// get the distance to the plane
	dist = plane->Distance( point );

	if ( dist >= traceDist * d ) {
		return faceDist;
	}

	const vertIndex_t* index = indexes + faceNum * 3;
	const idDrawVert &v0 = verts[ index[ 0 ] ];
	const idDrawVert &v1 = verts[ index[ 1 ] ];
	const idDrawVert &v2 = verts[ index[ 2 ] ];

	// if normal is inside all edge planes, this face is hit
	dir[0] = v0.xyz - point;
	dir[1] = v1.xyz - point;
	edge = dir[0].Cross( dir[1] );
	t = normal * edge;
	if ( t < -TRIANGLE_EDGE_EPSILON ) {
		return faceDist;
	}
	dir[2] = v2.xyz - point;
	edge = dir[1].Cross( dir[2] );
	t = normal * edge;
	if ( t < -TRIANGLE_EDGE_EPSILON ) {
		return faceDist;
	}
	edge = dir[2].Cross( dir[0] );
	t = normal * edge;
	if ( t < -TRIANGLE_EDGE_EPSILON ) {
		return faceDist;
	}

	// find the point of impact on the triangle plane
	dist /= d;
	testVert = point + dist * normal;

	// calculate barycentric coordinates of the impact point on the high poly triangle
	baseArea = 1.0f / idWinding::TriangleArea( v0.xyz, v1.xyz, v2.xyz );
	bary[0] = idWinding::TriangleArea( testVert, v1.xyz, v2.xyz ) * baseArea;
	bary[1] = idWinding::TriangleArea( v0.xyz, testVert, v2.xyz ) * baseArea;
	bary[2] = idWinding::TriangleArea( v0.xyz, v1.xyz, testVert ) * baseArea;

	if ( bary[0] + bary[1] + bary[2] > 1.1f ) {
		return faceDist;
	}

	dv.xyz = testVert;

	// triangularly interpolate the texture coordinates, normals and colors to the sample point
	// FIXME: SD_USE_DRAWVERT_SIZE_32
	for ( i = 0; i < 2; i++ ) {
		dv._st[ i ] = bary[0] * v0._st[i] + bary[1] * v1._st[i] + bary[2] * v2._st[i];
	}

#if defined( SD_USE_DRAWVERT_SIZE_32 )
	idVec3 n;
	idVec3 n0 = v0.GetNormal();
	idVec3 n1 = v1.GetNormal();
	idVec3 n2 = v2.GetNormal();
	for ( i = 0; i < 3; i++ ) {
		n[ i ] = bary[0] * n0[i] + bary[1] * n1[i] + bary[2] * n2[i];
	}
	n.Normalize();
	dv.SetNormal( n );

	idVec3 tgnt;
	idVec3 tgnt0 = v0.GetTangent();
	idVec3 tgnt1 = v1.GetTangent();
	idVec3 tgnt2 = v2.GetTangent();
	for ( i = 0; i < 3; i++ ) {
		tgnt[ i ] = bary[0] * tgnt0[i] + bary[1] * tgnt1[i] + bary[2] * tgnt2[i];
	}
	tgnt.Normalize();
	dv.SetTangent( tgnt );

	float s0 = v0.GetBiTangentSign();
	float s1 = v1.GetBiTangentSign();
	float s2 = v2.GetBiTangentSign();
	dv.SetBiTangentSign( bary[0] * s0 + bary[1] * s1 + bary[2] * s2 );

#else
	for ( i = 0; i < 3; i++ ) {
		dv._normal[ i ] = bary[0] * v0._normal[i] + bary[1] * v1._normal[i] + bary[2] * v2._normal[i];
	}
	dv._normal.Normalize();

	for ( i = 0; i < 4; i++ ) {
		dv._tangent[i] = bary[0] * v0._tangent[i] + bary[1] * v1._tangent[i] + bary[2] * v2._tangent[i];
	}

#endif

	for ( i = 0; i < 4; i++ ) {
		dv.color[i] = idMath::ClampInt( 0, 255, idMath::FtoiFast( bary[0] * v0.color[i] + bary[1] * v1.color[i] + bary[2] * v2.color[i] ) );
	}

	return dist;
}