概念就不介绍了,直接先上数学。
重心坐标:设三角形所在平面一点P的重心坐标为(a,b,c)则 a+b+c = 1;
( 三角形所在平面的所有点都可以用重心坐标表示,如果在三角形外面,则:
a,b,c三个数当中必有一个为负数!!!!)
这一点P的3D坐标为(Px, Py, Pz);
三角形的三个点为(顺时针)v0, v1, v2 则 v0*a + v1*b + v2*c = (Px, Py, Pz); (前面v0,v1,v2是点注意了。)
因为:a+b+c = 1;
所以: v0*a + v1*b + v2*c = v0 * (1-b-c) + v1*b + v2*c ;
= b * (v1 - v0) + c * (v2 - v0) + v0; ----------------- 1
假设射线方程式 F(x,y,z) = Orgin + rayVec * t; --------------------------------------2
则射线和P点的交点方程(由1和2): Orgin + rayVec * t = b * (v1 - v0) + c * (v2 - v0) + v0;
列成矩阵形式: 设v1 - v0 = edge1; v2 - v0 = edge2;
Orgin + rayVec * t = b * edge1+ c * edge2 + v0
变一下型:b * edge1 - rayVec * t + c * edge2 = Orgin - v0;
我们设fDist = -t; 去掉负号;
b * edge1 - rayVec * fDist + c * dege2 = Orgin - v0;
矩阵 b * edge1.x - rayVec.x * fDist + c * edge2.x = (Orgin - v0).x;
b * edge1.y - rayVec.y * fDist + c * edge2.y = (Orgin - v0).y;
b * edge1.z - rayVec.z * fDist + c * edge2.z = (Orgin - v0).z;
使用 克莱姆法则求b , fDist, c ;
|edge1.x rayVec.x edge2.x|
分母det = |edge1.y rayVec.y edge2.y| = Dot(edge1, Cross(rayVec, edge2))(是个公式,记住了)
|edge1.z rayVec.z edge2.z|
分子
|(Orgin - v0).x rayVec.x edge2.x|
未知数b的克莱姆分子 = |(Orgin - v0).y rayVec.y edge2.y| = Dot((Orgin - v0), Cross(rayVec, edge2))
|(Orgin - v0).z rayVec.z edge2.z|
|edge1.x (Orgin - v0).x edge2.x|
未知数c的克莱姆分子 = |edge1.y (Orgin - v0).y edge2.y| = Dot(edge1, Cross((Orgin - v0), edge2));
|edge1.z (Orgin - v0).z edge2.z|
|edge1.x rayVec.x (Orgin - v0).x|
未知数t的克莱姆分子 = |edge1.y rayVec.y (Orgin - v0).y| = Dot(edge1, Cross(rayVec, (Orgin - v0));
|edge1.z rayVec.z (Orgin - v0).z|
3个分子分别和det相除就行了.
现在看看Ms的代码:(貌似交换了列的顺序,和上面的稍微有些出入)
Code
bool IntersectTriangle( const D3DXVECTOR3& orig, const D3DXVECTOR3& dir,
D3DXVECTOR3& v0, D3DXVECTOR3& v1, D3DXVECTOR3& v2,
FLOAT* t, FLOAT* u, FLOAT* v )
{
// Find vectors for two edges sharing vert0
D3DXVECTOR3 edge1 = v1 - v0; //我们的edge1
D3DXVECTOR3 edge2 = v2 - v0; //我们的edge1
// Begin calculating determinant - also used to calculate U parameter
D3DXVECTOR3 pvec;
D3DXVec3Cross( &pvec, &dir, &edge2 ); //求det过程中
// If determinant is near zero, ray lies in plane of triangle
FLOAT det = D3DXVec3Dot( &edge1, &pvec ); //求得了det
//这下面注意了,这里用了矩阵的一个性质,用k乘以一个矩阵的某一行或者
某一列时,相当于用k乘以这个矩阵。当然k可以等于-1,于是 .转132
D3DXVECTOR3 tvec;
if( det > 0 )
{
tvec = orig - v0; //
}
else
{
tvec = v0 - orig; //我们的公式可是 orgin - v0 ,这里相当于乘了个-1,相当于矩阵外乘以-1,相当于和det的变号抵消了。
det = -det; // 132 这里分母变负了
}
//上面det変正主要是为了方便后头的比较。
if( det < 0.0001f )
return FALSE;
// Calculate U parameter and test bounds
*u = D3DXVec3Dot( &tvec, &pvec );
//u为重心坐标之一,不可能大于det.
if( *u < 0.0f || *u > det )
return FALSE;
// Prepare to test V parameter
D3DXVECTOR3 qvec;
D3DXVec3Cross( &qvec, &tvec, &edge1 );
//u+v > 1自然剩的一个就为负了,这也不成立。
// Calculate V parameter and test bounds
*v = D3DXVec3Dot( &dir, &qvec );
if( *v < 0.0f || *u + *v > det )
return FALSE;
// Calculate t, scale parameters, ray intersects triangle
*t = D3DXVec3Dot( &edge2, &qvec );
FLOAT fInvDet = 1.0f / det;
*t *= fInvDet;
*u *= fInvDet;
*v *= fInvDet;
return TRUE;
}
下面这个代码直接按公式写。
bool IntersectTriangle( const D3DXVECTOR3& orig, const D3DXVECTOR3& dir,
D3DXVECTOR3& v0, D3DXVECTOR3& v1, D3DXVECTOR3& v2,
FLOAT* t, FLOAT* u, FLOAT* v )
{
// Find vectors for two edges sharing vert0
D3DXVECTOR3 edge1 = v1 - v0; //我们的edge1
D3DXVECTOR3 edge2 = v2 - v0; //我们的edge1
// Begin calculating determinant - also used to calculate U parameter
D3DXVECTOR3 pvec;
D3DXVec3Cross( &pvec, &dir, &edge2 ); //求det过程中
// If determinant is near zero, ray lies in plane of triangle
FLOAT det = D3DXVec3Dot( &edge1, &pvec ); //求得了det
//这下面注意了,这里用了矩阵的一个性质,用k乘以一个矩阵的某一行或者
某一列时,相当于用k乘以这个矩阵。当然k可以等于-1,于是 .转132
D3DXVECTOR3 tvec;
if( det > 0 )
{
tvec = orig - v0; //
}
else
{
tvec = v0 - orig; //我们的公式可是 orgin - v0 ,这里相当于乘了个-1,相当于矩阵外乘以-1,相当于和det的变号抵消了。
det = -det; // 132 这里分母变负了
}
//上面det変正主要是为了方便后头的比较。
if( det < 0.0001f )
return FALSE;
// Calculate U parameter and test bounds
*u = D3DXVec3Dot( &tvec, &pvec );
//u为重心坐标之一,不可能大于det.
if( *u < 0.0f || *u > det )
return FALSE;
// Prepare to test V parameter
D3DXVECTOR3 qvec;
D3DXVec3Cross( &qvec, &tvec, &edge1 );
//u+v > 1自然剩的一个就为负了,这也不成立。
// Calculate V parameter and test bounds
*v = D3DXVec3Dot( &dir, &qvec );
if( *v < 0.0f || *u + *v > det )
return FALSE;
// Calculate t, scale parameters, ray intersects triangle
*t = D3DXVec3Dot( &edge2, &qvec );
FLOAT fInvDet = 1.0f / det;
*t *= fInvDet;
*u *= fInvDet;
*v *= fInvDet;
return TRUE;
}
Code
D3DXVECTOR3 m = v1 - v0;
D3DXVECTOR3 n = v2 - v0;
D3DXVECTOR3 q = orgin - v0;
D3DXVECTOR3 temp;
D3DXVec3Cross(&temp, &n, &vec);
FLOAT det = D3DXVec3Dot(&m, &temp);
if (abs(det) < 0.00001)
{
return FALSE;
}
FLOAT detU = 0;
FLOAT detV = 0;
FLOAT detT = 0;
detU = D3DXVec3Dot(&temp, &q);
u = detU / det;
if (u>1 || u<0)
{
return false;
}
D3DXVec3Cross(&temp, &q, &vec);
detV = D3DXVec3Dot(&temp, &m);
v = detV / det;
if (v<0 || u+v >1.0f)
{
return false;
}
D3DXVec3Cross(&temp, &n, &q);
detT = D3DXVec3Dot(&m, &temp);
t = -detT / det;
return TRUE;
D3DXVECTOR3 m = v1 - v0;
D3DXVECTOR3 n = v2 - v0;
D3DXVECTOR3 q = orgin - v0;
D3DXVECTOR3 temp;
D3DXVec3Cross(&temp, &n, &vec);
FLOAT det = D3DXVec3Dot(&m, &temp);
if (abs(det) < 0.00001)
{
return FALSE;
}
FLOAT detU = 0;
FLOAT detV = 0;
FLOAT detT = 0;
detU = D3DXVec3Dot(&temp, &q);
u = detU / det;
if (u>1 || u<0)
{
return false;
}
D3DXVec3Cross(&temp, &q, &vec);
detV = D3DXVec3Dot(&temp, &m);
v = detV / det;
if (v<0 || u+v >1.0f)
{
return false;
}
D3DXVec3Cross(&temp, &n, &q);
detT = D3DXVec3Dot(&m, &temp);
t = -detT / det;
return TRUE;
求交就完了,剩下的, Orgin 和 rayVec
屏幕上的点
齐次裁剪空间:projPt.x = (screenPt.x-screenWidth/2)/screenWidth*2; (公式1
齐次裁剪空间: projPt.y = (screenPt.y-screenHeight/2)/screenHeight*2; (公式2)
projPt.z = 1.0f(近裁减面的值);
投影矩阵 m_11 x缩放, m_22 y缩放
Orgin在视点空间的坐标为(0,0,0);
它们乘以投影的逆矩阵:Orgin * InverseMatProj; (视点空间)
projPt * InverseMatProj; (视点空间)
转换到模型空间,乘以InverseMatWorldView;
如果你熟悉这几种矩阵变换的话,可以直接操作上面的计算。
最后将它们的值带入即可。
Code
D3DXMATRIX matProj = camera->GetProjMatrix();
x = ((screenX*2.0f)/m_width - 1.0f) / matProj._11;
y = (1.0f - (2.0f*screenY)/m_height) / matProj._22;
z = 1.0f;
D3DXMATRIX matView = camera->GetViewMatrix();
D3DXMATRIX matWorld;
m_dev->GetTransform(D3DTS_WORLD, &matWorld);
D3DXMATRIX matWorldView = matWorld * matView;
D3DXMATRIX inverseMatWorldView;
D3DXMatrixInverse(&inverseMatWorldView, NULL, &matWorldView);
D3DXVECTOR3 pickOrgin, pickVec;
pickVec.x = x*inverseMatWorldView._11 + y*inverseMatWorldView._21 + z*inverseMatWorldView._31;
pickVec.y = x*inverseMatWorldView._12 + y*inverseMatWorldView._22 + z*inverseMatWorldView._32;
pickVec.z = x*inverseMatWorldView._13 + y*inverseMatWorldView._23 + z*inverseMatWorldView._33;
pickOrgin.x = inverseMatWorldView._41;
pickOrgin.y = inverseMatWorldView._42;
pickOrgin.z = inverseMatWorldView._43;
分享知识,共同进步。如需转载注明http://www.cnblogs.com/ttthink
D3DXMATRIX matProj = camera->GetProjMatrix();
x = ((screenX*2.0f)/m_width - 1.0f) / matProj._11;
y = (1.0f - (2.0f*screenY)/m_height) / matProj._22;
z = 1.0f;
D3DXMATRIX matView = camera->GetViewMatrix();
D3DXMATRIX matWorld;
m_dev->GetTransform(D3DTS_WORLD, &matWorld);
D3DXMATRIX matWorldView = matWorld * matView;
D3DXMATRIX inverseMatWorldView;
D3DXMatrixInverse(&inverseMatWorldView, NULL, &matWorldView);
D3DXVECTOR3 pickOrgin, pickVec;
pickVec.x = x*inverseMatWorldView._11 + y*inverseMatWorldView._21 + z*inverseMatWorldView._31;
pickVec.y = x*inverseMatWorldView._12 + y*inverseMatWorldView._22 + z*inverseMatWorldView._32;
pickVec.z = x*inverseMatWorldView._13 + y*inverseMatWorldView._23 + z*inverseMatWorldView._33;
pickOrgin.x = inverseMatWorldView._41;
pickOrgin.y = inverseMatWorldView._42;
pickOrgin.z = inverseMatWorldView._43;