射线与OBB相交检测
在上一篇 射线与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相交检测相关推荐
- 射线与AABB相交检测
Box2D使用了一个叫做 slab 的碰撞检测算法. 在2D中AABB是一个矩形边界框,slab 指的是矩形一组平行线之间的范围,所以在2D中矩形边界框四条边,两两一组,可以组成两个 slab. 如下 ...
- 射线和三角形的相交检测(ray triangle intersection test)
http://www.cnblogs.com/graphics/archive/2010/08/09/1795348.html 本文以Fast, Minimum Storage Ray Triangl ...
- 射线与圆、球相交检测
射线与圆.球相交检测 本篇讨论2D中射线和圆的相交检测,本方法同样适用于3D中射线和球的相交检测,这是因为可以在包含射线和球心的平面中进行检测,从而将3D问题转化为2D问题.如果射线穿过球心,那么平面 ...
- 射线和立方体相交的判断
本文主要介绍如何判定一条线和一个立方体相交 1.Slabs的使用(2D的介绍) 2.将Slabs推广到3D 其中只介绍数学相关,代码实现可自行实现 检测物体碰撞的时候,我们通常在物体表面添加包围盒,其 ...
- 空间射线与三角形相交算法的两种实现
文章目录 1. 概述 2. 常规算法 2.1. 理论推导 2.2. 具体实现 3. 优化算法 3.1. 理论推导 3.2. 具体实现 4. 参考 1. 概述 任何复杂的三维模型都可以视作空间三角面片的 ...
- 《用一周学习光线追踪》2.BVH树、AABB相交检测
本项目上接<用两天学习光线追踪>,继续学习光线追踪. 项目链接:https://github.com/maijiaquan/ray-tracing-with-imgui 目录: <用 ...
- NX/UG二次开发—3D几何—包围盒相交检测(转载)
一:包围盒介绍 包围盒是指能够包容物体的三维立方体或者二维长方形,是包围体的一种,常常用于模型的碰撞检测.包围体主要包括球体.轴对齐包围盒(AABB).有向包围盒(OBB)和凸包(Convex Hul ...
- 【Unity】图形相交检测
前言 图形相交检测常常用在伤害判定,使用自定义的图形相交检测,可以在一定程度上控制性能. 比如2D格斗游戏中使用的矩形包围盒(AABB),一些动作游戏中常常出现的扇形攻击. 2D的图形相交检测能够满足 ...
- 二维中的OBB相交测试
二维中的OBB相交测试 置顶2013年10月23日 21:05:53 阅读数:2087 1. 背景知识 OBB全称oriented bounding box,比AABB(axis-aligned bo ...
最新文章
- 女朋友啥时候怒了?Keras识别面部表情挽救你的膝盖
- 【学术相关】直博和读完硕士再读博,在能力上的差距有多大?
- Harvard's CS50
- 超赞的 PyTorch 资源大列表,有人把它翻译成了中文版!
- Python中类方法、类实例方法、静态方法,私有属性和私有方法有何区别?
- Oracle数据泵备份与恢复 命令 expdp/impdp 用法详解
- JAVA指定范围生成随机数
- [debug] “ImportError DLL load failed 找不到指定的程序”的解析和解决办法。
- java 参数类型转换_java – 如何从通配符类型转换为参数化类型?
- 【View】之【SimpleWaveView】可多色可刷新的加速球、进度球【demo】
- 输入两个正整数,求其最大公约数和最小公倍数
- word2010里脚注横线如何顶格
- NXP IMX8系列应用处理器介绍
- (一)淘宝首页的代码(周六一天敲出来的)html结构展示
- LeetCode162数组寻峰问题
- Taobao api, Jingdong api, 1688api, Pinduoduo api, Douyin api commodity interface source code
- HEIF HEVC 你知道多少?
- CXXNET 安装教程
- idea通过svn上传_IDEA提交整个项目到svn
- 分享:STM32与迪文屏交互,轻松实现一些简单的功能!