您的位置:首页 > 其它

使用射线矢量对三角形图元求交 D3DXIntersect()函数说明

2011-09-05 21:44 316 查看
使用射线矢量对场景中的所有三角形图元求交,获得三角形索引值和重心坐标。1 D3D扩展函数实现求交
这种方法很简单也很好用,对于应用来说应尽力是用这种方式来实现,毕竟效率比自己写得要高得多。

实际上其实没什么好讲的,大概讲一下函数D3DXIntersect吧

D3D SDK该函数声明如下

HRESULT D3DXIntersect(              LPD3DXBASEMESH pMesh,

CONST D3DXVECTOR3 *pRayPos,

CONST D3DXVECTOR3 *pRayDir,

BOOL *pHit,

DWORD *pFaceIndex,

FLOAT *pU,

FLOAT *pV,

FLOAT *pDist,

LPD3DXBUFFER *ppAllHits,

DWORD *pCountOfHits

);

l            pMesh指向一个ID3DXBaseMesh的对象,最简单的方式是从.x文件获得,描述了要进行相交检测的三角面元集合的信息,具体规范参阅direct9 SDK

l            pRayPos 指向射线发出点

l            pRayDir 指向前面我们辛辛苦苦求出的射线方向的向量

l            pHit 当检测到相交图元时,指向一个true,不与任何图元相交则为假

l            pU 用于返回重心坐标U分量

l            pV返回重心坐标V分量

l            pDist 返回射线发出点到相交点的长度

注意:以上红色字体部分均指最近的一个返回结果(即*pDist最小)

l            ppAllHits用于如果存在多个相交三角面返回相交的所有结果

l            pCountOfHits 返回共有多少个三角形与该射线相交

补充:重心坐标的概念
其中pU和pV用到了重心坐标的概念,下面稍作描述
一个三角形有三个顶点,在迪卡尔坐标系中假设表示为V1(x1,y1,z1),V2(x2,y2,z2),V3(x3,y3,z3),则三角形内任意一点的坐标可以表示为 pV = V1 + U(V2-V1) + V(V3-V1),所以已知三个顶点坐标的情况下,任意一点可用坐标(U,V)来表示,其中 参数U控制V2在结果中占多大的权值,参数V控制V3占多大权值,最终1-U-V控制V1占多大权值,这种坐标定义方式就叫重心坐标。
2射线三角面相交的数学算法

使用d3d扩展函数,毕竟有时不能满足具体需求,掌握了该方法,我们才能够获得最大的控制自由度,任意修改算法。

已知条件: 射线源点orginPoint,三角形三个顶点 v1,v2,v3,射线方向 Dir

(均以三维坐标向量形式表示)

算法目的: 判断射线与三角形是否相交,如果相交求出交点的重心坐标(U,V)和射线原点到交点的距离T。

我们可先假设射线与三角形相交则交点(注以下均为向量运算,*数乘,dot(X,Y) X,Y 点乘,cross(X,Y)X,Y叉乘;U,V,T为标量)

则:

IntersectPoint = V1 + U*(V2-V1) + V*(V3-V1) ;

IntersectPoint = originPoint + T*Dir;

所以

orginPoint + T*Dir = V1 + U*(V2-V1) + V*(V3-V1);

整理得:

这是一个简单的线性方程组,若有解则行列式 不为0。

根据T,U,V的含义当T>0, 0<U<1,0<V<1,0<U+V<1时该交点在三角形内部,

解此方程组即可获得我们关心的值,具体解法不再赘述,克莱姆法则就够了(详细见线性代数):射线原点到相交点的距离T,和交点的中心坐标(U,V)。

下面给出Direct 9 SDK示例程序中的实现代码

IntersectTriangle( const D3DXVECTOR3& orig,
const D3DXVECTOR3& dir, D3DXVECTOR3& v0,
D3DXVECTOR3& v1, D3DXVECTOR3& v2,
FLOAT* t, FLOAT* u, FLOAT* v )
{
// 算出两个边的向量
D3DXVECTOR3 edge1 = v1 - v0;
D3DXVECTOR3 edge2 = v2 - v0;
D3DXVECTOR3 pvec;
D3DXVec3Cross( &pvec, &dir, &edge2 );
// 如果det为0,或接近于零则射线与三角面共面或平行,不相交
//此处det就相当于上面的 ,
FLOAT det = D3DXVec3Dot( &edge1, &pvec );
D3DXVECTOR3 tvec;
if( det > 0 )
{
tvec = orig - v0;
}
else
{
tvec = v0 - orig;
det = -det;
}
if( det < 0.0001f )
return FALSE;
// 计算u并测试是否合法(在三角形内)
*u = D3DXVec3Dot( &tvec, &pvec );
if( *u < 0.0f || *u > det )
return FALSE;
// Prepare to test V parameter
D3DXVECTOR3 qvec;
D3DXVec3Cross( &qvec, &tvec, &edge1 );
//计算u并测试是否合法(在三角形内)
*v = D3DXVec3Dot( &dir, &qvec );
if( *v < 0.0f || *u + *v > det )
return FALSE;
/*计算t,并把t,u,v放缩为合法值(注意前面的t,v,u不同于算法描述中的相应量,乘了一个系数det),注意:由于该步运算需要使用除法,所以放到最后来进行,避免不必要的运算,提高算法效率*/
*t = D3DXVec3Dot( &edge2, &qvec );
FLOAT fInvDet = 1.0f / det;
*t *= fInvDet;
*u *= fInvDet;
*v *= fInvDet;
return TRUE;
}

3 拾取完成根据获得的中心坐标计算我们关心的常见量,。

根据重心坐标(U,V),我们可以很容易的算出各种相关量比如纹理坐标和交点的差值颜色,假设以纹理坐标为例设V1,V2,V3的纹理坐标分别为T1(tu1,tv1),T2(tu2,tv2),T3(tu3,tv3)则交点的坐标为

IntersectPointTexture = T1 + U(T2-T1) + V(T3-T1)

http://hi.baidu.com/tshmliy/blog/item/63dcc786f5b1083b67096ea4.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: