内容将会持续更新,有错误的地方欢迎指正,谢谢!
拥有更好的学习体验 —— 不断努力,不断进步,不断探索 |
助力快速掌握 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)。这意味着它不会随着对象的旋转而旋转,而是始终保持沿着坐标轴的方向。文章来源:https://www.toymoban.com/news/detail-825573.html
AABB 通常用于快速包围物体,但在对象旋转时可能无法准确地包裹对象的形状,因为它是固定的沿坐标轴的边界框。文章来源地址https://www.toymoban.com/news/detail-825573.html
四、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);
}
}
每一次跌倒都是一次成长 每一次努力都是一次进步 |
如果您喜欢本博客,请点赞和分享给更多的朋友,让更多人受益。同时,您也可以关注我的博客,以便及时获取最新的更新和文章。
在未来的写作中,我将继续努力,分享更多有趣、实用的内容。再次感谢大家的支持和鼓励,期待与您在下一篇博客再见!
到了这里,关于Unity Bound详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!