0 votes

I have a rotated BoxShape and given a point outside the shape, I would like to find the closest point that lies on the shape towards that point.

I have developed a method that can do this for non rotated boxes but I am struggling with the math required to do this for a rotated box.

public static Vector3 GetClosestPoint(this BoxShape box, Transform boxTransform, Vector3 p)
  Vector3 worldPoint = Vector3.Zero;

  float boxX1 = boxTransform.origin.x - box.Extents.x;
  float boxX2 = boxTransform.origin.x + box.Extents.x;

  float boxY1 = boxTransform.origin.y - box.Extents.y;
  float boxY2 = boxTransform.origin.y + box.Extents.y;

  float boxZ1 = boxTransform.origin.z - box.Extents.z;
  float boxZ2 = boxTransform.origin.z + box.Extents.z;

  worldPoint.x = Mathf.Clamp(p.x, boxX1, boxX2);
  worldPoint.y = Mathf.Clamp(p.y, boxY1, boxY2);
  worldPoint.z = Mathf.Clamp(p.z, boxZ1, boxZ2);

  return worldPoint;

Solutions I found online say to make the box axis-aligned first but I am unsure how to go about doing that in Godot.

Here are some stack exchange links discussing this:
- https://math.stackexchange.com/questions/3517305/finding-the-nearest-least-distance-point-on-a-cube-from-a-point-lying-outside
- https://math.stackexchange.com/questions/2296533/shortest-distance-between-rectangular-cuboid-and-point-in-3d-space

I am using C# but solutions in GDScript are welcome as I can easily translate between the two.

Godot version 3.5.stable.mono
in Engine by (62 points)
edited by

Just as an off-the-wall suggestion, you can probably also do this with a temporary Area2D and a RayCast2D...

Where would I cast the ray towards though? If I cast it towards the box origin then that wouldn't necessarily get me the closest point and the longer the box the more inaccurate it's going to be.

Re-reading the above, I think I misunderstood what you're trying to do. And, you're right. I don't think my suggestion is helpful here... :(

Here's another SO hit for your trouble though... :)


I realize I'm continuing to be unhelpful here as I was assuming 2D, but now I realize you're working with 3D data...

One point of clarification... I assume you're looking for the closest point that lies anywhere on the surface of your BoxShape, right? That is, you're not just looking for the closest existing point from the BoxShape data, right?

Yes, the closest point could be anywhere on the corner, edge or face of the box or even inside the box itself if the point we're inputting is inside the box itself.

1 Answer

0 votes
Best answer

I managed to solve this thanks to this Stack Overflow question/answer https://stackoverflow.com/questions/44824512/how-to-find-the-closest-point-on-a-right-rectangular-prism-3d-rectangle

Solution as depicted in the link above: "Project the point onto each independent axis of the 3D rectangle to find the scalar parameters of the projection. Then saturate the scalar parameters at the limit of the faces. Then sum the components to get the answer"

Here's the working code.

public static Vector3 GetClosestPoint(this BoxShape box, Transform boxTransform, Vector3 p)
  Vector3 origin = boxTransform.Xform(new Vector3(-box.Extents.x, -box.Extents.y, -box.Extents.z));

  Vector3 px = boxTransform.Xform(new Vector3(box.Extents.x, -box.Extents.y, -box.Extents.z));
  Vector3 py = boxTransform.Xform(new Vector3(-box.Extents.x, box.Extents.y, -box.Extents.z));
  Vector3 pz = boxTransform.Xform(new Vector3(-box.Extents.x, -box.Extents.y, box.Extents.z));

  Vector3 vx = (px - origin);
  Vector3 vy = (py - origin);
  Vector3 vz = (pz - origin);

  var tx = vx.Dot(p - origin) / vx.LengthSquared();
  var ty = vy.Dot(p - origin) / vy.LengthSquared();
  var tz = vz.Dot(p - origin) / vz.LengthSquared();

  tx = tx < 0 ? 0 : tx > 1 ? 1 : tx;
  ty = ty < 0 ? 0 : ty > 1 ? 1 : ty;
  tz = tz < 0 ? 0 : tz > 1 ? 1 : tz;

  Vector3 worldPoint = tx * vx + ty * vy + tz * vz + origin;

  return worldPoint;
by (62 points)
Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read Frequently asked questions and How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to [email protected] with your username.