Ogre求射线到面的交点函数分析

昨天,看了Ogre的代码,关于取射线到面的交点坐标的函数,研究了半天,怪自己立体几何没学好啊 泪奔 

代码如下:

 //-----------------------------------------------------------------------
    std::pair<bool, Real> Math::intersects(const Ray& ray, const Plane& plane)
    {

        Real denom = plane.normal.dotProduct(ray.getDirection());
        if (Math::Abs(denom) < std::numeric_limits<Real>::epsilon())               

        {
            // Parallel
            return std::pair<bool, Real>(false, 0);
        }
        else
        {
            Real nom = plane.normal.dotProduct(ray.getOrigin()) + plane.d;
            Real t = -(nom/denom);
            return std::pair<bool, Real>(t >= 0, t);
        }
    }

 //-----------------------------------------------------------------------

分析如下:

Plane.normal是取平面的法向量

ray.getDirection()是取射线的方向向量

函数dotProduct()是用来做向量的点乘,函数结构如下:

        inline Real dotProduct(const Vector3& vec) const
        {
            return x * vec.x + y * vec.y + z * vec.z;
        }

把返回的点乘的值赋予demon,通过这个值可以来判断射线与平面是否平行。

//-----------------------------------------邪恶的分割线------------------------------------------

数学原理:两个向量相乘 a*b = |a|*|b|cosθ , 因为a和b向量都是方向向量,标量值不为0,θ就是两个方向向量之间的角度,当cosθ 趋近于0时,θ角度趋近于90°,由此可以说明a和b垂直。(高中的知识啊。。。)

//-----------------------------------------邪恶的分割线------------------------------------------

函数中把点成的值在用Math::Abs(denom) 其实就是fabs()函数,取其绝对值,在跟std::numeric_limits<Real>::epsilon()比较,这里的epslion是一个趋近于0的数,形如:

#define FLT_EPSILON     1.192092896e-07F        /* smallest such that 1.0+FLT_EPSILON != 1.0 */

当demon的值比其还小的时候,就可以近似的认为两个向量点乘的值为0,即两个向量垂直。

由于两个都是方向向量,所以,射线和平面就平行了。返回一个bool类型为false的值,和一个real值为0(也就是下面说的t值)。

//-----------------------------------------邪恶的分割线------------------------------------------

下面就是重点部分了,如果不平行,先恶补一下数学的知识 郁闷 

一条射线可以表示为:p(t) = p1+tu ;其中,p1为起点坐标,u为射线的方向向量,t为参数。如果t = 0,得到的是起点的坐标。

一个平面可以表示为:np+d = 0;其中,n为平面的法向量,p为平面上任意一点,d为参数。

如果射线与平面相交,把两个表达式合并,即:n*(p1+tu)+d = 0;经过变化以后得:t = -((d+n*p1)/(nu))

//-----------------------------------------邪恶的分割线------------------------------------------

现在,在把公式和代码比较就很好理解了。

Real nom = plane.normal.dotProduct(ray.getOrigin()) + plane.d;  // 求的就是 d+n*p1的值,ray.getOrigin()得到的就是起点的坐标,plane.d得到的就是平面的d值。

Real t = -(nom/denom);   //denom上面已将求过了,就是n*u,此代码就实现了t = -((d+n*p1)/(nu))

函数返回bool值,且t要大于等于0为真,如果t小于0,就得到了一条三维空间的直线(就不是射线了 微笑 ) ,然后在返回t值。

然后利用p(t) = p1+tu 就可以很容易的求出交点坐标了 微笑 

 

经过这次教训,要好好恶补一下数学了。 疑惑 

    

你可能感兴趣的:(Math,vector,parallel)