How to calculate an Actor Oriented Bounding Box (OBB) With Unreal Engine

To obtain an Oriented Bounding Box (OBB) for an object, we first need to retrieve the local Axis Aligned Bounding Box (AABB) and then construct our OBB using a center and an extent vector transformed with the Actor’s world Transform. While the AABB consists of a single Extent vector representing the magnitude on each axis (X, Y, Z), our OBB requires an extent vector per axis.

In the image below, we can visualize:

  • In red: the Local space AABB (with the original object inside).
  • In blue: the AABB of the object.
  • In yellow: our calculated OBB (of our scaled, rotated and translated Actor).

Let’s start by defining the OBB structure:

/**
 * @brief Represents an oriented bounding box.
 *        The extents are measured from the center to the maximum point along each axis.
 */
struct FL0OrientedBox
{
	FVector Center;

	FVector Forward;
	FVector Right;
	FVector Up;

	FL0OrientedBox()
		: Center(0.0f, 0.0f, 0.0f),
		  Forward(0.0f, 0.0f, 0.0f),
		  Right(0.0f, 0.0f, 0.0f),
		  Up(0.0f, 0.0f, 0.0f)
	{
	}
};

Now, let’s compute our OBB from an actor:

FL0OrientedBox UL0GameplayLibrary::CalculateActorOrientedBoundingBox(AActor* Actor)
{
	if (ensure(Actor) == false)
	{
		return FL0OrientedBox();
	}

	// Get the AABB in Local space (aka Object space: such as in the Blueprint viewer). You might want to cache this result as this may be costly. 
	const FBox Box = Actor->CalculateComponentsBoundingBoxInLocalSpace();
	const auto Transform = Actor->GetTransform();

	// Get World space Location.
	const FVector Center = Transform.TransformPosition(Box.GetCenter());

	// And World space extent
	const FVector Extent = Box.GetExtent();
	const FVector Forward = Transform.TransformVector(FVector::ForwardVector * Extent.X);
	const FVector Right = Transform.TransformVector(FVector::RightVector * Extent.Y);
	const FVector Up = Transform.TransformVector(FVector::UpVector * Extent.Z);

	// Now you have an oriented bounding box represented by a `Center` and three extent vectors.
	FL0OrientedBox OrientedBox;
	OrientedBox.Center = Center;
	OrientedBox.Forward = Forward;
	OrientedBox.Right = Right;
	OrientedBox.Up = Up;

	return OrientedBox;
}

Note that the DrawDebugBox function cannot be used directly because it expects an AABB. However, here’s a custom function that draws an OBB:

void UL0GameplayLibrary::DrawDebugOrientedBox(UWorld* World, const FL0OrientedBox& Box, const FColor& Color,
                                              float LifeTime)
{
	const FVector Center = Box.Center;
	const FVector Forward = Box.Forward;
	const FVector Right = Box.Right;
	const FVector Up = Box.Up;

	const FVector ExtentsX = Right;
	const FVector ExtentsY = Up;
	const FVector ExtentsZ = Forward;

	const FVector Corner1 = Center + ExtentsX + ExtentsY + ExtentsZ;
	const FVector Corner2 = Center + ExtentsX - ExtentsY + ExtentsZ;
	const FVector Corner3 = Center - ExtentsX - ExtentsY + ExtentsZ;
	const FVector Corner4 = Center - ExtentsX + ExtentsY + ExtentsZ;
	const FVector Corner5 = Center + ExtentsX + ExtentsY - ExtentsZ;
	const FVector Corner6 = Center + ExtentsX - ExtentsY - ExtentsZ;
	const FVector Corner7 = Center - ExtentsX - ExtentsY - ExtentsZ;
	const FVector Corner8 = Center - ExtentsX + ExtentsY - ExtentsZ;

	DrawDebugLine(World, Corner1, Corner2, Color, false, LifeTime);
	DrawDebugLine(World, Corner2, Corner3, Color, false, LifeTime);
	DrawDebugLine(World, Corner3, Corner4, Color, false, LifeTime);
	DrawDebugLine(World, Corner4, Corner1, Color, false, LifeTime);

	DrawDebugLine(World, Corner5, Corner6, Color, false, LifeTime);
	DrawDebugLine(World, Corner6, Corner7, Color, false, LifeTime);
	DrawDebugLine(World, Corner7, Corner8, Color, false, LifeTime);
	DrawDebugLine(World, Corner8, Corner5, Color, false, LifeTime);

	DrawDebugLine(World, Corner1, Corner5, Color, false, LifeTime);
	DrawDebugLine(World, Corner2, Corner6, Color, false, LifeTime);
	DrawDebugLine(World, Corner3, Corner7, Color, false, LifeTime);
	DrawDebugLine(World, Corner4, Corner8, Color, false, LifeTime);
}

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *