如何判断世界空间点是否在由Transform定义的盒子范围内?
问题:判断世界空间点是否在Transform定义的虚拟盒子内
我有一个对象,其Transform的position、rotation、scale分别代表一个盒子的位置、旋转与缩放。需要判断一个Vector3类型的世界空间点是否处于该虚拟盒子的范围内。
可以通过给该对象挂载默认比例的Cube子物体,或使用以下Gizmo代码查看这个虚拟盒子:
private void OnDrawGizmos() { Gizmos.color = Color.blue; Gizmos.matrix = Matrix4x4.TRS(transform.position, transform.rotation, transform.localScale); Gizmos.DrawWireCube(Vector3.zero, Vector3.one); }
需要判断类似new Vector3(0.98f, 3.2f, 1.26f)这样的世界坐标点是否在Gizmo绘制的区域内。
已尝试的方法
- 知道可以用碰撞体(如
BoxCollider.ClosestPoint)轻松解决,但场景中会在运行时创建大量GameObject组成迷宫,不需要物理系统,碰撞体可能干扰游戏其他部分,因此不能使用。 - 网格渲染的绘制网格或bounds可能与要测试的盒子不完全匹配,视觉表现和逻辑不一致,因此也无法使用。
- 尝试使用
thatObjectWithGizmo.InverseTransformPoint(myWorldPoint)将世界点转换为本地坐标,并用以下代码测试,但返回了错误结果:
public class ScriptToTestPoint : MonoBehaviour { public Transform thatObjectWithGizmo; public Vector3 myWorldPoint; public void OnDrawGizmos() { Vector3 resultingPosition = thatObjectWithGizmo.InverseTransformPoint(myWorldPoint); bool isInside = new Bounds(thatObjectWithGizmo.position, thatObjectWithGizmo.lossyScale).Contains(resultingPosition); Gizmos.color = isInside ? Color.red : Color.white; Gizmos.DrawSphere(transform.position, 1f); } }
正确的判断方法
你的核心思路(将世界点转换到本地空间)是对的,但错误在于创建Bounds时用了世界空间的参数来匹配本地坐标。正确的做法是:
- 将世界空间点转换为目标对象的本地空间坐标:使用
InverseTransformPoint,这一步你已经做对了。 - 检查转换后的本地点是否在本地空间中以原点为中心、边长为1的立方体范围内——这正好对应Gizmo绘制的盒子。
可以用两种方式实现判断:
方式一:直接判断分量范围
因为本地空间的盒子中心在原点,边长为1,所以每个轴的范围是[-0.5, 0.5],直接判断转换后的点每个分量的绝对值是否≤0.5即可:
public class ScriptToTestPoint : MonoBehaviour { public Transform thatObjectWithGizmo; public Vector3 myWorldPoint; public void OnDrawGizmos() { Vector3 localPoint = thatObjectWithGizmo.InverseTransformPoint(myWorldPoint); // 判断每个轴是否在[-0.5, 0.5]区间内 bool isInside = Mathf.Abs(localPoint.x) <= 0.5f && Mathf.Abs(localPoint.y) <= 0.5f && Mathf.Abs(localPoint.z) <= 0.5f; Gizmos.color = isInside ? Color.red : Color.white; Gizmos.DrawSphere(myWorldPoint, 0.1f); // 直接在测试点绘制球体更直观 } }
方式二:使用Bounds判断
创建一个中心在Vector3.zero、大小为Vector3.one的Bounds,用它来检查转换后的本地点:
public class ScriptToTestPoint : MonoBehaviour { public Transform thatObjectWithGizmo; public Vector3 myWorldPoint; // 可以提前创建Bounds,避免每次OnDrawGizmos都实例化 private readonly Bounds _localBoxBounds = new Bounds(Vector3.zero, Vector3.one); public void OnDrawGizmos() { Vector3 localPoint = thatObjectWithGizmo.InverseTransformPoint(myWorldPoint); bool isInside = _localBoxBounds.Contains(localPoint); Gizmos.color = isInside ? Color.red : Color.white; Gizmos.DrawSphere(myWorldPoint, 0.1f); } }
这两种方式都能准确匹配Gizmo绘制的虚拟盒子范围,且完全不需要依赖物理系统或网格组件。
内容的提问来源于stack exchange,提问作者E. Zacarias
相关产品推荐
相关产品推荐

