赞
踩
内容将会持续更新,有错误的地方欢迎指正,谢谢!
拥有更好的学习体验 —— 不断努力,不断进步,不断探索 |
助力快速掌握 Bounds 为初学者节省宝贵的学习时间,避免困惑! |
在 Unity 中,包围盒(Bounding Box)是一个几何形状,用于近似地表示物体或一组物体在三维空间中的范围或边界。它是一个简单的形状,通常是立方体或矩形,完全包围了一个物体或一组物体。
包围盒有多种类型,包括:
AABB(Axis-Aligned Bounding Box,轴对齐包围盒): 这是一种以坐标轴为方向的包围盒,其六个面都与坐标轴平行。AABB 在处理物体的碰撞检测、物体的可见性检查和简单的物体包围优化方面非常高效。
OBB(Oriented Bounding Box,方向包围盒): 这是一种可以沿着物体的方向进行旋转的包围盒。与 AABB 不同,OBB 可以根据物体的朝向而自由旋转,因此更精确地包围了物体,但计算量也更大。
Sphere 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,这个值将分别添加到包围盒的宽度、高度和深度上。 |
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); } }
当物体发生位移时,渲染器的 Bounds 将会相应地跟随物体的移动而更新。此时,渲染器的 Bounds 也会随之移动,以确保正确的可见性计算。
当物体发生旋转时,渲染器的 Bounds 将会进行相应的更新。与位移不同,旋转会导致包围盒的大小发生变化,但是并不会随着物体的旋转而旋转。
当物体发生缩放时,渲染器的 Bounds 将根据缩放而相应地进行更新,此时,渲染器的 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); } }
当物体发生位移时,渲染器的 Bounds 将会相应地跟随物体的移动而更新。此时,渲染器的 Bounds 也会随之移动,以确保正确的可见性计算。
当物体发生旋转时,渲染器的 Bounds 将会进行相应的更新。与位移不同,旋转会导致包围盒的大小发生变化,但是并不会随着物体的旋转而旋转。
当物体发生缩放时,渲染器的 Bounds 将根据缩放而相应地进行更新,此时,渲染器的 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); } }
当物体发生位移时,渲染器的 Bounds 将会相应地跟随物体的移动而更新。此时,渲染器的 Bounds 也会随之移动,以确保正确的可见性计算。
Mesh 的 Bounds 是在创建 Mesh 时根据其顶点位置计算得出的最小包围盒。这个包围盒通常在创建 Mesh 时就已经固定,并不会随着对象的缩放或旋转而实时更新。
所以,当对物体进行缩放或旋转时,Mesh Bounds 并不会实时更新以适应这些变化。即使缩放或旋转了对象,Mesh Bounds 也仍然保持着原始计算得出的包围盒形状和大小。
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)。这意味着它不会随着对象的旋转而旋转,而是始终保持沿着坐标轴的方向。
AABB 通常用于快速包围物体,但在对象旋转时可能无法准确地包裹对象的形状,因为它是固定的沿坐标轴的边界框。
/// <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; }
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); } }
每一次跌倒都是一次成长 每一次努力都是一次进步 |
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。