原帖:http://blog.csdn.net/nhsoft/archive/2004/06/23/22992.aspx
这个算法来自微软DirectX SDK.兰幽草推荐的.
基本算法都想明白了。就是那个t 为什么没有负号.我还没有想明白.不知道为什么
不过结果基本已经正确了。应该比较好用的。
bool InterSection(XRay& ray,XTriangle& tri,XPoint& point,float& t, float& u, float& v )
{
// Find vectors for two edges sharing vert0
/***
三角形为 v1,v2,v3
两条边为 e1 = v2-v1 e2 = v3 - v1
射线为 ray = p0 + d * t
三角形内部的一点 p = v1 + u * e1 + v * e2 ( u+v<1)
所以:
v1 + u * e1 + v * e2 = p0 + d * t ===>
u * e1 + v * e2 - t * d = p0 - v1 ===>
- t * d + v * e2 + u * e1 = p0 - v1 ===>
| d.x d.y d.z |
[-t,v,u] | e2.x e2.y e2.z | = p0 - p1 ===>
| e1.x e1.y e1.z |
[-t,v,u] * M = p0 - p1 ;
[-t,v,u] = (p0 - p1) * Inv(M);
t = (p0 - p1) * e1 X e2 / Det(M) = (p0 - p1) X e1 * e2 / Det(M)
v = (p0 - p1) * e1 X d / Det(M) = (p0 - p1) X e1 * d / Det(M)
u = (p0 - p1) * d X e2 / Det(M)
**/
XVector3D e1 = tri.m_points[1] - tri.m_points[0];
XVector3D e2 = tri.m_points[2] - tri.m_points[0];
//求出矩阵 M 的 det(M)。并记录 d x e2;
XVector3D vCP_dir_e2;
ray.m_Dir.cp(e2,vCP_dir_e2);
//得到矩阵的行列式的值
float det = e1.dp(vCP_dir_e2);
//保存 (p0 - p1)
XVector3D v_p0_p1;
//为了判断方便。det = abs(det)
if( det > 0 )
{
v_p0_p1 = ray.m_Point - tri.m_points[0];
}
else
{
v_p0_p1 = tri.m_points[0] - ray.m_Point ;
det = -det;
}
if( det < 0.0000001f )
return false;
// u = (p0 - p1) * d X e2 / Det(M) Det(M)以后再除
u = v_p0_p1.dp(vCP_dir_e2);
if( u < 0.0f || u > det )
return false;
// 保存 (p0 - p1) X e1
XVector3D vCP_p0p1_e1;
v_p0_p1.cp(e1,vCP_p0p1_e1);
// v = (p0 - p1) * e1 X d / Det(M) = (p0 - p1) X e1 * d / Det(M)
// Det(M)以后再除
v = ray.m_Dir.dp(vCP_p0p1_e1);
if( v < 0.0f || u + v > det )
return false;
// Calculate t, scale parameters, ray intersects triangle
t = e2.dp(vCP_p0p1_e1);
float fInvDet = 1.0f / det;
t *= fInvDet;
u *= fInvDet;
v *= fInvDet;
point = ray.m_Point + ray.m_Dir*t;
return true;
}
按照仿射坐标系分解来理解就更好了。 三角形的两个边就是仿射坐标系的两个轴 把点坐标分解为仿射坐标(u,v) 0<=u<=1 && 0<=v<=1 && u+v<1 表示点在三角形内部 |