射线与三角面相交判定

转:http://www.cnblogs.com/graphics/archive/2010/08/09/1795348.html
射线表示:
O + D *t
三角表示:
V0 + (V1 - V0)*u + (V2 - V0) * v
u >= 0;
v >= 0;
u + v < 1; 
如果射线相交在三角内,则:
O + D *t = V0 + (V1 - V0)*u + (V2 - V0) * v
u >= 0;
v >= 0;
u + v < 1; 
分析:uvt是3个未知数, V0,V1,V2,O,D是已知向量,是个3阶行列式,可求uvt
可以做简化
E1 = V1 - V0;
E2 = V2 - V0;
T = O - V0;
O + D *t = V0 + (V1 - V0)*u + (V2 - V0) * v
=》
- D *t + E1*u + E2 * v = T
=》
|-D  E1 E2| t = T
|               | u 
|               | v  
三阶行列式求解(克莱姆法则)
=》
t = det|T E1 E2| / det|-D E1 E2|  
u = det|-D T E2| / det|-D E1 E2|  
v = det|-D E1 T| / det|-D E1 E2| 
下面的推导只是为简化函数   
根据混合积公式(等价的代数余子式表示方法)  
det|a b c| = aXb *c = bXc *a = -aXc *b  //这里3种转换,只是为后面简化成PQ更方便
=》
t = TxE1 *E2 / DxE2 *E1
u = DxE2 *T  / DxE2 *E1
v = TxE1 *D  / DxE2 *E1
简化
P = DxE2
Q = TxE1 
=》
t = Q *E2 / P *E1
u = P *T  / P *E1
v = Q *D  / P *E1
函数实现:
bool InterSectTrangle(
const vec3& O, const vec3& D,
const vec3& V0, const vec3& V1, const vec3& V2,
float& t, float& u, float& v)
{
vec3 E1 = v1 - v0;
vec3 E2 = v2 - v0;
vec3 P  = cross(D, E2);
float det = dot(P, E1);
    
vec3 T;
if(det > 0)
{
    T = O - V0;
}
else
{
    T = V0 - O;
    det = -det;
}


if(det < 0.0001f)
    return false;


u = dot(P, T);
if(u < 0 || u > det)
    return false;


vec3 Q = cross(T, E1);
    
v = dot(Q, D);
if(v < 0 || u + v > det)
    return false;


t = dot(Q, E2);


float invDet = 1.0f / det;


t  *= invDet;
u *= invDet;
v  *= invDet;


return true;
}


代码说明:
1,里面有很多if为了提高代码效率,
2,确保det>0,如果det<0则令det = -det,并对T做相应的调整,这样做是为了方便后续计算,否则的话需要分别处理det>0和det<0两种情况。
3,if(det < 0.0001f) 此时无解,三角与射线近乎平行,注意浮点数和0的比较,一般不用 == 0的方式,而是给定一个Epsilon值,并与这个值比较。
4,u = dot(P, T);这里实际上u还没有计算完毕,此时的值是dot(P,T),如果dot(P,T) > det, 那么u > 1,无交点。
5,要确保u + v <= 1,也即 [dot(P,T) + dot(Q, D)] / det 必须不能大于1,否则无交点。


 
交点坐标:
根据上面代码求出的t,u,v的值,交点的最终坐标可以用下面两种方法计算


O + Dt


(1 - u - v)V0 + uV1 + vV2  
*/

猜你喜欢

转载自blog.csdn.net/u010400998/article/details/80676227