❤️UNITY实战进阶-三维AABB包围盒详解-6_欲望如海水,越喝越渴。-CSDN博客前言 碰撞检测问题在虚拟现实、计算机辅助设计与制造、游戏、机器人等方面都有着广泛的应用,而包围盒算法是进行碰撞检测的重要方法之一。 而常见的包围盒有:AABB包围盒(Axis-aligned bounding box)包围球(Sphere)OBB包围盒(Oriented bounding box)凸包包围盒(Convex Hull)...在Unity中的Collider包含:介绍在游戏中,为了简化物体之间的碰...https://blog.csdn.net/flj135792468/article/details/120654391在前文中,我们可以通过2个点来确定一个立方体。在此基础上添加3个轴向

        public Vector3 XAxis { get { return transform.right; } }public Vector3 YAxis { get { return transform.up; } }public Vector3 ZAxis { get { return transform.forward; } }

已知一个点的坐标和物体的四元数,我们就可以得知旋转完的点

public void GetCorners()
{// 朝着Z轴正方向的面// 左上顶点坐标m_Corners[0].Set(m_RealCalcMin.x, m_RealCalcMax.y, m_RealCalcMax.z);// 左下顶点坐标m_Corners[1].Set(m_RealCalcMin.x, m_RealCalcMin.y, m_RealCalcMax.z);// 右下顶点坐标m_Corners[2].Set(m_RealCalcMax.x, m_RealCalcMin.y, m_RealCalcMax.z);// 右上顶点坐标m_Corners[3].Set(m_RealCalcMax.x, m_RealCalcMax.y, m_RealCalcMax.z);// 朝着Z轴负方向的面// 右上顶点坐标m_Corners[4].Set(m_RealCalcMax.x, m_RealCalcMax.y, m_RealCalcMin.z);// 右下顶点坐标.m_Corners[5].Set(m_RealCalcMax.x, m_RealCalcMin.y, m_RealCalcMin.z);// 左下顶点坐标.m_Corners[6].Set(m_RealCalcMin.x, m_RealCalcMin.y, m_RealCalcMin.z);// 左上顶点坐标.m_Corners[7].Set(m_RealCalcMin.x, m_RealCalcMax.y, m_RealCalcMin.z);// 根据旋转修改8个点的坐标for (int i = 0; i < m_Corners.Length; i++){Vector3 dis = m_Corners[i] - transform.position;m_Corners[i] = transform.position + transform.localRotation * dis;}
}

这样一个可以跟着旋转的8个顶点坐标就算出来了


OBB包围盒的碰撞检测方法

检测方法常采用的是分离轴定理。说白了就是去检测并判断两个图形之间是否有间隙。

找到一个轴,两个凸形状在该轴上的投影不重叠,则这两个形状不相交。如果这个轴不存在,并且那些形状是凸形的,则可以确定两个形状相交。

在算法上就是取两个OBB的坐标轴各3个以及垂直于每个轴的9个轴。

1.先将点投影到坐标抽上

/// <summary>
/// 将点投影到坐标轴
/// </summary>
/// <param name="point"></param>
/// <param name="axis"></param>
/// <returns>投影的坐标</returns>
private float ProjectPoint(Vector3 point, Vector3 axis)
{Vector3 projectPoint = Vector3.Project(point, axis);float result = projectPoint.magnitude * Mathf.Sign(Vector3.Dot(projectPoint, axis));return result;
}

2.获取8个点在轴上投影的最大值和最小值

/// <summary>
/// 计算最大最小投影值
/// </summary>
/// <param name="corners"></param>
/// <param name="axis"></param>
/// <param name="min"></param>
/// <param name="max"></param>
private void GetInterval(Vector3[] corners, Vector3 axis, out float min, out float max)
{float value;//分别投影八个点,取最大和最小值min = max = ProjectPoint(corners[0], axis);for (int i = 1; i < corners.Length; i++){value = ProjectPoint(corners[i], axis);min = Mathf.Min(min, value);max = Mathf.Max(max, value);}
}

3.判断是不是交叉点

/// <summary>
/// 预测是不是交叉点
/// </summary>
/// <param name="aCorners"></param>
/// <param name="bCorners"></param>
/// <param name="axis"></param>
/// <returns></returns>
private bool AxisProjection(Vector3[] aCorners, Vector3[] bCorners, Vector3 axis)
{GetInterval(aCorners, axis, out float xMin, out float xMax);GetInterval(bCorners, axis, out float yMin, out float yMax);if (yMin >= xMin && yMin <= xMax) return false;if (yMax >= xMin && yMax <= xMax) return false;if (xMin >= yMin && xMin <= yMax) return false;if (xMax >= yMin && xMax <= yMax) return false;return true;
}

4.根据2个包围盒的3个轴以及垂直于每个轴的9个轴判断是否有交集

public bool Intersects(IMathAABB aabb)
{m_IsNotIntersect = false;m_IsNotIntersect |= AxisProjection(this.Corners, aabb.Corners, XAxis);m_IsNotIntersect |= AxisProjection(this.Corners, aabb.Corners, YAxis);m_IsNotIntersect |= AxisProjection(this.Corners, aabb.Corners, ZAxis);m_IsNotIntersect |= AxisProjection(this.Corners, aabb.Corners, aabb.XAxis);m_IsNotIntersect |= AxisProjection(this.Corners, aabb.Corners, aabb.YAxis);m_IsNotIntersect |= AxisProjection(this.Corners, aabb.Corners, aabb.ZAxis);m_IsNotIntersect |= AxisProjection(this.Corners, aabb.Corners, Vector3.Cross(XAxis, aabb.XAxis).normalized);m_IsNotIntersect |= AxisProjection(this.Corners, aabb.Corners, Vector3.Cross(XAxis, aabb.YAxis).normalized);m_IsNotIntersect |= AxisProjection(this.Corners, aabb.Corners, Vector3.Cross(XAxis, aabb.ZAxis).normalized);m_IsNotIntersect |= AxisProjection(this.Corners, aabb.Corners, Vector3.Cross(YAxis, aabb.XAxis).normalized);m_IsNotIntersect |= AxisProjection(this.Corners, aabb.Corners, Vector3.Cross(YAxis, aabb.YAxis).normalized);m_IsNotIntersect |= AxisProjection(this.Corners, aabb.Corners, Vector3.Cross(YAxis, aabb.ZAxis).normalized);m_IsNotIntersect |= AxisProjection(this.Corners, aabb.Corners, Vector3.Cross(ZAxis, aabb.XAxis).normalized);m_IsNotIntersect |= AxisProjection(this.Corners, aabb.Corners, Vector3.Cross(ZAxis, aabb.YAxis).normalized);m_IsNotIntersect |= AxisProjection(this.Corners, aabb.Corners, Vector3.Cross(ZAxis, aabb.ZAxis).normalized);return !m_IsNotIntersect;
}

完整代码

public class OBB : MonoBehaviour, IMathAABB{//修改此值控制m_CalcMin[SerializeField, AABBModify("MinVector")]private Vector3 m_Min = -Vector3.one;//修改此值控制m_CalcMax[SerializeField, AABBModify("MaxVector")]private Vector3 m_Max = Vector3.one;/// <summary>/// 中心点/// </summary>[SerializeField, AABBDisable]private Vector3 m_Center = Vector3.zero;/// <summary>/// 保存包围盒八个顶点/// </summary>[SerializeField, AABBDisable]private Vector3[] m_Corners = new Vector3[8];#if UNITY_EDITOR[SerializeField]private Color m_DebugLineColor = Color.green;
#endifpublic Vector3 MinVector{set{SetMinMax(m_Min, m_Max);}get{return m_RealCalcMin;}}public Vector3 MaxVector{set{SetMinMax(m_Min, m_Max);}get{return m_RealCalcMax;}}public Vector3[] Corners{get{return m_Corners;}}public Vector3 Center{get{return m_Center;}}public Vector3 XAxis { get { return transform.right; } }public Vector3 YAxis { get { return transform.up; } }public Vector3 ZAxis { get { return transform.forward; } }/// <summary>/// 实际计算的最小值/// </summary>private Vector3 m_RealCalcMin;/// <summary>/// 实际计算的最大值/// </summary>private Vector3 m_RealCalcMax;private bool m_IsNotIntersect = false;/// <summary>/// 防止在update之前产生碰撞/// </summary>private void Awake(){SetMinMax(m_Min, m_Max);}// Update is called once per frameprivate void Update(){SetMinMax(m_Min, m_Max);}#if UNITY_EDITORvoid OnDrawGizmos(){//// draw linesGizmos.color = m_DebugLineColor;Gizmos.DrawLine(Corners[0], Corners[1]);Gizmos.DrawLine(Corners[1], Corners[2]);Gizmos.DrawLine(Corners[2], Corners[3]);Gizmos.DrawLine(Corners[3], Corners[0]);Gizmos.DrawLine(Corners[4], Corners[5]);Gizmos.DrawLine(Corners[5], Corners[6]);Gizmos.DrawLine(Corners[6], Corners[7]);Gizmos.DrawLine(Corners[7], Corners[4]);Gizmos.DrawLine(Corners[0], Corners[7]);Gizmos.DrawLine(Corners[1], Corners[6]);Gizmos.DrawLine(Corners[2], Corners[5]);Gizmos.DrawLine(Corners[3], Corners[4]);}
#endifpublic Vector3 GetCenter(){m_Center.x = 0.5f * (m_RealCalcMin.x + m_RealCalcMax.x);m_Center.y = 0.5f * (m_RealCalcMin.y + m_RealCalcMax.y);m_Center.z = 0.5f * (m_RealCalcMin.z + m_RealCalcMax.z);return m_Center;}public void GetCorners(){// 朝着Z轴正方向的面// 左上顶点坐标m_Corners[0].Set(m_RealCalcMin.x, m_RealCalcMax.y, m_RealCalcMax.z);// 左下顶点坐标m_Corners[1].Set(m_RealCalcMin.x, m_RealCalcMin.y, m_RealCalcMax.z);// 右下顶点坐标m_Corners[2].Set(m_RealCalcMax.x, m_RealCalcMin.y, m_RealCalcMax.z);// 右上顶点坐标m_Corners[3].Set(m_RealCalcMax.x, m_RealCalcMax.y, m_RealCalcMax.z);// 朝着Z轴负方向的面// 右上顶点坐标m_Corners[4].Set(m_RealCalcMax.x, m_RealCalcMax.y, m_RealCalcMin.z);// 右下顶点坐标.m_Corners[5].Set(m_RealCalcMax.x, m_RealCalcMin.y, m_RealCalcMin.z);// 左下顶点坐标.m_Corners[6].Set(m_RealCalcMin.x, m_RealCalcMin.y, m_RealCalcMin.z);// 左上顶点坐标.m_Corners[7].Set(m_RealCalcMin.x, m_RealCalcMax.y, m_RealCalcMin.z);// 根据旋转修改8个点的坐标for (int i = 0; i < m_Corners.Length; i++){Vector3 dis = m_Corners[i] - transform.position;m_Corners[i] = transform.position + transform.localRotation * dis;}}public bool Intersects(IMathAABB aabb){m_IsNotIntersect = false;m_IsNotIntersect |= AxisProjection(this.Corners, aabb.Corners, XAxis);m_IsNotIntersect |= AxisProjection(this.Corners, aabb.Corners, YAxis);m_IsNotIntersect |= AxisProjection(this.Corners, aabb.Corners, ZAxis);m_IsNotIntersect |= AxisProjection(this.Corners, aabb.Corners, aabb.XAxis);m_IsNotIntersect |= AxisProjection(this.Corners, aabb.Corners, aabb.YAxis);m_IsNotIntersect |= AxisProjection(this.Corners, aabb.Corners, aabb.ZAxis);m_IsNotIntersect |= AxisProjection(this.Corners, aabb.Corners, Vector3.Cross(XAxis, aabb.XAxis).normalized);m_IsNotIntersect |= AxisProjection(this.Corners, aabb.Corners, Vector3.Cross(XAxis, aabb.YAxis).normalized);m_IsNotIntersect |= AxisProjection(this.Corners, aabb.Corners, Vector3.Cross(XAxis, aabb.ZAxis).normalized);m_IsNotIntersect |= AxisProjection(this.Corners, aabb.Corners, Vector3.Cross(YAxis, aabb.XAxis).normalized);m_IsNotIntersect |= AxisProjection(this.Corners, aabb.Corners, Vector3.Cross(YAxis, aabb.YAxis).normalized);m_IsNotIntersect |= AxisProjection(this.Corners, aabb.Corners, Vector3.Cross(YAxis, aabb.ZAxis).normalized);m_IsNotIntersect |= AxisProjection(this.Corners, aabb.Corners, Vector3.Cross(ZAxis, aabb.XAxis).normalized);m_IsNotIntersect |= AxisProjection(this.Corners, aabb.Corners, Vector3.Cross(ZAxis, aabb.YAxis).normalized);m_IsNotIntersect |= AxisProjection(this.Corners, aabb.Corners, Vector3.Cross(ZAxis, aabb.ZAxis).normalized);return !m_IsNotIntersect;}public bool ContainPoint(Vector3 point){m_IsNotIntersect = false;m_IsNotIntersect |= AxisProjection(this.Corners, point, XAxis);m_IsNotIntersect |= AxisProjection(this.Corners, point, YAxis);m_IsNotIntersect |= AxisProjection(this.Corners, point, ZAxis);return !m_IsNotIntersect;}public void Merge(IMathAABB box){throw new System.NotImplementedException("Please ingore 'Merge(IMathAABB box)' function !");}public void SetMinMax(Vector3 min, Vector3 max){this.m_RealCalcMin = min * 0.5f + transform.position;this.m_RealCalcMax = max * 0.5f + transform.position;GetCenter();GetCorners();}public bool IsEmpty(){return m_RealCalcMin.x > m_RealCalcMax.x || m_RealCalcMin.y > m_RealCalcMax.y || m_RealCalcMin.z > m_RealCalcMax.z;}public void ResetMinMax(){m_RealCalcMin.Set(-1, -1, -1);m_RealCalcMax.Set(1, 1, 1);GetCenter();GetCorners();}/// <summary>/// 预测是不是交叉点/// </summary>/// <param name="aCorners"></param>/// <param name="bCorners"></param>/// <param name="axis"></param>/// <returns></returns>private bool AxisProjection(Vector3[] aCorners, Vector3[] bCorners, Vector3 axis){GetInterval(aCorners, axis, out float xMin, out float xMax);GetInterval(bCorners, axis, out float yMin, out float yMax);if (yMin >= xMin && yMin <= xMax) return false;if (yMax >= xMin && yMax <= xMax) return false;if (xMin >= yMin && xMin <= yMax) return false;if (xMax >= yMin && xMax <= yMax) return false;return true;}/// <summary>/// 预测是不是交叉点/// </summary>/// <param name="aCorners"></param>/// <param name="point"></param>/// <param name="axis"></param>/// <returns></returns>private bool AxisProjection(Vector3[] aCorners, Vector3 point, Vector3 axis){GetInterval(aCorners, axis, out float xMin, out float xMax);float yMin = ProjectPoint(point, axis);float yMax = ProjectPoint(point, axis);if (yMin >= xMin && yMin <= xMax) return false;if (yMax >= xMin && yMax <= xMax) return false;if (xMin >= yMin && xMin <= yMax) return false;if (xMax >= yMin && xMax <= yMax) return false;return true;}/// <summary>/// 计算最大最小投影值/// </summary>/// <param name="corners"></param>/// <param name="axis"></param>/// <param name="min"></param>/// <param name="max"></param>private void GetInterval(Vector3[] corners, Vector3 axis, out float min, out float max){float value;//分别投影八个点,取最大和最小值min = max = ProjectPoint(corners[0], axis);for (int i = 1; i < corners.Length; i++){value = ProjectPoint(corners[i], axis);min = Mathf.Min(min, value);max = Mathf.Max(max, value);}}/// <summary>/// 将点投影到坐标轴/// </summary>/// <param name="point"></param>/// <param name="axis"></param>/// <returns>投影的坐标</returns>private float ProjectPoint(Vector3 point, Vector3 axis){Vector3 projectPoint = Vector3.Project(point, axis);float result = projectPoint.magnitude * Mathf.Sign(Vector3.Dot(projectPoint, axis));return result;}}

  有兴趣的小伙伴可以关注一波

o(* ̄▽ ̄*)ブ

❤️UNITY实战进阶-OBB包围盒详解-6相关推荐

  1. python 拼音库_python有没有拼音库python进阶之socket详解

    Socket的英文原义是"孔"或"插座".作为BSD UNIX的进程通信机制,通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句 ...

  2. Unity UGUI Batches合批规则详解(含源码)

    Unity UGUI Batches合批规则详解 在处理UGUI DrawCall问题的时候,我们经常遇到各式各样的问题. 问题1:在处理UGUI合批的时候,发现了一个面板父节点发生旋转,底下的UI合 ...

  3. 《Unity 3D 游戏开发技术详解与典型案例》——1.3节第一个Unity 3D程序

    本节书摘来自异步社区<Unity 3D 游戏开发技术详解与典型案例>一书中的第1章,第1.3节第一个Unity 3D程序,作者 吴亚峰 , 于复兴,更多章节内容可以访问云栖社区" ...

  4. OpenCV-Python实战(10)——详解 OpenCV 轮廓检测

    OpenCV-Python实战(10)--详解 OpenCV 轮廓检测 0. 前言 1. 轮廓介绍 2. 轮廓检测 3. 轮廓压缩 4. 图像矩 4. 1 一些基于矩的对象特征 4.2 Hu 不变矩 ...

  5. C#高级编程——C#扩展方法+接口,定义统一的搜索接口,基于Unity(三)——图文详解加源码

    C#高级编程--C#扩展方法+接口,定义统一的搜索接口,基于Unity(三)--图文详解加源码 前言

  6. Unity实现植物识别示例详解

    文章来源: 学习通http://www.bdgxy.com/ 普学网http://www.boxinghulanban.cn/ 智学网http://www.jaxp.net/ 表格制作excel教程h ...

  7. ext4数据恢复实战及文件系统结构详解

    ext4数据恢复实战及文件系统结构详解 一.前言 二.ext4数据恢复实战 三.ext4文件系统结构详解 四.ext4分区结构 五.ext4目录结构 六.目录项的删除特性 七.ext4文件结构 八.最 ...

  8. 【原创-更新完毕】|日历拼图游戏的解决方案(C语言-进阶应用)-详解连载2

    [原创]|日历拼图游戏的解决方案(C语言-进阶应用)-详解连载1_zhuyi8120的博客-CSDN博客 [原创]|日历拼图游戏的解决方案(C语言-进阶应用)-详解连载3_zhuyi8120的博客-C ...

  9. 攻防世界web进阶区Web_php_wrong_nginx_config详解

    攻防世界web进阶区Web_php_wrong_nginx_config详解 题目 详解 题目 打开发现无论我们输入什么他都会弹出网站建设不完全 那么我们使用御剑进行扫描,扫描到了admin和robo ...

最新文章

  1. 人群密度估计--Learning to Count with CNN Boosting
  2. TypeScript Type Innference(类型推断)
  3. lecture 3 qkine- start with connections
  4. IOS开发之Autolayout——“Content Compression Resistance”和“Content Hugging”
  5. 牛客 - 牛妹的考验(AC自动机+dp)
  6. Ubuntu16.04安装Hadoop+Spark+pyspark大数据python开发环境
  7. 玩转SpringSession,重要知识点全面剖析!
  8. 案例:实现文件下载并能正确显示中文文件名
  9. C++笔试题整理(一)
  10. WCF中DBNull序列化的问题
  11. Java中private修饰变量的继承问题
  12. HTML5期末大作业:网页设计作业网站设计——千与千寻-电影图文(9页) HTML+CSS+JavaScript 学生DW网页设计作业成品 web课程设计网页规划与设计 计算机毕设网页设计源码
  13. pycharm 代码跳转
  14. Android倒计时工具
  15. 小学计算机画图课件第一册,第一册信息技术课件-第三章 第1课 认识“画图”软件 甘少版(共12张PPT)...
  16. CentOS 7 最小化系统安装图形化桌面
  17. arduino中的serial .available()和serial.read()是区别
  18. iptables端口复用
  19. 使用继电器和Arduino开发板控制高压电路
  20. 最简单的基于libVLC的例子:最简单的基于libVLC的视频播放器

热门文章

  1. Bootstrap 下拉菜单和按钮
  2. 小福利,带你快速入门sumifs多条件求和函数、设置下拉菜单结合vlookup函数双条件查找数据、excel的切片器(表关联)、数据透视表、数据透视图
  3. 支付清算系统简介(1)
  4. Python 简单的龟鱼游戏
  5. springtask Cron表达式与fixedDelay的区别
  6. 当华为云WeLink遇上P40,多屏协同全场景办公有多神奇?
  7. 有人说程序员是一个很高大上又高不可攀的职业,你认同吗?
  8. 凯特勒通道(backtrader)
  9. excel想要把两列合并且用空格隔开
  10. druid监控页面授权