Unity功能可以立即从3D管道访问2D盒子?

问题描述 投票:5回答:2

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

enter image description here

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

enter image description here

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

So Unity does indeed have a direct function to give you the 3D AABB box instantly, out of the internal mesh/render pipeline every frame.

现在,对于相关的摄像机,如同定位,AABB确实覆盖了某个2D边界框......

enter image description here

事实上......是否有某种内置的直接方式在Unity中找到橙色的2D盒子?

Question - does Unity have a function which immediately gives that 2D frustrum box from the pipeline?

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

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

有电话吗?

(事实上​​,拥有它会更好......)

enter image description here

我的感觉是一个或全部

  • 特别是闭塞系统
  • 着色器
  • 渲染器

肯定会知道橙色的盒子,甚至是管道内的蓝色盒子,就在显卡的正上方,就像知道给定网格的AABB一样。

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

unity3d 3d game-physics aabb
2个回答
2
投票

As far as I am aware, there is no built in for this.

然而,自己找到极端非常容易。获取网格的边界框(截图中显示的长方体)就是如何完成的,你只是在变换的空间中进行。

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

您可能还希望首先执行模型的Gift Wrapping,并且仅处理所得到的凸包(因为没有凸出船体的一部分将不会出现在凸包的边界之外)。如果您打算在模型移动,缩放或在屏幕上旋转时绘制此屏幕空间矩形,并且必须重新计算边界框,那么您将要执行此操作并缓存结果。

请注意,如果模型具有动画效果(例如,如果您的人形机器人站起来并且跳跃插孔),则此功能无效。解决动画案例要困难得多,因为你必须将每个动画的每一帧视为原始网格的一部分,以便进行凸包解决(以确保你的动画都不会移动网格的一部分)在凸包外面),通过功率增加复杂性。


0
投票

3D边界框

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

函数GUI3dRectWithObject将在屏幕上返回给定GameObject的3D边界框。

2D边界框

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

函数GUI2dRectWithObject将在屏幕上返回给定GameObject的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;
}

Example

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

© www.soinside.com 2019 - 2024. All rights reserved.