射线与空间内三角形的相交检测算法(Möller-Trumbore)的推导与实践
背景介绍(学习算法之前需要先了解)
射线与空间内三角形的相交检测是游戏程序设计中一个常见的问题,最典型的应用就是拾取(Picking),本文介绍一个最常见的方法,这个方法也是DirectX中采用的方法,该方法速度快,而且存储空间少。先讲述理论,然后文章末尾给出对应的代码实现与Unity中的显示。
简单而直观的方法是:先判断射线是否与三角形所在的平面相交,如果相交,再判断交点是否在三角形内。但这种方法效率并不高,因为多计算了三角形所在的平面。
Möller-Trumbore射线三角相交算法是一种快速计算射线与空间内三角形的交点的方法,通过向量与矩阵计算可以快速得出交点与重心坐标,而无需对包含三角形的平面方程进行预计算。它应用于计算机图形学中以实现涉及三角形网格的光线跟踪计算。算法名字是以发明者TomasMöller和Ben Trumbore的名字来命名的。


参数说明
设射线的方程Ray=O+td(O为起点,D为射线方向(方向向量),t为权重),一个点从起点O开始,沿着方向D移动任意长度,得到终点R,根据t值得不同,得到得R值也不同,所有这些不同的R值便构成了整条射线。
三角形三个顶点P0,P1,P2。u为P1的权重,v为P2的权重,而1-u-v是P0的权重,可以理解为沿着边AC移动一段距离,然后再沿着边AB移动一段距离,最后求它们的和向量。至于移动多大距离,就是由参数u和v控制的,所表达的数学意义是三角形及其内部所有点的方程。

\]
\]
推导过程
两个重要的定理
克莱姆法则
解线性方程组时
\]
D,E1,E2是含有三个参数的行列式,即可表达成
\]
\]
\]
向量混合积
a·(b×c)=-a·(c×b)\\
a·(b×c)=-b·(a×c)\\
a·(b×c)=-c·(b×a)
\]
将方程联立
\]
化简
S=uE_1+vE_2-td\\{\quad}(S=O-P0,E_1=P1-P0,E_2=P2-P0)
\]
\]
克拉姆法则
\]
向量混合积
分母部分
运用向量混合积定理,D前的-号,被抵消了
\]
令
\]
分子部分:
\]
令
\]
原式等于
\]
因此
\]
同理可推得其他两个参数u,v
\]
\]
总结
我们在最后可以通过已知的数据,求出t、u、v三个参数,通过三个参数的范围限制判断是否相交,如果不满足则不相交,如果满足则相交
代码实现
// Vector3 a b c triangle vertexs
// orig is ray original point, dir is direction vector
bool rayTriangleIntersect(Vector3 orig, Vector3 dir,
Vector3 a, Vector3 b, Vector3 c, float t, float b1, float b2)
{
bool isIn = false;
Vector3 E1 = b - a;
Vector3 E2 = c - a;
Vector3 S = orig - a;
Vector3 S1 = Vector3.Cross(dir, E2);
Vector3 S2 = Vector3.Cross(S, E1);
// 共同系数
float coeff = 1.0f / Vector3.Dot(S1, E1);
t = coeff * Vector3.Dot(S2, E2);
b1 = coeff * Vector3.Dot(S1, S);
b2 = coeff * Vector3.Dot(S2, dir);
Debug.Log($"t = {t}, b1 = {b1}, b2 = {b2}");
if (t >= 0 && b1 >= 0 && b2 >= 0 && (1 - b1 - b2) >= 0)
{
isIn = true;
}
return isIn;
}
Unity中的演示效果
当射线与三角形相交时,三角形的材质会变成红色,射线是采用LineRenderer的形式,三角形用了编辑材质顶点的脚本,过几天会分享出来~
项目地址:https://github.com/shadow-lr/RayTriangleIntersect



题外话
虽然射线和三角形的相交检测可以用来实现拾取(Picking),但是大多数程序并不采用这个方法,原因是这个方法效率很低,我们可以设想,一个大型的3D游戏,某个模型的三角形数量很可能是百万级的,在此情况下,对模型上的每个三角形求交是一件极其耗费时间的事情。
所以一般可行的方法是,用包围球和包围盒(AABB、OBB、FDH)来代替,计算出能容纳模型的最小球体或者举行提,只要判断射线与包围球或者包围盒求交即可,只是精确度上有一定误差,但是足以满足多数程序的需要。
射线与空间内三角形的相交检测算法(Möller-Trumbore)的推导与实践的更多相关文章
- 射线和三角形的相交检测(ray triangle intersection test)【转】
本文以Fast, Minimum Storage Ray Triangle Intersection为参考,在此感谢原作者,大家也可以直接阅读原版. 概述 射线和三角形的相交检测是游戏程序设计中一个常 ...
- 3D空间中射线与三角形的交叉检测算法【转】
引言 射线Ray,在3D图形学中有很多重要的应用.比如,pick操作就是使用射线Ray来实现的,还有诸如子弹射线的碰撞检测等等都可以使用射线Ray来完成.所以,在本次博客中,将会简单的像大家介绍下,如 ...
- 3D空间中射线与轴向包围盒AABB的交叉检测算法【转】
引言 在上一节中,我讲述了如何实现射线与三角形的交叉检测算法.但是,我们应该知道,在游戏开发中,一个模型有很多的三角形构成,如果要对所有的物体,所有的三角形进行这种检测,就算现在的计算机运算能力,也是 ...
- 3D空间中射线与轴向包围盒AABB的交叉检测算法 【转】
http://blog.csdn.net/i_dovelemon/article/details/38342739 引言 在上一节中,我讲述了如何实现射线与三角形的交叉检测算法. 但是,我们应该知道, ...
- 求空间内两条直线的最近距离以及最近点的坐标(C++)
关键词:空间几何 用途:总有地方会用到吧 文章类型:C++函数展示 @Author:VShawn(singlex@foxmail.com) @Date:2016-11-19 @Lab: CvLab20 ...
- hihoCoder-1633 ACM-ICPC北京赛区2017 G.Liaoning Ship’s Voyage 线段与三角形规范相交
题面 题意:给你一个20*20的地图,起点(0,0),终点(n-1,n-1),有障碍的点为‘#’,每次可以向8个方向走一步,还给了一个三角形,除了障碍以外,到这8个方向上的点的线段如果没有与三角形相交 ...
- Ray-AABB交叉检测算法
最近在解决三维问题时,需要判断线段是否与立方体交叉,这个问题可以引申为:射线是否穿过立方体AABB. 在3D游戏开发中碰撞检测普遍采用的算法是轴对齐矩形边界框(Axially Aligned ...
- [转]前景检测算法--ViBe算法
原文:http://blog.csdn.net/zouxy09/article/details/9622285 转自:http://blog.csdn.net/app_12062011/article ...
- 【深度学习】目标检测算法总结(R-CNN、Fast R-CNN、Faster R-CNN、FPN、YOLO、SSD、RetinaNet)
目标检测是很多计算机视觉任务的基础,不论我们需要实现图像与文字的交互还是需要识别精细类别,它都提供了可靠的信息.本文对目标检测进行了整体回顾,第一部分从RCNN开始介绍基于候选区域的目标检测器,包括F ...
随机推荐
- canvas-修改图片亮度
canvas操作-修改图片亮度 目录 canvas操作-修改图片亮度 图片亮度的概念 下面用ps截图举一个例子: 调整图片亮度的方案 实现方案一 从RGB到HSV的转换 转换的公式 javascrip ...
- PTA 中序输出叶子结点
6-8 中序输出叶子结点 (10 分) 本题要求实现一个函数,按照中序遍历的顺序输出给定二叉树的叶结点. 函数接口定义: void InorderPrintLeaves( BiTree T); T ...
- [Design Pattern With Go]设计模式-工厂模式
这次介绍的设计模式是工厂模式,这是一个比较常见的创建型模式.一般情况下,工厂模式分为三种:简单工厂.工厂方法和抽象工厂,下面慢慢举例介绍下. 简单工厂 考虑一个加密程序的应用场景,一个加密程序可能提供 ...
- 在M1芯片的Mac系统上做.net core开发靠谱吗?
作为一个7年老.NET程序员,最近几年苹果慢慢接替微软,成为我心中最酷的科技公司. 为什么我会选择Mac os作为我的开发环境? 很多做.net的同学都使用Windows系统作为自己的开发环境,我其实 ...
- Spring Cloud 升级之路 - 2020.0.x - 2. 使用 Undertow 作为我们的 Web 服务容器
本项目代码地址:https://github.com/HashZhang/spring-cloud-scaffold/tree/master/spring-cloud-iiford 在我们的项目中,我 ...
- > 与 < 差在哪?-- Shell十三问<第十一问>
> 与 < 差在哪?-- Shell十三问<第十一问> 谈到 I/O redirection ,不妨先让我们认识一下 File Descriptor (FD) .程序的运算,在 ...
- [素数判断]P1125 笨小猴
笨小猴 题目描述 笨小猴的词汇量很小,所以每次做英语选择题的时候都很头疼.但是他找到了一种方法,经试验证明,用这种方法去选择选项的时候选对的几率非常大! 这种方法的具体描述如下:假设maxn是单词中出 ...
- Java中的equals()和hashCode() - 超详细篇
前言 大家好啊,我是汤圆,今天给大家带来的是<Java中的equals()和hashCode() - 详细篇>,希望对大家有帮助,谢谢 文章纯属原创,个人总结难免有差错,如果有,麻烦在评论 ...
- 带你全面认识CMMI V2.0(五)——改进
改进(Improving)涉及开发.管理和改进过程及其相关资产,其主要重点是提高组织绩效.保持习惯和持久性可确保过程在整个组织中是持久.习惯性地执行和维持,并有助于有效地实现业务绩效目标.治理(GOV ...
- C#修改AD账号及密码
在使用AD域环境搭建的账号系统修改密码的时候比较麻烦一般需要管理员在域环境去进行对用户的密码进行修改. 以下就是用来查询和修改AD域密码的方法. 1 /// <summary> 2 /// ...