光线绑定平面相交

时间:2019-05-26 18:57:20

标签: c++ math linear-algebra intersection raytracing

我正在尝试在业余时间编写光线跟踪器。当前正在尝试进行射线边界平面相交。

我的程序已经在无限平面上工作。我正在尝试为非无限平面计算数学。尝试过使用google,但是所有资源都只讨论无限平面。

我的飞机有一个拐角点(称为位置),两个矢量(u和v)从拐角点延伸(它们的长度对应于边的长度)。射线具有原点和方向。

首先,我用公式计算出一个无限平面的交点

t = normal * (position - origin) / (normal * direction)

法线被计算为u和v的叉积。 然后加上公式

origin + direction * t

我得到了交点本身。

下一步是检查此点是否在矩形的边界内,这就是我遇到的问题。

我的想法是获得从平面角到交点延伸的相对矢量intersection - position,然后将其转换为u,法线和v的新基,然后检查转换后的向量比u和v向量要短。

bool BoundedPlane::intersect(const Vec3f &origin, const Vec3f &direction, float &t) const {
    t = normal * (position - origin) / (normal * direction);
    Vec3f relative = (origin + direction * t) - position;

    Mat3f transform{
        Vec3f(u.x, normal.x, v.x),
        Vec3f(u.y, normal.y, v.y),
        Vec3f(u.z, normal.z, v.z)
    };

    Vec3f local = transform.mul(relative);
    return t > 0 && local.x >= 0 && local.x <= u.x && local.z <= 0 && local.z <= v.z;

}

最后,我检查t是否大于0,这意味着交点在相机的前面,并且向量的长度是否在边界之内。这给了我一条怪异的线:

weird line

飞机应显示在球体下方,如下所示:

like this

(用于手动检查以查看数字是否正确显示是否正确)。

我不确定自己在做什么错,是否有更简便的方法来检查界限。预先感谢。

编辑1:

我将转换矩阵计算移到了构造函数中,所以交集测试是:

bool BoundedPlane::intersect(const Vec3f &origin, const Vec3f &direction, float &t) const {
    if (!InfinitePlane::intersect(origin, direction, t)) {
        return false;
    }

    Vec3f local = transform.mul((origin + direction * t) - position);

    return local.x >= 0 && local.x <= 1 && local.z >= 0 && local.z <= 1;
}

变换成员是变换矩阵的逆。

1 个答案:

答案 0 :(得分:1)

我可以建议另一种方法吗?考虑原点的框架 position和基向量

u = { u.x, u.y, u.z }  
v = { v.x, v.y, v.z }  
direction = { direction.x, direction.y, direction.z} 

步骤1:形成矩阵

M = {
      {u.x,  v.x,  direction.x},
      {u.y,  v.y,  direction.y},
      {u.z,  v.z,  direction.z} 
    }

步骤2:计算向量w,它是3 x 3线性方程组系统的解决方案

M * w = origin - position,即

w = inverse(M) * (origin - position);

确保directionu, v不共面,否则不存在交点且inverse(M)不存在。

步骤3:,如果0.0 <= w.x && w.x <= 1.0 && 0.0 <= w.y && w.y <= 1.0,则该线与矢量u, v所跨越的平行四边形相交,并且交点为

w0 = { w.x, w.y , 0 };

intersection = position + M * w0; 

否则,该线不与向量u, v跨过的平行四边形相交

此算法的思想是考虑(非正交)帧position, u, v, direction。然后,矩阵M会更改此新帧的坐标中的所有内容。在此框架中,线是垂直的,平行于“ z-”轴,点origin的坐标为w,穿过w的垂直线与平面在{{1 }}。

编辑1:这是3x3矩阵逆矩阵的模板公式:

如果原始矩阵M为

w0

逆是

a  b  c

d  e  f

g  h  i

其中

(1 / det(M)) * { 
                 {e*i - f*h,     c*h - b*i,     b*f - c*e},

                 {f*g - d*i,     a*i - c*g,     c*d - a*f},

                 {d*h - e*g,     b*g - a*h,     a*e - b*d},
                } 

是M的决定因素。

因此反演算法可以如下:

给出

det(M) = a*(e*i - f*h) + b*(f*g - d*i) + c*(d*h - e*h)
  1. 计算
M = {
      {a,  b,  c},
      {d,  e,  f},
      {g,  h,  i},
    }
  1. 计算
inv_M = { 
           {e*i - f*h,     c*h - b*i,     b*f - c*e},

           {f*g - d*i,     a*i - c*g,     c*d - a*f},

           {d*h - e*g,     b*g - a*h,     a*e - b*d},
         };  
  1. M的返回逆矩阵
det_M = a*inv_M[1][1] + b*inv_M[2][1] + c*inv_M[3][1]; 

编辑2:让我们尝试另一种方法以加快处理速度。

步骤1:对于由点inv_M = (1/det_M) * inv_M; 以及两个向量positionu确定的每个平面,预先计算以下数量:

v

步骤2:现在,对于给定的点normal = cross(u, v); u_dot_u = dot(u, u); u_dot_v = dot(u, v); v_dot_v = dot(v, v); // all these need to be computed only once for the u and v vectors det = u_dot_u * v_dot_v - u_dot_v * u_dot_v; // again only once per u and v 和方向origin的线,像以前一样,计算与平面的交点directionint_pointu撰写:

v

第3步:计算

t = dot(normal,  position - origin) / dot(normal, direction);

int_point = origin + t * direction;

rhs = int_point - position;

第4步:

u_dot_rhs = dot(u, rhs);

v_dot_rhs = dot(v, rhs);

w1 = (v_dot_v * u_dot_rhs - u_dot_v * v_dot_rhs) / det;

w2 = (- u_dot_v * u_dot_rhs + u_dot_u * v_dot_rhs) / det;

所以我在这里所做的基本上是找到线if (0 < = w1 && w1 <= 1 && 0 < = w2 && w2 <= 1 ){ int_point is in the parallelogram; } else{ int_point is not in the parallelogram; } origin, direction给定的平面的交点并将自己限制在该平面上,这使我可以在2D而不是3D中工作。我代表

position,  u,  v

并通过将该向量表达式与基础向量int_point = position + w1 * u + w2 * v; rhs = int_point - position = w1 * u + w2 * v w1进行点乘来找到w2u,这将导致2x2线性系统直接解决。