本文主要是介绍射线与三角面相交判定,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
转: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
*/
这篇关于射线与三角面相交判定的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!