zoukankan      html  css  js  c++  java
  • 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>




    演示样例程序截图

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

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


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


  • 相关阅读:
    【crontab】误删crontab及其恢复
    New Concept English there (7)
    New Concept English there (6)
    New Concept English there (5)
    New Concept English there (4)
    New Concept English there (3)
    New Concept English there (2)Typing speed exercise
    New Concept English there (1)Typing speed exercise
    New Concept English Two 34 game over
    New Concept English Two 33 94
  • 原文地址:https://www.cnblogs.com/yxwkf/p/5142700.html
Copyright © 2011-2022 走看看