Bounds 外包围盒
Bounds 叫作外包围盒、边界框、外扩矩形.是struct 结构体。
而我们获得Bounds的主要途径有三种:Render,Collider,Mesh。
Render.bounds 世界坐标
Collider.bounds 世界坐标
Mesh.bounds 本地坐标
var m= GetComponent<MeshFilter>().bounds;
var c = GetComponent<Collider>().bounds;
var r = GetComponent<Renderer>().bounds;
把 Mesh.bounds 本地坐标换算成世界坐标bounds
//把本地坐标换算成世界坐标
var centerPoint = transform.TransformPoint(bounds.center);
Bounds newBounds = new Bounds(centerPoint, bounds.size);
碰撞器绿方框
Bounds和碰撞器的绿方框(绿色线)的区别
碰撞器的方框始终跟着模型旋转移动,缩放跟着模型的,只要模型不缩放它也不缩放
Bounds 跟随模型移动,
而不会跟模型着旋转,而是随着模型旋转而缩放变大变小,始终包裹模型.
下面红色方框就是 Bounds 方框
Bounds属性
只读属性
我们不能直接修改 Bounds 结构体里头的 center 和 size 属性都不能直接设置,而且 BoxCollider 的 bounds 属性也不能.
.bounds.center; //中心点坐标
.bounds.size; //盒子的总尺寸,xyz长度
.bounds.min; //最小点的位置:左下角
.bounds.max; //最大点的位置:右上角
.bounds.center.x; //中心点的X
.bounds.center.y; //中心点的Y
Bounds 常用方法
// 点point是否在这个包围盒内部
public bool Contains(Vector3 point);
// bounds会自动扩充大小(改变center和extens),来包含这个point
public void Encapsulate(Vector3 point);
// bounds会自动扩充大小(改变center和extens),把原本的bounds和传入的bounds都包含进来
public void Encapsulate(Bounds bounds);
// 这条射线是否与这个包围盒相交
public bool IntersectRay(Ray ray);
//包围盒最近的点
public Vector3 ClosestPoint(Vector3 point);
//设置边界框的最小最大值
public void SetMinMax(Vector3 min, Vector3 max);
多物体Bounds, Encapsulate方法
计算多物体Bounds,则要遍历所有子物体,然后调用Encapsulate方法来计算。
Bounds bounds;
Renderer[] renderers = model.GetComponentsInChildren<Renderer>();
for (int i = 0; i < renderers.Length; i++)
{
bounds.Encapsulate(renderers[i].bounds);
}
计算包围盒的八个顶点
center = bounds.center;
ext = bounds.extents;
float deltaX = Mathf.Abs(ext.x);
float deltaY = Mathf.Abs(ext.y);
float deltaZ = Mathf.Abs(ext.z);
#region 获取AABB包围盒顶点
points = new Vector3[8];
points[0] = center + new Vector3(-deltaX, deltaY, -deltaZ); // 上前左(相对于中心点)
points[1] = center + new Vector3(deltaX, deltaY, -deltaZ); // 上前右
points[2] = center + new Vector3(deltaX, deltaY, deltaZ); // 上后右
points[3] = center + new Vector3(-deltaX, deltaY, deltaZ); // 上后左
points[4] = center + new Vector3(-deltaX, -deltaY, -deltaZ); // 下前左
points[5] = center + new Vector3(deltaX, -deltaY, -deltaZ); // 下前右
points[6] = center + new Vector3(deltaX, -deltaY, deltaZ); // 下后右
points[7] = center + new Vector3(-deltaX, -deltaY, deltaZ); // 下后左
#endregion
绘制bounds方框
/// <summary>
/// 绘制Bounds方框
/// </summary>
/// <param name="bounds"></param>
/// <param name="color"></param>
/// <param name="offsetSize"></param>
/// <param name="duration"></param>
public static void DrawBoundBoxLine(Bounds bounds, Color color = default(Color), float offsetSize = 1f, float duration = 0.1f)
{
//先计算出包围盒8个点
Vector3[] points = new Vector3[8];
var width_x = bounds.size.x * offsetSize;
var hight_y = bounds.size.y * offsetSize;
var length_z = bounds.size.z * offsetSize;
var LeftBottomPoint = bounds.min;
var rightUpPoint = bounds.max;
var centerPoint = bounds.center;
var topPoint = new Vector3(centerPoint.x, centerPoint.y + hight_y / 2, centerPoint.z);
var bottomPoint = new Vector3(centerPoint.x, centerPoint.y - hight_y * 0.5f, centerPoint.z);
points[0] = LeftBottomPoint + Vector3.right * width_x;
points[1] = LeftBottomPoint + Vector3.up * hight_y;
points[2] = LeftBottomPoint + Vector3.forward * length_z;
points[3] = rightUpPoint - Vector3.right * width_x;
points[4] = rightUpPoint - Vector3.up * hight_y;
points[5] = rightUpPoint - Vector3.forward * length_z;
points[6] = LeftBottomPoint;
points[7] = rightUpPoint;
Debug.DrawLine(LeftBottomPoint, points[0], color, duration);
Debug.DrawLine(LeftBottomPoint, points[1], color, duration);
Debug.DrawLine(LeftBottomPoint, points[2], color, duration);
Debug.DrawLine(rightUpPoint, points[3], color, duration);
Debug.DrawLine(rightUpPoint, points[4], color, duration);
Debug.DrawLine(rightUpPoint, points[5], color, duration);
Debug.DrawLine(points[1], points[3], color, duration);
Debug.DrawLine(points[2], points[4], color, duration);
Debug.DrawLine(points[0], points[5], color, duration);
Debug.DrawLine(points[2], points[3], color, duration);
Debug.DrawLine(points[0], points[4], color, duration);
Debug.DrawLine(points[1], points[5], color, duration);
}
绘制碰撞器方框 -方法1
/// <summary>
/// 绘制boxCollider的绿色方框
/// </summary>
/// <param name="color"></param>
void DrawGizmosOnRunTime(Color color)
{
var boxCollider = GetComponent<BoxCollider>();
Gizmos.color = color;
Matrix4x4 rotationMatrix = Matrix4x4.TRS(boxCollider.transform.position, boxCollider.transform.rotation, boxCollider.transform.lossyScale);
Gizmos.matrix = rotationMatrix;
Gizmos.DrawWireCube(boxCollider.center, boxCollider.size);
}
void OnDrawGizmos()
{
DrawGizmosOnRunTime(Color.red);
}
绘制碰撞器方框 -方法2
/// <summary>
/// 绘制boxCollider的绿色方框
/// </summary>
/// <param name="boxCollider"></param>
/// <param name="color"></param>
/// <param name="offsetSize"></param>
public static void DrawOnGameViewRuntime(BoxCollider boxCollider, Color color = default(Color), float offsetSize = 1f)
{
float width = 0.1f;
Vector3 rightDir = boxCollider.transform.right.normalized;
Vector3 forwardDir = boxCollider.transform.forward.normalized;
Vector3 upDir = boxCollider.transform.up.normalized;
Vector3 center = boxCollider.transform.position + boxCollider.center;
Vector3 size = boxCollider.size * offsetSize;
size.x *= boxCollider.transform.lossyScale.x;
size.y *= boxCollider.transform.lossyScale.y;
size.z *= boxCollider.transform.lossyScale.z;
Debug.DrawLine(center + upDir * size.y / 2f + rightDir * size.x / 2f + forwardDir * size.z / 2f, center + upDir * size.y / 2f - rightDir * size.x / 2f + forwardDir * size.z / 2f, color);
Debug.DrawLine(center - upDir * size.y / 2f + rightDir * size.x / 2f + forwardDir * size.z / 2f, center - upDir * size.y / 2f - rightDir * size.x / 2f + forwardDir * size.z / 2f, color);
Debug.DrawLine(center + upDir * size.y / 2f + rightDir * size.x / 2f + forwardDir * size.z / 2f, center - upDir * size.y / 2f + rightDir * size.x / 2f + forwardDir * size.z / 2f, color);
Debug.DrawLine(center + upDir * size.y / 2f - rightDir * size.x / 2f + forwardDir * size.z / 2f, center - upDir * size.y / 2f - rightDir * size.x / 2f + forwardDir * size.z / 2f, color);
Debug.DrawLine(center + upDir * size.y / 2f + rightDir * size.x / 2f - forwardDir * size.z / 2f, center + upDir * size.y / 2f - rightDir * size.x / 2f - forwardDir * size.z / 2f, color);
Debug.DrawLine(center - upDir * size.y / 2f + rightDir * size.x / 2f - forwardDir * size.z / 2f, center - upDir * size.y / 2f - rightDir * size.x / 2f - forwardDir * size.z / 2f, color);
Debug.DrawLine(center + upDir * size.y / 2f + rightDir * size.x / 2f - forwardDir * size.z / 2f, center - upDir * size.y / 2f + rightDir * size.x / 2f - forwardDir * size.z / 2f, color);
Debug.DrawLine(center + upDir * size.y / 2f - rightDir * size.x / 2f - forwardDir * size.z / 2f, center - upDir * size.y / 2f - rightDir * size.x / 2f - forwardDir * size.z / 2f, color);
Debug.DrawLine(center + upDir * size.y / 2f + rightDir * size.x / 2f + forwardDir * size.z / 2f, center + upDir * size.y / 2f + rightDir * size.x / 2f - forwardDir * size.z / 2f, color);
Debug.DrawLine(center - upDir * size.y / 2f + rightDir * size.x / 2f + forwardDir * size.z / 2f, center - upDir * size.y / 2f + rightDir * size.x / 2f - forwardDir * size.z / 2f, color);
Debug.DrawLine(center + upDir * size.y / 2f - rightDir * size.x / 2f + forwardDir * size.z / 2f, center + upDir * size.y / 2f - rightDir * size.x / 2f - forwardDir * size.z / 2f, color);
Debug.DrawLine(center - upDir * size.y / 2f - rightDir * size.x / 2f + forwardDir * size.z / 2f, center - upDir * size.y / 2f - rightDir * size.x / 2f - forwardDir * size.z / 2f, color);
}
求两个包围盒之间的距离
// Distance between two ClosestPointOnBounds
// this is needed in cases where entites are really big. in those cases,
// we can't just move to entity.transform.position, because it will be
// unreachable. instead we have to go the closest point on the boundary.
//
// Vector3.Distance(a.transform.position, b.transform.position):
// _____ _____
// | | | |
// | x==|======|==x |
// |_____| |_____|
//
//
// Utils.ClosestDistance(a.collider, b.collider):
// _____ _____
// | | | |
// | |x====x| |
// |_____| |_____|
//
public static float ClosestDistance(Collider a, Collider b)
{
return Vector3.Distance(a.ClosestPointOnBounds(b.transform.position),
b.ClosestPointOnBounds(a.transform.position));
}
求点A到包围盒最近的点,ClosestPoint
计算所有包围盒的中心点
计算出多个Bounds的中心点
[MenuItem ("MyMenu/Do Test")]
static void Test ()
{
Transform parent = Selection.activeGameObject.transform;
Vector3 postion = parent.position;
Quaternion rotation = parent.rotation;
Vector3 scale = parent.localScale;
parent.position = Vector3.zero;
parent.rotation = Quaternion.Euler(Vector3.zero);
parent.localScale = Vector3.one;
Vector3 center = Vector3.zero;
Renderer[] renders = parent.GetComponentsInChildren<Renderer>();
foreach (Renderer child in renders){
center += child.bounds.center;
}
center /= parent.GetComponentsInChildren<Transform>().Length;
Bounds bounds = new Bounds(center,Vector3.zero);
foreach (Renderer child in renders){
bounds.Encapsulate(child.bounds);
}
parent.position = postion;
parent.rotation = rotation;
parent.localScale = scale;
foreach(Transform t in parent){
t.position = t.position - bounds.center;
}
parent.transform.position = bounds.center + parent.position;
}
参考
https://blog.csdn.net/sinat_25415095/article/details/104588989
https://www.5axxw.com/questions/content/imitu9