在上一篇 射线与AABB相交检测
射线与OBB3D 相交检测的原理跟射线与AABB相交检测的原理相同,本篇不再讲解原理
上篇推论出:射线与平面相交点距离射线起点距离t的距离公式为 t = (d - Dot(p, n)) / Dot(rayDir, n)

OBB3D 与 AABB 属性上的区别
AABB 三个轴向量固定: (1, 0, 0), (0, 1, 0), (0, 0, 1)
OBB3D 三个轴向量随旋转变化

AABB 的表示可以使用 min, max 坐标点表示
OBB3D 则没有 min, max 坐标点

所以AABB计算逻辑中使用到的坐标点和固定轴向,需要替换为 OBB3D 的属性,
轴向分别使用 _axisX,_axisY, _axisZ
取 OBB3D 两个顶点,每个顶点分别是三个面的交点或者叫顶点

_vertexs[0] = center + (axisX * size.x + axisY * size.y + axisZ * size.z) * 0.5f;
_vertexs[5] = center + (-axisX * size.x - axisY * size.y - axisZ * size.z) * 0.5f;

逻辑代码如下

public class OBB3D
{/// <summary>///  X 轴方向向量/// </summary>public Vector3 _axisX;/// <summary>/// Y 轴方向向量/// </summary>public Vector3 _axisY;/// <summary>/// Z 轴方向向量/// </summary>public Vector3 _axisZ;/// <summary>/// 中心点坐标/// </summary>public Vector3 _center;/// <summary>/// 三条边长度/// </summary>public Vector3 _size;/// <summary>/// 八个顶点坐标/// </summary>public Vector3[] _vertexs;public OBB3D(){   }public void Set(Vector3 axisX, Vector3 axisY, Vector3 axisZ, Vector3 center, Vector3 size){_axisX = axisX;_axisY = axisY;_axisZ = axisZ;_center = center;_size = size;_vertexs = new Vector3[8];_vertexs[0] = center + (axisX * size.x + axisY * size.y + axisZ * size.z) * 0.5f;_vertexs[1] = center + (axisX * size.x - axisY * size.y + axisZ * size.z) * 0.5f;_vertexs[2] = center + (axisX * size.x + axisY * size.y - axisZ * size.z) * 0.5f;_vertexs[3] = center + (axisX * size.x - axisY * size.y - axisZ * size.z) * 0.5f;_vertexs[4] = center + (-axisX * size.x + axisY * size.y - axisZ * size.z) * 0.5f;_vertexs[5] = center + (-axisX * size.x - axisY * size.y - axisZ * size.z) * 0.5f;_vertexs[6] = center + (-axisX * size.x - axisY * size.y + axisZ * size.z) * 0.5f;_vertexs[7] = center + (-axisX * size.x + axisY * size.y + axisZ * size.z) * 0.5f;}
}/// <summary>
/// 射线与AABB相交检测
/// 下面方法是 射线与 3D AABB 相交的计算
/// 如果想计算 射线与 2D AABB 相交,则将下方关于 z 坐标的部分删除即可
/// </summary>
public class RayOBBCollision
{/// <summary>/// 判断射线与AABB是否相交/// </summary>/// <param name="raySource">射线起点</param>/// <param name="rayDir">射线方向</param>/// <param name="aabb">AABB</param>/// <param name="point">射线与AABB交点坐标</param>/// <returns></returns>public bool IsCollision(Vector3 raySource, Vector3 rayDir, OBB3D obb3D, ref Vector3 point){float length = 0;bool collision = IsCollision(raySource, rayDir, obb3D, ref length);point = raySource + rayDir * length;return collision;}/// <summary>/// 判断射线与AABB是否相交/// </summary>/// <param name="raySource">射线起点</param>/// <param name="rayDir">射线方向向量</param>/// <param name="obb3D">OBB3D</param>/// <param name="length">射线起点到相交点距离</param>/// <returns></returns>public bool IsCollision(Vector3 raySource, Vector3 rayDir, OBB3D obb3D, ref float length){float t1 = 0;float t2 = 0;bool collision = Calculate(raySource, rayDir, obb3D, obb3D._axisX, ref t1, ref t2);if (!collision || !CheckValue(ref t1, ref t2)){return false;}float t3 = 0;float t4 = 0;collision = Calculate(raySource, rayDir, obb3D, obb3D._axisY, ref t3, ref t4);if (!collision || !CheckValue(ref t3, ref t4)){return false;}float t5 = 0;float t6 = 0;collision = Calculate(raySource, rayDir, obb3D, obb3D._axisZ, ref t5, ref t6);if (!collision || !CheckValue(ref t5, ref t6)){return false;}float entryT1 = Math.Max(Math.Max(t1, t3), t5);float entryT2 = Math.Min(Math.Min(t2, t4), t6);length = entryT1;return (entryT1 < entryT2);}/// <summary>/// 射线与平面相交计算/// </summary>/// <param name="raySource">射线起点</param>/// <param name="rayDir">射线方向向量</param>/// <param name="obb3D">aabb</param>/// <param name="normal">平面法向量</param>/// t = (d - Dot(raySource, normal)) / Dot(rayDir, normal)/// d = Dot(planePoint, normal)/// t = (Dot(planePoint, normal)  - Dot(raySource, normal)) / Dot(rayDir, normal)/// t = Dot((planePoint - raySource), normal) / Dot(rayDir, normal)private bool Calculate(Vector3 raySource, Vector3 rayDir, OBB3D obb3D, Vector3 normal, ref float t1, ref float t2){float p_sub_r_dot_n1 = Vector3.Dot(obb3D._vertexs[0] - raySource, normal);float p_sub_r_dot_n2 = Vector3.Dot(obb3D._vertexs[5] - raySource, normal);float r_dot_n = Vector3.Dot(rayDir, normal);if (Math.Abs(r_dot_n) <= float.Epsilon)  // 射线垂直于平面法向量,所以射线与平面平行{float dot1 = Vector3.Dot(obb3D._vertexs[0] - raySource, normal);float dot2 = Vector3.Dot(obb3D._vertexs[5] - raySource, normal);if (dot1 * dot2 > 0){return false;}}t1 = p_sub_r_dot_n1 / r_dot_n;t2 = p_sub_r_dot_n2 / r_dot_n;return true;}private bool CheckValue(ref float value1, ref float value2){if (value1 < 0 && value2 < 0){return false;}value1 = Mathf.Clamp(value1, 0, value1);value2 = Mathf.Clamp(value2, 0, value2);if (value1 > value2){float temp = value1;value1 = value2;value2 = temp;}return true;}
}

测试代码如下

using System;
using UnityEngine;public class RayOBBController : MonoBehaviour
{// Cube 立方体 Apublic Transform cube;// 定义两个 OBB3D 立方体private OBB3D obb3D;// 相交检测逻辑private RayOBBCollision rayOBBCollision;void Start(){// 实例化obb3D = new OBB3D();rayOBBCollision = new RayOBBCollision();}private bool result = false;// 创建一个小球,当射线与AABB相交时,将交点坐标设置给小球private GameObject go;void Update(){// 将两个Cube 的数据分别赋值给 OBB3DSetOBB(cube, obb3D);Vector3 point = Vector3.zero;// 判断是否相交bool isCollision = rayOBBCollision.IsCollision(transform.position, transform.forward, obb3D, ref point);if (result != isCollision){result = isCollision;// 如果设想与AABB相交,将AABB物体设置为红色cube.GetComponent<Renderer>().material.color = result ? Color.red : Color.gray;}if (result){// 如果射线与AABB相交,将小球坐标设置为相交点if (!go){go = GameObject.CreatePrimitive(PrimitiveType.Sphere);go.transform.localScale = Vector3.one * 0.2f;}go.transform.position = point;}}private void SetOBB(Transform tr, OBB3D obb){// OBB3D 的三个轴分别使用 Cube.transform:right、up、forward// OBB3D 的坐标使用 Cube.transform.position// OBB3D 的size 使用 Cube.transform.localScaleobb.Set(tr.right, tr.up, tr.forward, tr.position, tr.localScale);}
}

射线与OBB相交检测相关推荐

  1. 射线与AABB相交检测

    Box2D使用了一个叫做 slab 的碰撞检测算法. 在2D中AABB是一个矩形边界框,slab 指的是矩形一组平行线之间的范围,所以在2D中矩形边界框四条边,两两一组,可以组成两个 slab. 如下 ...

  2. 射线和三角形的相交检测(ray triangle intersection test)

    http://www.cnblogs.com/graphics/archive/2010/08/09/1795348.html 本文以Fast, Minimum Storage Ray Triangl ...

  3. 射线与圆、球相交检测

    射线与圆.球相交检测 本篇讨论2D中射线和圆的相交检测,本方法同样适用于3D中射线和球的相交检测,这是因为可以在包含射线和球心的平面中进行检测,从而将3D问题转化为2D问题.如果射线穿过球心,那么平面 ...

  4. 射线和立方体相交的判断

    本文主要介绍如何判定一条线和一个立方体相交 1.Slabs的使用(2D的介绍) 2.将Slabs推广到3D 其中只介绍数学相关,代码实现可自行实现 检测物体碰撞的时候,我们通常在物体表面添加包围盒,其 ...

  5. 空间射线与三角形相交算法的两种实现

    文章目录 1. 概述 2. 常规算法 2.1. 理论推导 2.2. 具体实现 3. 优化算法 3.1. 理论推导 3.2. 具体实现 4. 参考 1. 概述 任何复杂的三维模型都可以视作空间三角面片的 ...

  6. 《用一周学习光线追踪》2.BVH树、AABB相交检测

    本项目上接<用两天学习光线追踪>,继续学习光线追踪. 项目链接:https://github.com/maijiaquan/ray-tracing-with-imgui 目录: <用 ...

  7. NX/UG二次开发—3D几何—包围盒相交检测(转载)

    一:包围盒介绍 包围盒是指能够包容物体的三维立方体或者二维长方形,是包围体的一种,常常用于模型的碰撞检测.包围体主要包括球体.轴对齐包围盒(AABB).有向包围盒(OBB)和凸包(Convex Hul ...

  8. 【Unity】图形相交检测

    前言 图形相交检测常常用在伤害判定,使用自定义的图形相交检测,可以在一定程度上控制性能. 比如2D格斗游戏中使用的矩形包围盒(AABB),一些动作游戏中常常出现的扇形攻击. 2D的图形相交检测能够满足 ...

  9. 二维中的OBB相交测试

    二维中的OBB相交测试 置顶2013年10月23日 21:05:53 阅读数:2087 1. 背景知识 OBB全称oriented bounding box,比AABB(axis-aligned bo ...

最新文章

  1. 女朋友啥时候怒了?Keras识别面部表情挽救你的膝盖
  2. 【学术相关】直博和读完硕士再读博,在能力上的差距有多大?
  3. Harvard's CS50
  4. 超赞的 PyTorch 资源大列表,有人把它翻译成了中文版!
  5. Python中类方法、类实例方法、静态方法,私有属性和私有方法有何区别?
  6. Oracle数据泵备份与恢复 命令 expdp/impdp 用法详解
  7. JAVA指定范围生成随机数
  8. [debug] “ImportError DLL load failed 找不到指定的程序”的解析和解决办法。
  9. java 参数类型转换_java – 如何从通配符类型转换为参数化类型?
  10. 【View】之【SimpleWaveView】可多色可刷新的加速球、进度球【demo】
  11. 输入两个正整数,求其最大公约数和最小公倍数
  12. word2010里脚注横线如何顶格
  13. NXP IMX8系列应用处理器介绍
  14. (一)淘宝首页的代码(周六一天敲出来的)html结构展示
  15. LeetCode162数组寻峰问题
  16. Taobao api, Jingdong api, 1688api, Pinduoduo api, Douyin api commodity interface source code
  17. HEIF HEVC 你知道多少?
  18. CXXNET 安装教程
  19. idea通过svn上传_IDEA提交整个项目到svn
  20. 分享:STM32与迪文屏交互,轻松实现一些简单的功能!

热门文章

  1. 计算机一级ppt演示文稿第5套,PPT | 操作题第 13 套
  2. 我带你去哪里 VIII
  3. 为了数学的明天,,穿越时空,重返南大(III)-
  4. 【算法分析】实验 1. 基于贪心的会议安排问题
  5. JAVA面向对象编程学习 (1)语法基础与类与对象
  6. python中科学记数法表示_matplotlib中的科学记数法
  7. android磁盘分区,Android SD卡做磁盘分区图文教程
  8. 码云团队如何使用码云?
  9. 微信小程序项目实例——二维码生成器
  10. SQL全称量词使用存在量词替代