Skip to main content
GameDev.net gamedev.net
🔒 Locked

Some collision code for everyone

Started by Jiia May 16, 2004 at 7:51 AM 0 replies 550+ views
Original Post
Jiia
Jiia
I spent three days trying to find all of the info I needed to do sphere collision. Some of the math itself is over my head. I know I'll learn these things in my classes, so I don't want to bother spending weeks figuring it out now. Since I spent so much time searching for this stuff, I decided to post my final code so that other less-than-math-freaks can learn from it (or just throw it into their code somewhere in the background). The basic structure of the functions is to use references (&VECTOR) as input to the functions, and pointers (*VECTOR) as outputs. Hope these are useful for someone. If not, I'm sure they will be some day. Feel free to point out mistakes, typos, or just if something isn't readable.
// Stores closest point to plane in *Closest

VOID ClosestPointOnPlane(VECTOR *Closest, VECTOR &v0, VECTOR &v1, VECTOR &v2, VECTOR &Normal, VECTOR &p)
{
	*Closest = p - v0;
	FLOAT Offset = D3DXVec3Dot(&Normal, Closest);
	*Closest -= (Normal * Offset);
	*Closest += v0;
}
// Stores closest point on line in *Closest

VOID ClosestPointOnLine(VECTOR *Closest, VECTOR &a, VECTOR &b, VECTOR &p)
{
	VECTOR c = p - a;
	VECTOR v = b - a;
	FLOAT d = D3DXVec3Length(&v);
	D3DXVec3Normalize(&v,&v);
	FLOAT t = D3DXVec3Dot(&v, &c);

	if(t < 0)
	{
		*Closest = a;
		return;
	}
	if(t > d)
	{
		*Closest = b;
		return;
	}

	*Closest = a + (v * t);
}
// Checks to make sure a point is on the same side of the line

// as the 3rd vertex. At least I think so :P

BOOL PIT_SameSide(VECTOR &p1, VECTOR &p2, VECTOR &a, VECTOR &b)
{
	VECTOR cp1,cp2;

	D3DXVec3Cross(&cp1, &(b-a), &(p1-a));
	D3DXVec3Cross(&cp2, &(b-a), &(p2-a));

	if(D3DXVec3Dot(&cp1, &cp2) >= 0.0f)
		return TRUE;

	return FALSE;
}
// Returns TRUE if a point on the triangle's plane is within the

// actual triangle

BOOL PointInTriangle(VECTOR &a, VECTOR &b, VECTOR &c, VECTOR &p)
{
	return (PIT_SameSide(p, a, b, c) && PIT_SameSide(p, b, a, c) &&	PIT_SameSide(p, c, a, b));
}
// Fills *Closest with closest point on the triangle to another

// point. Also returns distance to that point.

FLOAT ClosestPointOnTriangle(VECTOR *Closest, VECTOR &a, VECTOR &b, VECTOR &c, VECTOR &Normal, VECTOR &p)
{
	// Find Closest point on plane

	*Closest = p - a;
	FLOAT Offset = D3DXVec3Dot(&Normal, Closest);
	*Closest += a - (Normal * Offset);

	// See what to do next

	if(PointInTriangle(a,b,c, *Closest)) // Point is in triangle, so it's the closest point

	{
		return D3DXVec3Length(&(p - *Closest));
	}
	else
	{
		FLOAT Dist,CDist;
		VECTOR Close;

		ClosestPointOnLine(&Close, a, b, p);
		CDist = D3DXVec3Length(&(p - Close));
		*Closest = Close;

		ClosestPointOnLine(&Close, b, c, p);
		Dist = D3DXVec3Length(&(p - Close));
		if(Dist < CDist)
		{
			*Closest = Close;
			CDist = Dist;
		}

		ClosestPointOnLine(&Close, c, a, p);
		Dist = D3DXVec3Length(&(p - Close));
		if(Dist < CDist)
		{
			*Closest = Close;
			CDist = Dist;
		}

		return CDist;
	}
}
// Beware of this one, as I wrote it myself :P

VOID ClosestPointOnSphere(VECTOR *Closest, VECTOR &Position, FLOAT Radius, VECTOR &p)
{
	// Get Direction vector to sphere

	VECTOR Dir;
	D3DXVec3Normalize(&Dir, &(p - Position));

	// Closest point is just Sphere Position + (Direction * Radius)

	*Closest = Position + (Dir * Radius);
}
// I basically ripped this off from the SDK sample code. It

// casts a line from Origin in the Direction, returning TRUE

// if the line hits the triangle. "t" will tell you the

// distance from the Origin to the point on the triangle.

// "u" and "v" tell you the location on the triangle.

BOOL IntersectTriangle(VECTOR &Origin, VECTOR &Direction, VECTOR &v0, VECTOR &v1, VECTOR &v2, FLOAT *t, FLOAT *u, FLOAT *v)
{
	// Get Vectors for two edges that share vertex 0

	VECTOR Edge1 = v1 - v0;
	VECTOR Edge2 = v2 - v0;

	// Get Determinant to calculate U

	VECTOR PVec;
	D3DXVec3Cross(&PVec, &Direction, &Edge2);

	// if Determinant is near zero, ray lies in plane of triangle

	FLOAT Det = D3DXVec3Dot(&Edge1, &PVec);
	VECTOR TVec;
	if(Det > 0)
	{
		TVec = Origin - v0;
	}
	else
	{
		TVec = v0 - Origin;
		Det = -Det;
	}

	if(Det < 0.0001f)
		return FALSE;

	// Calculate U and test bounds

	*u = D3DXVec3Dot(&TVec, &PVec);
	if(*u < 0.0f || *u > Det)
		return FALSE;

	// Calculate V and test bounds

	VECTOR QVec;
	D3DXVec3Cross(&QVec, &TVec, &Edge1);
	*v = D3DXVec3Dot(&Direction, &QVec);
	if(*v < 0.0f || *u + *v > Det)
		return FALSE;

	// Calculate T and scale

	*t = D3DXVec3Dot(&Edge2, &QVec);
	FLOAT InvDet = 1.0f / Det;
	*t *= InvDet;
	*u *= InvDet;
	*v *= InvDet;

	return TRUE;
}
[edited by - Jiia on May 16, 2004 9:04:13 AM]

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.