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,如 Draco 所述,相同);将它们封装在 2D 中以制作橙色框.)
我不需要手动解决方案,我想问的是引擎是否每帧都以某种方式从管道中提供这个?
有电话吗?
(确实,要是有这个就更好了...)
我的感觉是
中的一项或全部
- 特别是遮挡系统
- 着色器
- 渲染器
肯定会知道橙色框,甚至可能知道管道内的蓝色框,就在显卡旁边,就像它知道给定网格的 AABB 一样。
我们知道 Unity 允许您在给定网格的每一帧立即点击 AABB 3D 框:事实上,Unity 是否给出了此处所示的“2D 平截头体边界”?
据我所知,没有内置。
然而,自己找到极端非常容易。获取网格的边界框(屏幕截图中显示的长方体)就是这样做的,您只是在转换后的 space.
中进行操作
- 遍历网格的所有顶点,执行以下操作:
- Transform 从本地到世界的点 space (这处理处理缩放和旋转)
- Transform 从世界 space 到屏幕 space
的点
- 确定新点的 X 和 Y 是否为 above/below 存储的 min/max 值,如果是,则用新值
更新存储的 min/max
- 遍历所有顶点后,您将有 4 个值:min-X、min-Y、max-X 和 max-Y。现在你可以构建你的边界矩形
您可能还希望先对模型执行 Gift Wrapping,然后只处理生成的凸包(因为不属于凸包的任何点都不会超出凸包的范围船体)。如果您打算在模型在屏幕上移动、缩放或旋转时绘制此屏幕 space 矩形,并且必须重新计算边界框,那么您需要这样做并缓存结果。
请注意,如果模型动画(例如,如果你的类人动物站起来做开合跳),这不会起作用。解决动画案例要困难得多,因为为了解决凸包问题,您必须将每个动画的每一帧都视为原始网格的一部分(以确保 none 的动画曾经移动过凸包外的部分网格),增加了一个幂的复杂度。
3D 边界框
- 获取给定的 GameObject 3D 边界框的中心和大小
- 计算8个角
- 将位置转换为 GUI space(屏幕 space)
函数 GUI3dRectWithObject
将 return 屏幕上给定游戏对象的 3D 边界框。
二维边界框
- 遍历给定游戏对象中的每个顶点
- 将每个顶点的位置转换为世界 space,并转换为 GUI space(屏幕 space)
- 找到 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)?
在 Unity 中,假设您有一个 3D 对象,
当然,获得AABB是微不足道的,Unity有直接的功能,
(您可能必须以通常的方式“将渲染器的所有边界框相加”,没问题。)
所以 Unity 确实有一个直接的功能,可以立即为您提供 3D AABB 框,每帧都在内部 mesh/render 管道之外。
现在,对于所讨论的相机,按照定位,AABB 确实覆盖了某个 2D 边界框...
事实上...是否有某种内置的直接方法可以在 Unity 中找到橙色 2D 框?
问题 - Unity 是否具有立即从管道中给出 2D 平截头体框的功能?
(请注意,要手动执行此操作,您只需为 AABB 的 8 个点制作光线(或使用世界来筛选 space,如 Draco 所述,相同);将它们封装在 2D 中以制作橙色框.)
我不需要手动解决方案,我想问的是引擎是否每帧都以某种方式从管道中提供这个?
有电话吗?
(确实,要是有这个就更好了...)
我的感觉是
中的一项或全部- 特别是遮挡系统
- 着色器
- 渲染器
肯定会知道橙色框,甚至可能知道管道内的蓝色框,就在显卡旁边,就像它知道给定网格的 AABB 一样。
我们知道 Unity 允许您在给定网格的每一帧立即点击 AABB 3D 框:事实上,Unity 是否给出了此处所示的“2D 平截头体边界”?
据我所知,没有内置。
然而,自己找到极端非常容易。获取网格的边界框(屏幕截图中显示的长方体)就是这样做的,您只是在转换后的 space.
中进行操作- 遍历网格的所有顶点,执行以下操作:
- Transform 从本地到世界的点 space (这处理处理缩放和旋转)
- Transform 从世界 space 到屏幕 space 的点
- 确定新点的 X 和 Y 是否为 above/below 存储的 min/max 值,如果是,则用新值 更新存储的 min/max
- 遍历所有顶点后,您将有 4 个值:min-X、min-Y、max-X 和 max-Y。现在你可以构建你的边界矩形
您可能还希望先对模型执行 Gift Wrapping,然后只处理生成的凸包(因为不属于凸包的任何点都不会超出凸包的范围船体)。如果您打算在模型在屏幕上移动、缩放或旋转时绘制此屏幕 space 矩形,并且必须重新计算边界框,那么您需要这样做并缓存结果。
请注意,如果模型动画(例如,如果你的类人动物站起来做开合跳),这不会起作用。解决动画案例要困难得多,因为为了解决凸包问题,您必须将每个动画的每一帧都视为原始网格的一部分(以确保 none 的动画曾经移动过凸包外的部分网格),增加了一个幂的复杂度。
3D 边界框
- 获取给定的 GameObject 3D 边界框的中心和大小
- 计算8个角
- 将位置转换为 GUI space(屏幕 space)
函数 GUI3dRectWithObject
将 return 屏幕上给定游戏对象的 3D 边界框。
二维边界框
- 遍历给定游戏对象中的每个顶点
- 将每个顶点的位置转换为世界 space,并转换为 GUI space(屏幕 space)
- 找到 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)?