Sign in to follow this  
WhiskyJoe

Intersection on boundingboxes with raycasting

Recommended Posts

Hey, I'm trying to get raycasting to work to see if it intersects with a boundingbox, the code below here is what i have so far which calculates the ray and checks for intersection. problem is.. it's not working! the values i get from the calculation seem to be alright, and i think the main problem is in the intersection test. my engine is abstract so i'm trying to avoid any direct DX in here. i would like to have some kind of functionality like the D3DXBoxBoundProbe where i can specify my origin, direction and BB info. any help would be much appriciated :)
// Build the ray with the mouse position
void Ray::createRay(int mouseX, int mouseY, Matrix* mProjMatrix, Matrix* mViewMatrix, Matrix* mWorldMatrix)
{
	// Calculate projection stuff
	v.x = ((( 2.0f*mouseX) / 640.0f)  - 1.0f) / mProjMatrix->_11;
	v.y = (((-2.0f*mouseY) / 480.0f) + 1.0f) / mProjMatrix->_22;
	v.z = 1.0f;

	Matrix* mInverse;

	mInverse = &mViewMatrix->Inverse();

	// Transform the screen space pick ray into 3D space
	vDirection.x  = v.x * mInverse->_11 + v.y * mInverse->_21 + v.z * mInverse->_31;
	vDirection.y  = v.x * mInverse->_12 + v.y * mInverse->_22 + v.z * mInverse->_32;
	vDirection.z  = v.x * mInverse->_13 + v.y * mInverse->_23 + v.z * mInverse->_33;

	vOrigin.x = mInverse->_41;
	vOrigin.y = mInverse->_42;
	vOrigin.z = mInverse->_43;

	Matrix* Matinverse;
	Matinverse = &mWorldMatrix->Inverse();

	//rayObjOrigin = Matinverse->TransformVectorByMatrix(&vOrigin); not working yet
	rayObjOrigin.x = vOrigin.x * Matinverse->_11 + vOrigin.y * Matinverse->_21 + vOrigin.z * Matinverse->_31 + Matinverse->_41;
	rayObjOrigin.y = vOrigin.x * Matinverse->_12 + vOrigin.y * Matinverse->_22 + vOrigin.z * Matinverse->_32 + Matinverse->_42;
	rayObjOrigin.z = vOrigin.x * Matinverse->_13 + vOrigin.y * Matinverse->_23 + vOrigin.z * Matinverse->_33 + Matinverse->_43;


	//rayObjeDirection = Matinverse->TransformVectorNormalByMatrix(&vDirection); not working yet
	rayObjeDirection.x = vDirection.x * Matinverse->_11 + vDirection.y * Matinverse->_21 + vDirection.z * Matinverse->_31;
	rayObjeDirection.y = vDirection.x * Matinverse->_12 + vDirection.y * Matinverse->_22 + vDirection.z * Matinverse->_32;
	rayObjeDirection.z = vDirection.x * Matinverse->_13 + vDirection.y * Matinverse->_23 + vDirection.z * Matinverse->_33;

	rayObjeDirection.Normalize();

}

// Now we check to see if we are going through anything
bool Ray::checkCollisionAtBB(BoundingBox* box)
{
	// By default we don't hit
	bool hit = false;

	// First grab the entity's bounding box
	Vector boxPos;
	Vector diff;

	// Now calculate the position of the box
	// We have the two corners of the box so we only need to calculate the average
	boxPos.x = ((box->minX + box->maxX) / 2.0f);
	boxPos.y = ((box->minY + box->maxY) / 2.0f);
	boxPos.z = ((box->minZ + box->maxZ) / 2.0f);

	// Now calculate width and height
	// NOTE: Not sure how to use boxes rather than spheres for checking collision, yet...
	float boxWidth = box->maxX - box->minX;
	float boxLength = box->maxZ - box->minZ;
	float boxHeight = box->maxY - box->minY;

	// Make sure the above values are positive
	if(boxWidth < 0){boxWidth = 0 - boxWidth;}
	if(boxLength < 0){boxLength = 0 - boxLength;}
	if(boxHeight < 0){boxHeight = 0 - boxHeight;}

	// Create a new vector
	diff.x = (this->rayObjOrigin.x - boxPos.x);
	diff.y = (this->rayObjOrigin.y - boxPos.y);
	diff.z = (this->rayObjOrigin.z - boxPos.z);

	// Calculate the dot products
	float dotA = 2.0f * this->rayObjeDirection.DotProduct(diff);
	float dotB = diff.DotProduct(diff) - (boxWidth * boxLength);

	// Discrimant thingy-ma-jiggy, who comes up with this shit...
	float fDiscriminant = (dotA * dotA) - (4.0f * dotB);

	// Check discrimant
	if(fDiscriminant > 0.0f)
	{
		// Square root
		fDiscriminant = sqrtf(fDiscriminant);

		float fSearchA = (-dotA + fDiscriminant) / 2.0f;
		float fSearchB = (-dotA - fDiscriminant) / 2.0f;

		// If it's larger than 0.0f, we've hit something
		if(fSearchA >= 0.0f || fSearchB >= 0.0f)
		{
			// Set to true
			hit = true;
		}
	}

	// Return result
	return hit;
}


Share this post


Link to post
Share on other sites
Quote:
// Discrimant thingy-ma-jiggy, who comes up with this shit...

Maybe you should try understanding AABB-ray intersection testing ;)

A couple of things I noticed looking at your code.

You hard-code 640×480 as the display size ... this is not the source of your problem but it is a bad idea. At the very least these ought to be constants defined in one place, not sprinkled throughout your code.

Your difference vector is from the box centre to the ray. I would expect it to be the other way around. This will cause rayObjeDirection.DotProduct(diff) to be negative and therefore the test to fail (though you might hit things directly opposite where you are aiming, i.e. behind you somewhere).

I don't entirely understand the hit test you are doing either but I think it is a ray-sphere test not a ray-AABB test. It doesn't look right though, you are not taking account of the diminishing size of the sphere at distance. An approximate test would be:
hitTest = this->rayObjeDirection.CrossProduct(diff).Magnitude < sphereRadius
I imagine you can find AABB-ray intersection tests online.

Have you tried rendering the generated ray to ensure that you are creating it correctly? You probably are but I never really understood the interaction of the various matrices so I can't check that part by glancing at it.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this