Unity 函数可以立即从 3D 管道访问 2D 框?

Unity function to access the 2D box immediately from the 3D pipeline?

在 Unity 中,假设您有一个 3D 对象,

当然,获得AABB是微不足道的,Unity有直接的功能,

(您可能必须以通常的方式“将渲染器的所有边界框相加”,没问题。)

所以 Unity 确实有一个直接的功能,可以立即为您提供 3D AABB 框,每帧都在内部 mesh/render 管道之外。

现在,对于所讨论的相机,按照定位,AABB 确实覆盖了某个 2D 边界框...

事实上...是否有某种内置的直接方法可以在 Unity 中找到橙色 2D 框?

问题 - Unity 是否具有立即从管道中给出 2D 平截头体框的功能?

(请注意,要手动执行此操作,您只需为 AABB 的 8 个点制作光线(或使用世界来筛选 space,如 D​​raco 所述,相同);将它们封装在 2D 中以制作橙色框.)

我不需要手动解决方案,我想问的是引擎是否每帧都以某种方式从管道中提供这个?

有电话吗?

(确实,要是有这个就更好了...)

我的感觉是

中的一项或全部

肯定会知道橙色框,甚至可能知道管道内的蓝色框,就在显卡旁边,就像它知道给定网格的 AABB 一样。

我们知道 Unity 允许您在给定网格的每一帧立即点击 AABB 3D 框:事实上,Unity 是否给出了此处所示的“2D 平截头体边界”?

据我所知,没有内置

然而,自己找到极端非常容易。获取网格的边界框(屏幕截图中显示的长方体)就是这样做的,您只是在转换后的 space.

中进行操作
  1. 遍历网格的所有顶点,执行以下操作:
  2. Transform 从本地到世界的点 space (这处理处理缩放和旋转)
  3. Transform 从世界 space 到屏幕 space
  4. 的点
  5. 确定新点的 X 和 Y 是否为 above/below 存储的 min/max 值,如果是,则用新值
  6. 更新存储的 min/max
  7. 遍历所有顶点后,您将有 4 个值:min-X、min-Y、max-X 和 max-Y。现在你可以构建你的边界矩形

您可能还希望先对模型执行 Gift Wrapping,然后只处理生成的凸包(因为不属于凸包的任何点都不会超出凸包的范围船体)。如果您打算在模型在屏幕上移动、缩放或旋转时绘制此屏幕 space 矩形,并且必须重新计算边界框,那么您需要这样做并缓存结果。

请注意,如果模型动画(例如,如果你的类人动物站起来做开合跳),这不会起作用。解决动画案例要困难得多,因为为了解决凸包问题,您必须将每个动画的每一帧都视为原始网格的一部分(以确保 none 的动画曾经移动过凸包外的部分网格),增加了一个幂的复杂度。

3D 边界框

  1. 获取给定的 GameObject 3D 边界框的中心和大小
  2. 计算8个角
  3. 将位置转换为 GUI space(屏幕 space)

函数 GUI3dRectWithObject 将 return 屏幕上给定游戏对象的 3D 边界框。

二维边界框

  1. 遍历给定游戏对象中的每个顶点
  2. 将每个顶点的位置转换为世界 space,并转换为 GUI space(屏幕 space)
  3. 找到 4 个角值:x1, x2, y1, y2

函数 GUI2dRectWithObject 将 return 屏幕上给定游戏对象的 2D 边界框。

代码

public static Rect GUI3dRectWithObject(GameObject go)
{

    Vector3 cen = go.GetComponent<Renderer>().bounds.center;
    Vector3 ext = go.GetComponent<Renderer>().bounds.extents;
    Vector2[] extentPoints = new Vector2[8]
    {
            WorldToGUIPoint(new Vector3(cen.x-ext.x, cen.y-ext.y, cen.z-ext.z)),
            WorldToGUIPoint(new Vector3(cen.x+ext.x, cen.y-ext.y, cen.z-ext.z)),
            WorldToGUIPoint(new Vector3(cen.x-ext.x, cen.y-ext.y, cen.z+ext.z)),
            WorldToGUIPoint(new Vector3(cen.x+ext.x, cen.y-ext.y, cen.z+ext.z)),
            WorldToGUIPoint(new Vector3(cen.x-ext.x, cen.y+ext.y, cen.z-ext.z)),
            WorldToGUIPoint(new Vector3(cen.x+ext.x, cen.y+ext.y, cen.z-ext.z)),
            WorldToGUIPoint(new Vector3(cen.x-ext.x, cen.y+ext.y, cen.z+ext.z)),
            WorldToGUIPoint(new Vector3(cen.x+ext.x, cen.y+ext.y, cen.z+ext.z))
    };
    Vector2 min = extentPoints[0];
    Vector2 max = extentPoints[0];
    foreach (Vector2 v in extentPoints)
    {
        min = Vector2.Min(min, v);
        max = Vector2.Max(max, v);
    }
    return new Rect(min.x, min.y, max.x - min.x, max.y - min.y);
}

public static Rect GUI2dRectWithObject(GameObject go)
{
    Vector3[] vertices = go.GetComponent<MeshFilter>().mesh.vertices;

    float x1 = float.MaxValue, y1 = float.MaxValue, x2 = 0.0f, y2 = 0.0f;

    foreach (Vector3 vert in vertices)
    {
        Vector2 tmp = WorldToGUIPoint(go.transform.TransformPoint(vert));

        if (tmp.x < x1) x1 = tmp.x;
        if (tmp.x > x2) x2 = tmp.x;
        if (tmp.y < y1) y1 = tmp.y;
        if (tmp.y > y2) y2 = tmp.y;
    }

    Rect bbox = new Rect(x1, y1, x2 - x1, y2 - y1);
    Debug.Log(bbox);
    return bbox;
}

public static Vector2 WorldToGUIPoint(Vector3 world)
{
    Vector2 screenPoint = Camera.main.WorldToScreenPoint(world);
    screenPoint.y = (float)Screen.height - screenPoint.y;
    return screenPoint;
}

参考:Is there an easy way to get on-screen render size (bounds)?