Random Point on BoundingBox Perimeter

Kismet has a function for random point in bounding box, but I’m looking for a random point along a bounding box perimeter.

I have a fixed location for the bounding box origin and have access to the box extent.

Thanks,
Mark

Why not just pick a random pair of coordiates from the box extent (in world space) and get a random distance between them (clamped with thir own dustance) as the offset?

Oh and uou need a function to check that the verts are on the same plane (not diagonally across from each other)

Hi thanks for the reply. I’m not sure I understand your suggestion. I might not have explained what I’m looking for well enough.

The final result that I’m looking for is the random point on the bounding box perimeter. If i picked two coordinates in the box extent and got their distance, what exactly would that be accomplishing?

I don’t know if this help you and if I understood what you need.
You want a point from the SURFACE of the bounding box instead
a random point of the VOLUME?

What about this:

put a cube in the location of the bounding box and same dimmensions
The cube is just to generate a trace hit.

Then you make a trace by channel from a random place of the outside to the center of the cube…something similar to this:

1 Like

Oh I think a line trace could work. I should’ve mentioned that I’m using the bounding box as a 2-dimensional square, with the X value of the box extent being zero.

wait…you want a point in the perimeter of a 2D box??

how about this:

basically it takes a random value for X and Y (like in the surface) and then it
‘clamps’ the value to one of the 4 sides

1 Like

:expressionless: So not something like this at all?

1 Like

Sorry! I’m still interested in how you accomplished this if you’re willing to share. Eventually I’ll have to implement in 3D, but for now I’m doing 2D.

It’s this:

But something is not entirely correct here, it seems to overfocus on the edges too much. Would like to fix it up but need to fix dinner first ;p

Do experiment with the Vector Bounded to Box node - perhaps it will get you there.

1 Like

I like the approach. Just wondering why it seems hit points tend so much to the edges of the box

I had had to do something similar in the past but couldn’t get the distribution right. What I ended up doing was tracing from a random point on the sphere surface towards a random point in the volume.

And then finding Closest Point on Line :person_shrugging: It was too long ago. This created no hot-spots afaik.

There might be a better way.

1 Like

To elaborate on this:




PointsInBounds

5 Likes

If you want the points to be evenly distributed across the surface, you need to do this in two steps:

  1. Determine which face to put the point on. Each face needs to be picked with a relative probability of the area of that face.
  2. Once the face is determined, pick a random point on the face. This can easily be done by scaling barycentric 0…1 coordinates for “u” and “v” along the two face basis (edge) vectors.
2 Likes

BoundedToBox sticks to the egdes because it’s a simple clamp, no projection.
The sphere has to be larger than the box, so it has high chance of generating points where two axis (say X and Y) are both larger than box extent. BoundedToBox will simply clamp that to BoxExtent.X and BoxExtent.Y so the points end up on egde.

Here’s my attempt :stuck_out_tongue:

FVector RandomPointOnBoundingBoxPerimeter(FVector Origin, FVector BoxExtent)
{
	const FVector Dir = FMath::VRand();
	const FVector Dist = BoxExtent / Dir;
	return Origin + Dir * Dist.GetAbsMin();
}
1 Like

Since my question (although vague) was how to choose a random point on the perimeter of a 2D box, @eldany.uy was the first to point me in the right direction. This is how I ended up implemented in C++. I’m kind of embarrassed I didn’t think of this before… but I’m glad there was also a discussion about how to do it in 3D. Thanks everyone!

SpawnLocation = BoxBounds.Origin;
// Y is left-right Z is up-down
const float OffsetX = 0.f;
float OffsetY;
float OffsetZ;
if (const int32 RandomDirection = UKismetMathLibrary::RandomIntegerInRange(0, 3); 
	RandomDirection == 0)
{
	// top
	OffsetY = UKismetMathLibrary::RandomFloatInRange(-ScaledBoxBounds.Y, ScaledBoxBounds.Y);
	OffsetZ = ScaledBoxBounds.Z;
}
else if (RandomDirection == 1)
{
	// right
	OffsetY = ScaledBoxBounds.Y;
	OffsetZ = UKismetMathLibrary::RandomFloatInRange(-ScaledBoxBounds.Z, ScaledBoxBounds.Z);
}
else if (RandomDirection == 2)
{
	// left
	OffsetY = -ScaledBoxBounds.Y;
	OffsetZ = UKismetMathLibrary::RandomFloatInRange(-ScaledBoxBounds.Z, ScaledBoxBounds.Z);
}
else
{
	// bottom
	OffsetY = UKismetMathLibrary::RandomFloatInRange(-ScaledBoxBounds.Y, ScaledBoxBounds.Y);
	OffsetZ = -ScaledBoxBounds.Z;
}
FVector Offset = { OffsetX, OffsetY, OffsetZ };
SpawnLocation = FirstSpawnLocation + Offset;
2 Likes

Glad to help in the brainstorming process!
There are always a lot of ways of achieve a goal and
I am sure there are many better than this one but hey! it works :slight_smile:

instead of nested If conditions you can use switch like this:

switch (RandomDirection)
{
case 0:

	// top
	OffsetY = UKismetMathLibrary::RandomFloatInRange(-ScaledBoxBounds.Y, ScaledBoxBounds.Y);
	OffsetZ = ScaledBoxBounds.Z;

case 1:

	// right
	OffsetY = ScaledBoxBounds.Y;
	OffsetZ = UKismetMathLibrary::RandomFloatInRange(-ScaledBoxBounds.Z, ScaledBoxBounds.Z);

case 2:

	// left
	OffsetY = -ScaledBoxBounds.Y;
	OffsetZ = UKismetMathLibrary::RandomFloatInRange(-ScaledBoxBounds.Z, ScaledBoxBounds.Z);

default:

// bottom
	OffsetY = UKismetMathLibrary::RandomFloatInRange(-ScaledBoxBounds.Y, ScaledBoxBounds.Y);
	OffsetZ = -ScaledBoxBounds.Z;

}






Greetz!
Dany

1 Like

Thank you so much for providing this approach!!

2 Likes