bool BasicPrimitiveTests::IntersectingRayAgainstAABB(const Ray & ray, const AABB & aabb, float & rtn_t)
{
	/*
		Main Idea:
            -> Uses slab representation for box.
            -> Finds intersection of ray/segment with each slab. Then compares intersection times for overlap in all slabs.
                -> Keep track of:
                    -> A: The farthest of all entries into a slab
                    -> B: The closest of all exits out of a slab.
                -> If A > B at anytime, exit with no intersection. 

        Intersecting slabs:
            -> Intersect slabs by inserting ray equation into plane equations for slab.
            -> Solve for t

        -> Must handle case when ray parallel to slab separately.
            -> To avoid division by zero.

        Can test for intersection without calculating intersection point:
            -> Choose coordinate system where box is axis aligned and centered at origin:
                AABB:
                    -> Translate segment and AABB to origin.
                OBB:
                    -> Transform Segment to OBB space, then translate both segment and OBB to origin.

            -> Do separating axis test with 6 axes:
                -> Three principle axes.
                -> Three cross products of box face normals and segment direction vector.
	*/
	
	rtn_t = 0.0f;
	float tmax = FLT_MAX;
	Eigen::Vector3f aabb_min = aabb.GetCenter() - aabb.GetExtents();
	Eigen::Vector3f aabb_max = aabb.GetCenter() + aabb.GetExtents();
	for (int i = 0; i < 3; ++i)
	{
		if (abs(ray.GetDirection()[i]) < EPSILON)
		{
			//Ray is parallel to slab. Not hit if origin not within slab.
			if (ray.GetOrigin()[i] < aabb_min[i] || ray.GetOrigin()[i] > aabb_max[i])
			{
				return false;
			}
		}
		else
		{
			float one_over_direction = 1.0f / ray.GetDirection()[i];
			float t1 = (aabb_min[i] - ray.GetOrigin()[i]) * one_over_direction;
			float t2 = (aabb_max[i] - ray.GetOrigin()[i]) * one_over_direction;
			if (t1 > t2) Swap(t1, t2);
			if (t1 > rtn_t) rtn_t = t1;
			if (t2 > tmax) tmax = t2;
			if (rtn_t > tmax) return false;
		}
	}
	
	return true;
}
int BasicPrimitiveTests::IntersectingSegmentAgainstAABB(const LineSegment & segment, const AABB & aabb, float & rtn_t1, float & rtn_t2)
{
	
	rtn_t1 = 0.0f;
	rtn_t2 = FLT_MAX;
	Eigen::Vector3f aabb_min = aabb.GetCenter() - aabb.GetExtents();
	Eigen::Vector3f aabb_max = aabb.GetCenter() + aabb.GetExtents();
	Eigen::Vector3f segment_direction = segment.GetPointB() - segment.GetPointA();
	for (int i = 0; i < 3; ++i)
	{
		if (abs(segment_direction[i]) < EPSILON)
		{
			//Ray is parallel to slab. Not hit if origin not within slab.
			if (segment.GetPointA()[i] < aabb_min[i] || segment.GetPointA()[i] > aabb_max[i])
			{
				return 0;
			}
		}
		else
		{
			float one_over_direction = 1.0f / segment_direction[i];
			float t1 = (aabb_min[i] - segment.GetPointA()[i]) * one_over_direction;
			float t2 = (aabb_max[i] - segment.GetPointA()[i]) * one_over_direction;
			if (t1 > 1.0f && t2 > 1.0f)
			{
				return 0;
			}
			if (t1 > t2) Swap(t1, t2);
			if (t1 > rtn_t1) rtn_t1 = t1;
			if (t2 > rtn_t2) rtn_t2 = t2;
			if (rtn_t1 > rtn_t2) return 0;
		}
	}
	if (rtn_t1 >= 0.0f && rtn_t1 <= 1.0f)
	{
		if (rtn_t2 >= 0.0f && rtn_t2 <= 1.0f)
		{
			return 2;
		}
		else
		{
			return 1;
		}
	}
	else
	{
		Swap(rtn_t1, rtn_t2);
		if (rtn_t1 >= 0.0f && rtn_t1 <= 1.0f)
		{
			return 1;
		}
		return 0;
	}
	
}
Beispiel #3
0
void OBB::Create(const AABB& aabb, const Matrix4x4& mat)
{
	// Note: must be coherent with Rotate()

	aabb.GetCenter(mCenter);
	aabb.GetExtents(mExtents);
	// Here we have the same as OBB::Rotate(mat) where the obb is (mCenter, mExtents, Identity).

	// So following what's done in Rotate:
	// - x-form the center
	mCenter *= mat;
	// - combine rotation with identity, i.e. just use given matrix
	mRot = mat;
}