如何求三角形和线的交点InterSection函数

来源:互联网 发布:python generator 协程 编辑:程序博客网 时间:2024/05/06 07:05

原帖: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 表示点在三角形内部

原创粉丝点击