9

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

在此处输入图像描述

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

在此处输入图像描述

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

所以 Unity 确实有一个直接的功能,可以立即为您提供 3D AABB 盒子,而不是每帧的内部网格/渲染管道。

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

在此处输入图像描述

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

问题 - Unity 是否具有立即从管道中提供 2D 截锥体的功能?

(请注意,要手动执行此操作,您只需为 AABB 的 8 个点制作光线(或使用世界到屏幕空间,就像 Draco 提到的那样);将它们封装在 2D 中以制作橙色框。)

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

有电话吗?

(确实,如果有这个会更好......)

在此处输入图像描述

我的感觉是其中一个或所有

  • 特别是遮挡系统
  • 着色器
  • 渲染器

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

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

4

2 回答 2

2

据我所知,没有内置的

但是,自己找到极端确实非常容易。获取网格的边界框(屏幕截图中显示的长方体)就是这样做的方式,您只是在变换的空间中进行。

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

您可能还希望首先执行模型的礼品包装,并且只处理生成的凸包(因为不属于凸包的任何点都不会超出凸包的边界)。如果您打算在模型在屏幕上移动、缩放或旋转时绘制此屏幕空间矩形,并且必须重新计算边界框,那么您需要执行此操作并缓存结果。

请注意,如果模型具有动画效果(例如,如果您的类人机器人站起来并跳起千斤顶),这将不起作用解决动画案例要困难得多,因为您必须将每个动画的每一帧都视为原始网格的一部分,以便进行凸包求解(以确保您的任何动画都不会移动网格的一部分在凸包之外),以幂增加复杂性。

于 2018-08-18T18:48:51.030 回答
0

3D bounding box

  1. Get given GameObject 3D bounding box's center and size
  2. Compute 8 corners
  3. Transform positions to GUI space (screen space)

Function GUI3dRectWithObject will return the 3D bounding box of given GameObject on screen.

2D bounding box

  1. Iterate through every vertex in a given GameObject
  2. Transform every vertex's position to world space, and transform to GUI space (screen space)
  3. Find 4 corner value: x1, x2, y1, y2

Function GUI2dRectWithObject will return the 2D bounding box of given GameObject on screen.

Code

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;
}

Example

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

于 2019-02-17T06:15:41.263 回答