Unity Bound详解

内容将会持续更新,有错误的地方欢迎指正,谢谢!
 

Unity Bound详解
     


TechX 坚持将创新的科技带给世界!

拥有更好的学习体验 —— 不断努力,不断进步,不断探索

TechX —— 心探索、心进取!

助力快速掌握 Bounds

为初学者节省宝贵的学习时间,避免困惑!

在这里插入图片描述



一、Bounds概述

1、Bounds类型

在 Unity 中,包围盒(Bounding Box)是一个几何形状,用于近似地表示物体或一组物体在三维空间中的范围或边界。它是一个简单的形状,通常是立方体或矩形,完全包围了一个物体或一组物体。

包围盒有多种类型,包括:

  • AABB(Axis-Aligned Bounding Box,轴对齐包围盒): 这是一种以坐标轴为方向的包围盒,其六个面都与坐标轴平行。AABB 在处理物体的碰撞检测、物体的可见性检查和简单的物体包围优化方面非常高效。

  • OBB(Oriented Bounding Box,方向包围盒): 这是一种可以沿着物体的方向进行旋转的包围盒。与 AABB 不同,OBB 可以根据物体的朝向而自由旋转,因此更精确地包围了物体,但计算量也更大。

  • Sphere Bounds(球形包围盒): 这是一个包围物体的球体,通常用于物体的碰撞检测或可见性检查。对于不规则形状的物体,球形包围盒可能不是最精确的表示,但它提供了一种简单和快速的碰撞检测方法。

2、Bounds属性

在 Unity 中,许多对象都有一个 Bounds 属性,用于描述该对象的包围盒。例如,Renderer、Collider 和 Mesh 等组件都具有 Bounds 属性,这些属性用于表示对象或物体的包围盒。Bounds 的属性通常包括包围盒的中心点位置和尺寸。

在这里插入图片描述

size 包围盒的尺寸,它描述了包围盒在三个轴(X、Y 和 Z 轴)方向上的宽度、高度和深度。
center 包围盒的中心点位置,这个中心点是包围盒所囊括的对象或物体的几何中心。
extents 表示是 size 属性的一半,它表示包围盒在每个轴上的正向半尺寸。
min (世界坐标)边界盒的最小点,这个值总是等于center-extents。
max (世界坐标)边界盒的最大点,这个值总是等于center+extents。
ClosestPoint(Vector3 point) 用于找到包围盒上离给定点最近的点。传入一个点的 Vector3 坐标,返回包围盒上距离该点最近的点的坐标。
Contains(Vector3 point) 检查一个点是否在包围盒内部。传入一个 Vector3 坐标表示的点,如果点在包围盒内部,返回 true;否则返回 false。
Encapsulate(Bounds bounds) 用于扩展包围盒以包含另一个 Bounds 对象。传入一个 Bounds 对象,该方法会调整当前包围盒,使其完全包含传入的 Bounds 对象。
Encapsulate(Vector3 point) 用于扩展包围盒,使其包括给定点。传入一个点的 Vector3 坐标,这个点将被包围盒完全包含。
SetMinMax(Vector3 min, Vector3 max) 根据最小和最大顶点的坐标来设置包围盒。传入最小和最大顶点的坐标 Vector3 值,以重新定义包围盒的位置和大小。
Expand(float amount) 通过在每个轴上扩展包围盒的尺寸来调整包围盒的大小。传入一个浮点数 amount,这个值将分别添加到包围盒的宽度、高度和深度上。

二、Unity中的Bounds

1、Renderer Bounds(渲染器包围盒)

Renderer(渲染器)是将图形渲染到屏幕上的组件。每个 Renderer 都有一个 Bounds 属性,该属性表示该渲染器所渲染内容的包围盒。该包围盒由该 Renderer 下所有渲染的网格(Mesh)的合并包围而成。通常用于确定对象的可见性以进行相机裁剪。

绘制Renderer Bounds:

public class MyComponent : MonoBehaviour
{
	//Renderer Bounds为世界坐标
    private Bounds bounds;
	private MeshRenderer renderer;

    void OnDrawGizmos()
    {
        // 获取物体的 MeshRenderer 组件
        renderer = GetComponent<MeshRenderer>();
        bounds = renderer.bounds;
        
        // 设置 Gizmos 的颜色
        Gizmos.color = Color.green;
        Gizmos.DrawWireCube(bounds.center, bounds.size);
    }
}
  • 位移对 Render Bounds 的影响:

当物体发生位移时,渲染器的 Bounds 将会相应地跟随物体的移动而更新。此时,渲染器的 Bounds 也会随之移动,以确保正确的可见性计算。

在这里插入图片描述

  • 旋转对 Render Bounds 的影响:

当物体发生旋转时,渲染器的 Bounds 将会进行相应的更新。与位移不同,旋转会导致包围盒的大小发生变化,但是并不会随着物体的旋转而旋转。

在这里插入图片描述

  • 缩放对 Render Bounds 的影响:

当物体发生缩放时,渲染器的 Bounds 将根据缩放而相应地进行更新,此时,渲染器的 Bounds 也会随之缩放,以确保正确的包围盒。

在这里插入图片描述

2、Collider Bounds(碰撞器包围盒)

Collider(碰撞器)是用于检测碰撞的组件。各种类型的碰撞器(如 BoxCollider、SphereCollider 等)都有一个 Bounds 属性,表示碰撞器的包围盒。这个包围盒用于计算碰撞,触发碰撞事件或进行物理模拟。

绘制Collider Bounds:

public class MyComponent : MonoBehaviour
{
	//Collider Bounds为世界坐标
    private Bounds bounds;
	private BoxCollider boxCollider;

    void OnDrawGizmos()
    {
         //获取物体的 BoxCollider组件
         boxCollider = GetComponent<BoxCollider>();
         bounds = boxCollider.bounds;
        
        // 设置 Gizmos 的颜色
        Gizmos.color = Color.green;
        Gizmos.DrawWireCube(bounds.center, bounds.size);
    }
}
  • 位移对 Collider Bounds 的影响:

当物体发生位移时,渲染器的 Bounds 将会相应地跟随物体的移动而更新。此时,渲染器的 Bounds 也会随之移动,以确保正确的可见性计算。

在这里插入图片描述

  • 旋转对 Collider Bounds 的影响:

当物体发生旋转时,渲染器的 Bounds 将会进行相应的更新。与位移不同,旋转会导致包围盒的大小发生变化,但是并不会随着物体的旋转而旋转。

在这里插入图片描述

  • 缩放对 Collider Bounds 的影响:

当物体发生缩放时,渲染器的 Bounds 将根据缩放而相应地进行更新,此时,渲染器的 Bounds 也会随之缩放,以确保正确的包围盒。

在这里插入图片描述

3、Mesh Bounds(网格包围盒)

Mesh 是表示三维对象表面的集合,而 MeshRenderer 用于渲染这些 Mesh。每个 Mesh 也有一个 Bounds 属性,表示该网格的包围盒。这个包围盒通常是由网格的顶点位置计算得出的最小包围盒,用于优化渲染和碰撞检测。

绘制Mesh Bounds:

public class MyComponent : MonoBehaviour
{
	//Mesh Bounds为本地坐标
    private Bounds bounds;
	private MeshFilter filter ;

    void OnDrawGizmos()
    {
          获取物体的 MeshFilter组件
         MeshFilter filter = GetComponent<MeshFilter>();
         bounds = filter.sharedMesh.bounds;
         //将本地坐标转换未为世界坐标
         var centerPoint = transform.TransformPoint(bounds.center);
         bounds = new Bounds(centerPoint, bounds.size);
        
        // 设置 Gizmos 的颜色
        Gizmos.color = Color.green;
        Gizmos.DrawWireCube(bounds.center, bounds.size);
    }
}
  • 位移对 Mesh Bounds 的影响:

当物体发生位移时,渲染器的 Bounds 将会相应地跟随物体的移动而更新。此时,渲染器的 Bounds 也会随之移动,以确保正确的可见性计算。

在这里插入图片描述

  • 旋转对 Collider Bounds 的影响:
  • 缩放对 Collider Bounds 的影响:

Mesh 的 Bounds 是在创建 Mesh 时根据其顶点位置计算得出的最小包围盒。这个包围盒通常在创建 Mesh 时就已经固定,并不会随着对象的缩放或旋转而实时更新。

所以,当对物体进行缩放或旋转时,Mesh Bounds 并不会实时更新以适应这些变化。即使缩放或旋转了对象,Mesh Bounds 也仍然保持着原始计算得出的包围盒形状和大小。

在这里插入图片描述
在这里插入图片描述

三、Bounds和Collider 的区别

  • Collider 中的包围盒(OBB):

Collider 组件通常根据对象的形状来创建相应的碰撞区域(例如,BoxCollider、SphereCollider 等)。这些 Collider 使用的包围盒通常是有向包围盒(OBB),也就是说,它们可以随着对象的旋转而旋转,并根据对象的形状而形成相应的碰撞区域。

OBB 提供了更好的检测精度,因为它可以更好地适应对象的形状和旋转。

public class MyComponent : MonoBehaviour
{
	private BoxCollider boxCollider;

    void OnDrawGizmos()
    {
         //获取物体的 BoxCollider组件
         boxCollider = GetComponent<BoxCollider>();
         
         // 设置 Gizmos 的颜色
         Gizmos.color = Color.green;
         Matrix4x4 rotationMatrix = Matrix4x4.TRS(transform.position, transform.rotation, transform.lossyScale);
         // 根据物体的变换,绘制实时的 Bounds
         Matrix4x4 oldMatrix = Gizmos.matrix;
         Gizmos.matrix = rotationMatrix;
         Gizmos.DrawWireCube(boxCollider.center, boxCollider.size);
         Gizmos.matrix = oldMatrix;
    }
}
  • Bounds 中的包围盒(AABB):

Bounds 包围盒通常是无向包围盒(AABB)。这意味着它不会随着对象的旋转而旋转,而是始终保持沿着坐标轴的方向。

AABB 通常用于快速包围物体,但在对象旋转时可能无法准确地包裹对象的形状,因为它是固定的沿坐标轴的边界框。

四、Bounds的相关计算

1、计算Bounds顶点

/// <summary> Bounds顶点 </summary>
/// <param name="bounds"></param>
public Vector3[] DrawBoundBoxLine(Bounds bounds)
{
    //计算出包围盒8个点
    Vector3 min = bounds.min;
    Vector3 max = bounds.max;
    Vector3[] vertices = new Vector3[8];

    // 计算八个顶点的坐标
    vertices[0] = new Vector3(min.x, min.y, min.z);
    vertices[1] = new Vector3(max.x, min.y, min.z);
    vertices[2] = new Vector3(min.x, min.y, max.z);
    vertices[3] = new Vector3(max.x, min.y, max.z);
    vertices[4] = new Vector3(min.x, max.y, min.z);
    vertices[5] = new Vector3(max.x, max.y, min.z);
    vertices[6] = new Vector3(min.x, max.y, max.z);
    vertices[7] = new Vector3(max.x, max.y, max.z);
	return vertices;
}

2、扩展多个Bounds

public class MyComponent : MonoBehaviour
{
	private Bounds bounds;
	
	/// <summary> 扩展Bounds </summary>
	/// <param name="model"></param>
	public Bounds ExtendBound(Transform model)
	{
		Vector3 center = Vector3.zero;
		Renderer[] renders = model.GetComponentsInChildren<Renderer>();
		
		foreach (Renderer child in renders){
			center += child.bounds.center;   
		}
		
		center /= model.GetComponentsInChildren<Transform>().Length; 
		Bounds bounds = new Bounds(center,Vector3.zero);
		
		foreach (Renderer child in renders)
		{
			bounds.Encapsulate(child.bounds);   
		}
		return bounds;
	}
	
	void OnDrawGizmos()
	{
	    bounds = ExtendBound(transform);
	     设置 Gizmos 的颜色
	    Gizmos.color = Color.green;
	    Gizmos.DrawWireCube(bounds.center, bounds.size);
	}
}


TechX —— 心探索、心进取!

每一次跌倒都是一次成长

每一次努力都是一次进步


END

感谢您阅读本篇博客!希望这篇内容对您有所帮助。如果您有任何问题或意见,或者想要了解更多关于本主题的信息,欢迎在评论区留言与我交流。我会非常乐意与大家讨论和分享更多有趣的内容。
如果您喜欢本博客,请点赞和分享给更多的朋友,让更多人受益。同时,您也可以关注我的博客,以便及时获取最新的更新和文章。
在未来的写作中,我将继续努力,分享更多有趣、实用的内容。再次感谢大家的支持和鼓励,期待与您在下一篇博客再见!

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码

)">
< <上一篇
下一篇>>