3D空间中射线与三角形的交叉检测算法

引言

射线Ray,在3D图形学中有很多重要的应用。比如,pick操作就是使用射线Ray来实现的,还有诸如子弹射线的碰撞检测等等都可以使用射线Ray来完成。所以,在本次博客中,将会简单的像大家介绍下,如何进行Ray-Triangle的交叉检测。

Ray-Triangle交叉检测算法

在Tomas Moller的MT97论文中,提出了一种新的算法。这种算法能够减少以前进行Ray-Triangle交叉检测所需要的内存消耗。在以前,进行Ray-Triangle交叉检测,主要是计算射线与三角形所构成的平面的交点,然后重新判断交点是否在三角形上,从而来判断是否发生了交叉。这种方法很直观,符合我们一直以来所学的数学知识。但是,这种检测方法进行的计算较多,而且还需要根据三角形来求它所在的平面,这样又需要进行计算,同时也需要另外开辟空间来保存计算出来的平面。

数学之美,就在于能够找到其他的方法来代替这种显而易见的方式,从而将问题简化到一定的程度。这种简化的过程,不需要在代码中实现,只需要我们事先根据条件,然后在草稿纸上计算出最后的结论,我们只需要在我们的代码中直接使用最终得到的结论即可。

在Tomas Moller的论文中,它提到了这样的一个概念:

如果一个点在三角形V0, V1, V2上,那么这个点就可以用如下的方式来表示:

T(u, v) = (1 - u - v) * V0 + u * V1 + v * V2 ;

这里u+v <= 1, u >= 0 ,  v >=0

而对于射线,我们一般使用如下的方程来表示它:

R (t)= O + t * D ; (O为射线的起始点,D为射线的方向)

所以,既然他们要有交点,我们就能够直接使用如下的方法来得出:

O + t * D = (1 - u - v) * V0 + u * V1 + v * V2

然后在进行一系列的变换,最终得到结果。感兴趣的读者可以自行阅读Tomas Moller的论文,论文中详细的解释了推导过程。这里不再赘述。

Ray-Triangle交叉检测算法实现

以下是Ray-Triangle交叉检测算法的Moller算法实现,基本上就是Tomas Moller论文中代码的拷贝,如下所示:

<span style="font-family:Microsoft YaHei;">bool Ray::intersectWithTriangle(VECTOR3 v0,VECTOR3 v1, VECTOR3 v2,
			bool bCull,
			float *t)
{
	VECTOR3 edge1, edge2, tvec, pvec, qvec ;
	float det, inv_det ;
	float u,v ;

	//Find vectors for two edges sharing vert0
	Vec3Sub(edge1, v1, v0);
	Vec3Sub(edge2, v2, v0);

	//Begin calculating determinant - also used to calculate U parameter
	Vec3Cross(pvec, dir, edge2);

	//If the determinant is near zero, ray lies in plane of triangle
	Vec3Dot(det, edge1, pvec);

	//If bCull is true
	if(bCull)
	{
		if(det < 0.00001f)
			return false ;

		//Calculate distance from vert0 to ray origin
		Vec3Sub(tvec, origin, v0);

		//Calculate U parameter and test bounds
		Vec3Dot(u, tvec, pvec);
		if(u < 0.0 || u > det)
			return false ;

		//Prepare to test v parameter
		Vec3Cross(qvec, tvec, edge1);

		//Calculate V parameter and test bounds
		Vec3Dot(v, dir, qvec);
		if(v < 0.0f || u + v > det)
			return false ;

		//Calculate t , scale paramter, ray intersect triangle
		Vec3Dot(*t, edge2, qvec);
		inv_det = 1.0f / det ;
		*t *= inv_det ;
		u *= inv_det ;
		v *= inv_det ;
	}
	else
	{
		if(det > -0.00001f && det < 0.00001)
			return false ;
		inv_det = 1.0f / det ;

		//calculate distance from v0 to ray origin
		Vec3Sub(tvec, origin, v0);

		//Calculate u parameter  and test bounds
		Vec3Dot(u, tvec, pvec);
		u *= inv_det ;
		if(u < 0.0 || u > 1.0)
			return false ;

		//prepare to test v parameter
		Vec3Cross(qvec, tvec, edge1);

		//Calculate v parameter and test bounds
		Vec3Dot(v, dir, qvec);
		v *= inv_det ;
		if(v < 0.0 || u + v > 1.0)
			return false ;

		//calculate t, ray intersect triangle
		Vec3Dot(*t, edge2, qvec);
		*t *= inv_det ;
	}

	return true ;
}// end for intersectWithTriangle</span>

示例程序截图

这个图是在没有发生交叉的时候的情况,

下图是在发生了交叉之后的截图:

今天的笔记就此结束。以后会陆续出现这种文章,请大家关注吧!!!

3D空间中射线与三角形的交叉检测算法

时间: 2024-10-25 08:23:35

3D空间中射线与三角形的交叉检测算法的相关文章

3D空间中射线与轴向包围盒AABB的交叉检测算法

引言 在上一节中,我讲述了如何实现射线与三角形的交叉检测算法.但是,我们应该知道,在游戏开发中,一个模型有很多的三角形构成,如果要对所有的物体,所有的三角形进行这种检测,就算现在的计算机运算能力,也是无法高效的完成.所以,我们需要通过其他的手段来提早剔除一些不可能发生交叉的物体,这种早退的思想,大量的运用在3D游戏技术中.在本篇文章中,我将像大家讲述如何实现射线与轴向包围盒AABB的交叉检测.如果读者不明白什么是轴向包围盒,请看这篇文章. Ray-AABB交叉检测算法 现如今,有很多的Ray-A

3D空间中射线与轴向包围盒AABB的交叉检测算法【转】

引言 在上一节中,我讲述了如何实现射线与三角形的交叉检测算法.但是,我们应该知道,在游戏开发中,一个模型有很多的三角形构成,如果要对所有的物体,所有的三角形进行这种检测,就算现在的计算机运算能力,也是无法高效的完成.所以,我们需要通过其他的手段来提早剔除一些不可能发生交叉的物体,这种早退的思想,大量的运用在3D游戏技术中.在本篇文章中,我将像大家讲述如何实现射线与轴向包围盒AABB的交叉检测.如果读者不明白什么是轴向包围盒,请看这篇文章. Ray-AABB交叉检测算法 现如今,有很多的Ray-A

3D空间中射线与轴向包围盒AABB的交叉检测算法 【转】

http://blog.csdn.net/i_dovelemon/article/details/38342739 引言 在上一节中,我讲述了如何实现射线与三角形的交叉检测算法. 但是,我们应该知道,在游戏开发中,一个模型有很多的三角形构成,如果要对所有的物体,所有的三角形进行这种检测,就算现在的计算机运算能力,也是无法高 效的完成.所以,我们需要通过其他的手段来提早剔除一些不可能发生交叉的物体,这种早退的思想,大量的运用在3D游戏技术中.在本篇文章中,我将像大家讲 述如何实现射线与轴向包围盒A

Ray-AABB交叉检测算法

??最近在解决三维问题时,需要判断线段是否与立方体交叉,这个问题可以引申为:射线是否穿过立方体AABB. ??在3D游戏开发中碰撞检测普遍采用的算法是轴对齐矩形边界框(Axially Aligned Bounding Box, AABB)包装盒方法,其基本思想是用一个立方体或者球体完全包裹住3D物体对象,然后根据包装盒的距离.位置等相关信息来计算是否发生碰撞. slab的碰撞检测算法 ??本文接下来主要讨论射线与AABB的关系,主要对box2d碰撞检测使用的slab的碰撞检测算法(Slabs m

在3D空间中绘制四边形

在3D空间中绘制四边形 四边形 GL_QUADS OpenGL的GL_QUADS图元用于绘制四边形,它根据每四个顶点绘制一个四边形. 注意,在使用四边形时,必需记住一个重要规则:一个四边形的四个角必须位于同一个平面中(不存在弯曲的四边形).如图所示 四边形带 GL_QUAD_STRIP 该图元指定一个连接的四边形带.它们都保持相同方向的环绕.如图所示 通用多边形 GL_POLYGON 我们可以用它绘制任意数量的多边形.与四边形一样,多边形的所有顶点也必须位于同一平面中.如果想越过这个规则,可以采

Qt_OpenGL:3D空间中移动图像

Qt_OpenGL:3D空间中移动图像 //.h #ifndef GLWIDGET_H #define GLWIDGET_H #include <QGLWidget> #include <QtOpenGL> class QGLWidget; class QTimer; typedef struct Stars{ public: int r, g, b; GLfloat dist, angle; }Stars; class GLWidget : public QGLWidget {

使3D空间中物体朝向和其速度方向一致的旋转矩阵计算方案

在3D空间中的物体以某一速度运动,有时候需要这个物体的朝向和速度的方向一致, 为了实现这个目标我们一般借助旋转矩阵 M 来将物体旋转到对应的朝向. 例如速度方向矢量 spdV: Vector3D(1,2,3), X轴基向量为 axis_x: Vector3D(1,0,0), 这个矢量的方向和3D物体不做任何旋转时候的默认朝向一致 3D矢量 cross_x 记录了 axis_x 叉乘 spdV 的结果. 算出矩阵 M 的方法一: 先计算出 spdV 和 axis_x 两矢量之间的弧度值 rad(可

2D和3D空间中计算两点之间的距离

自己在做游戏的忘记了Unity帮我们提供计算两点之间的距离,在百度搜索了下. 原来有一个公式自己就写了一个方法O(∩_∩)O~,到僵尸到达某一个点之后就向另一个奔跑过去 /// <summary> /// 3维中如何计算两点之间的距离 /// </summary> /// <param name="p1"></param> /// <param name="p2"></param> /// &l

OpenGl学习进程(9)在3D空间的绘制实例

    本节将演示在3D空间中绘制图形的几个简单实例:     (1)在3D空间内绘制圆锥体: #include <GL/glut.h> #include <math.h> #pragma comment(linker,"/subsystem:\"windows\" /entry:\"mainCRTStartup\"") #define PI 3.1416 GLfloat xRot = 0; GLfloat yRot =