夏天/isummer

Sun of my life !Talk is cheap, Show me the code! 追风赶月莫停留,平芜尽处是春山~

博客园 首页 新随笔 联系 管理

点是否再三角形面之内的位置关系判定

  常用的方法是,如果点在三角形内部,则连接与三角形的三个顶点,并计算组成的组成矢量的角度和,如果为2pei, 则在三角形内部,否则不再三角形内不。理论上该方法可行,但是效率非常慢。

  因为要计算夹角,需要多次计算平方根。

1. 判定是否同边的技术原理(Same Side Technique)

  快速且简洁的方法如下:

   

  如图,三角形,线段AB, BC, and CA,每一条都半分剩下的部分,且剩下的在三角形的外部部分,我们可以利用这个特性做如下处理:

  如果一个点在三角形内部,则点必然在AB下面, BC左面,AC右边。如果不符合这个特性,则判定结果比在三角形外面,因此这个判定很快。

(1)计算一个点在一个线段的位置关系

  

  通过叉积的方式,用[B - A ]和[p - A ]组成的叉积,即AB * Ap, 如果结果为正(叉积朝向屏幕外面),则p 在AB的左边, 否则(叉积朝向屏幕里面)在AB的右边。

  因为在3D空间中,AB方向线段,与点p的位置关系,可以借助点C来判定,因为ABC组成一个平面,因此C可以作为参考值。

  继而,判定任意点p, 如果[B - A ]和[p - A ]叉积方向,与[B - A ]和[C - A]的叉积方向不相同,则可直接判定没有在三角形内部; 如果与叉积方向相同,则可以继续对余下的边进行同样的判定方式。

  判断两个叉积结果的方向是否同向,使用点乘的方式。

  实现方面的方法非常容易,可以实现一个方法来判定是否在相同的边的位置。在判定的时候可以分别调用:

function SameSide(p1,p2, a,b)
    cp1 = CrossProduct(b-a, p1-a)
    cp2 = CrossProduct(b-a, p2-a)
    if DotProduct(cp1, cp2) >= 0 then return true
    else return false

function PointInTriangle(p, a,b,c)
    if SameSide(p,a, b,c) and SameSide(p,b, a,c)
        and SameSide(p,c, a,b) then return true
    else return false

   这样的方法非常高效,不需要计算平方根,弧度反求,等等。

2 判定中心的技术原理(Barycentric Technique)

  还有一种方法可以执行的更快,原理更简单的方法,与数学知识有一点点关联。

  因为三角形的三个点确定一个平面,在这个平面中,可以任意选择一点,其他的点都是作为相对位置关系。如以点A为例,然后选定[C-A][B-A]两个向量作为该平面的坐标分量,因此三角形平面中任意一点都可以用这连个向量AB,AC表示。

  即  P = A + u * (C - A) + v * (B - A)

注意:如果系数u或者v都< 0, 则p点必然在三角形区域之外。同样,如果u 或者v > 1, 则 点 p则在三角形之外,最后,如果 u + v > 1, 同样越过BC边,而到三角形之外

  

  因此可以计算出P在u,v系数下的表示。但是怎么获取p点在上述公式中的系数u,v呢?

  可以使用下述的公式推导:

    // We have two unknowns (u and v) so we need two equations to solve
    // for them.  Dot both sides by v0 to get one and dot both sides by
    // v1 to get a second.
    (v2) . v0 = (u * v0 + v * v1) . v0
    (v2) . v1 = (u * v0 + v * v1) . v1

    // Distribute v0 and v1
    v2 . v0 = u * (v0 . v0) + v * (v1 . v0)
    v2 . v1 = u * (v0 . v1) + v * (v1 . v1)

    // Now we have two equations and two unknowns and can solve one 
    // equation for one variable and substitute into the other.  Or
    // if you're lazy like me, fire up Mathematica and save yourself
    // some handwriting.
    Solve[v2.v0 == {u(v0.v0) + v(v1.v0), v2.v1 == u(v0.v1) + v(v1.v1)}, {u, v}]
    u = ((v1.v1)(v2.v0)-(v1.v0)(v2.v1)) / ((v0.v0)(v1.v1) - (v0.v1)(v1.v0))
    v = ((v0.v0)(v2.v1)-(v0.v1)(v2.v0)) / ((v0.v0)(v1.v1) - (v0.v1)(v1.v0))

  下面是用于编程的快速实现:

  

// Compute vector,计算向量AC, AB, CP    
v0 = C - A
v1 = B - A
v2 = P - A

// Compute dot products 计算点乘
dot00 = dot(v0, v0)
dot01 = dot(v0, v1)
dot02 = dot(v0, v2)
dot11 = dot(v1, v1)
dot12 = dot(v1, v2)

// Compute barycentric coordinates 计算系数坐标
invDenom = 1 / (dot00 * dot11 - dot01 * dot01)
u = (dot11 * dot02 - dot01 * dot12) * invDenom
v = (dot00 * dot12 - dot01 * dot02) * invDenom

// Check if point is in triangle 检测
return (u >= 0) && (v >= 0) && (u + v < 1)

 

技巧:

(1)判定相交性:

  一般情况下, 空间三角形三个空间坐标确定三角形平面在三维空间的姿态。但是如果每个顶点,只计算(Y,Z)分量,则将三角形转化为YZ平面空间内的三角形。

  对于三给空间中的一条射线如(y=Y1, z=Z1),即在(Y,Z)确定的平面相当于一个(Y1,Z1)

  因此,判定射线与三角形平面的相交性,即转化为判定二维三角形平面中的点与三角形的位置关系。

(2)如果相交,则求交点

  这样可以利用上述公式,求出交点。即得到与UV坐标,然后对原三角形三个定点,利用公式,仅仅对于X分量计算,即可求得交点的Xcut坐标。

  因此交点即为:(Xcut,Y,Z),空间坐标点。

  

  

 

 

 

 

 

endl;

  

  

posted on 2017-08-02 14:23  夏天/isummer  阅读(2969)  评论(0编辑  收藏  举报