🎯 光与面的命运交锋:Möller-Trumbore 线段三角形相交算法全解析

by:一位在像素海洋里追光逐影的几何诗人


🌌 引言:光线穿越虚拟空间的哲学思考

在这个由点、线、面织成的虚幻世界中,有一个永恒的追问:

"这道光线,会不会撞上那片三角形?"

这不是哲学,是图形学的核心问题 。你在玩射击游戏?检测子弹是否命中敌人模型。你在做路径追踪?判断光线是否被场景遮挡。都绕不开这个关键判断:线段是否与三角形相交

在这里,登场的主角是计算机图形学中一位超级英雄------Möller-Trumbore 相交算法 。它以高效、健壮、优雅著称,号称图形学界的"速度与精度之王"。


⚙️ 背后机制:三角形的三重命题

一个三角形由三个点 A、B、C 组成,而一条线段由两个点 O(起点)和 E(终点)构成。

你要做的事情是------判断从 O 出发射出一条线段 OE,是否会和三角形 ABC 的内部发生"命运交汇"。

Möller-Trumbore 的核心思想是:

不搞繁杂的平面方程,不管三角形法线方向,直接解一个线性系统,用向量叉乘与点乘一波带走。


🧠 算法结构:几何就是代数穿了个马甲

先抛开数学公式,用更形象的方式理解它的步骤:

  1. 建构三角形边向量:我们拿三角形边当参照物,构建向量 AB 和 AC。

  2. 构造线段方向向量 D = E - O,也就是光线的方向。

  3. 通过叉乘反推一个线性系统 ,用来解出 u, v, t 三个变量,分别代表:

    • uv 是三角形内部的"重心坐标"。
    • t 是从 O 到交点的比例距离。

如果:

  • u, v 都在 0 到 1 之间
  • u + v <= 1
  • t >= 0 && t <= 1(因为是线段,不是无限光线)

那就说明交点就在三角形内部!


💡 优化秘技:提前退出 + 一次除法

在传统的 Möller-Trumbore 实现中,我们可能会在每步都计算除法。但事实上:

  • 除法是 CPU 中最昂贵的基本运算之一。
  • 很多中间值的检查(比如是否与三角形平行)根本不需要除法

所以我们的优化目标是:

将所有判断都提前用乘法完成,最后一步才执行一次除法。

这样既节约性能,又避免浮点精度带来的灾难。


💻 JavaScript 实现:撸起袖子干活

ini 复制代码
function intersectSegmentTriangle(O, E, A, B, C) {
  const EPSILON = 1e-8;

  const edge1 = new THREE.Vector3().subVectors(B, A);
  const edge2 = new THREE.Vector3().subVectors(C, A);

  const D = new THREE.Vector3().subVectors(E, O); // 线段方向
  const P = new THREE.Vector3().crossVectors(D, edge2); // 用于解u
  const det = edge1.dot(P);

  // 如果行列式接近0,说明线段和平面几乎平行
  if (Math.abs(det) < EPSILON) return null;

  const invDet = 1 / det; // 只除一次!

  const T = new THREE.Vector3().subVectors(O, A);
  const u = T.dot(P) * invDet;
  if (u < 0 || u > 1) return null; // 提前退出!

  const Q = new THREE.Vector3().crossVectors(T, edge1);
  const v = D.dot(Q) * invDet;
  if (v < 0 || u + v > 1) return null; // 不在三角形内

  const t = edge2.dot(Q) * invDet;
  if (t < 0 || t > 1) return null; // 交点不在线段范围内

  // 命中啦!计算交点
  const intersection = new THREE.Vector3().addVectors(O, D.multiplyScalar(t));
  return intersection;
}

🎭 一场合理的提前退出

每一个 return null,都是你理性地避免 GPU 徒劳工作。

就像一位精明的侦探,在调查过程中发现关键线索不对,就当场终止调查,不浪费每一滴咖啡。


🎲 Möller-Trumbore vs 其他算法

算法 优点 缺点
Möller-Trumbore 极快、简单、适用于任意三角形 不返回法线、不检测后面(可改进)
面法线投影法 数学直观 慢、精度低
Barycentric重心法 可扩展到重建纹理坐标 解方程更复杂
Plücker坐标法 最精确 理解门槛高、实现复杂

Möller-Trumbore 就像图形学中的瑞士军刀:你不一定总用,但用上它就是真香。


🧪 实战应用

  • 碰撞检测引擎:判断子弹是否穿过模型网格
  • 路径追踪器:光线和三角形网格是否首次相交
  • 拾取系统:鼠标点击是否击中场景中的物体
  • 可见性分析:判断两点之间是否被遮挡

🧙 尾声:一场几何与速度的约会

Möller-Trumbore 算法,是图形学领域的一首古典钢琴曲,它用线性代数编排旋律,用叉乘与点乘击打节奏,在空间与时间之间,谱出了一场精准的交响乐。

而我们所做的优化------

  • 一次除法
  • 提前退出
    就像是给它换上了低延迟机械键盘,让演奏更加利落、精准。

📚 延伸阅读


愿你在追踪每一道光线时,不再迷路,而是直指交点,命中目标。

------图形学之诗人,算法之匠人 💡

相关推荐
患得患失94927 分钟前
【前端】【vscode】【.vscode/settings.json】为单个项目配置自动格式化和开发环境
前端·vscode·json
飛_30 分钟前
解决VSCode无法加载Json架构问题
java·服务器·前端
YGY Webgis糕手之路3 小时前
OpenLayers 综合案例-轨迹回放
前端·经验分享·笔记·vue·web
90后的晨仔3 小时前
🚨XSS 攻击全解:什么是跨站脚本攻击?前端如何防御?
前端·vue.js
Ares-Wang3 小时前
JavaScript》》JS》 Var、Let、Const 大总结
开发语言·前端·javascript
90后的晨仔3 小时前
Vue 模板语法完全指南:从插值表达式到动态指令,彻底搞懂 Vue 模板语言
前端·vue.js
德育处主任4 小时前
p5.js 正方形square的基础用法
前端·数据可视化·canvas
烛阴4 小时前
Mix - Bilinear Interpolation
前端·webgl
90后的晨仔4 小时前
Vue 3 应用实例详解:从 createApp 到 mount,你真正掌握了吗?
前端·vue.js
德育处主任4 小时前
p5.js 矩形rect绘制教程
前端·数据可视化·canvas