光线与AABB相交问题

光线与AABB相交问题

对于轴对齐的包围盒,可以简单的用两点来表示,第一点为包围盒的左下点,第二点为右上点。
考虑在2D中的一个包围盒,由四条与轴平行的直线$X_0,X_1,Y_0,Y_1$的交点构成,对于光线方程$P(t)=A+tb$,可以计算光线与每个直线的交点的t值,得到$t_{xmin},t_{xmax},t_{ymin},t_{ymax}$。

直线和包围盒相交

通过观察可以发现,只有当$t_x$的范围与$t_y$的范围产生重叠,光线才与包围盒相交。

类比三维空间,只要再计算$t_z$的范围,对$t_{xyz}$进行一下重叠检测,如果存在重叠,那么光线与aabb相交,反之则没有。

当t值存在重叠,则光线和aabb相交

由光线方程,可以得到$t=\frac{x_0-A_x}{b_x}$, 那么可能存在几种问题,一是b=0的情况(光线沿某条轴轴前进),分数下面为0;另一种是光线沿着轴的负向前进,$t_{min},t_{max}$存在先后问题。
第一个浮点数除零问题, c++的浮点数除以0会得到inf,负的浮点数除以0得到-inf,则仍然可以判断$t_{min},t_{max}$。
对于光线沿着负轴前进的问题,只需要用函数min max取一下值就行了,不影响求交点判断。

code

class AABB : hitable {
public:
  virtual bool hit(const ray &r, double t_min, double t_max,
                   record &rec) const override;
  vec3 pMin;
  vec3 pMax;
};

//To judge whether ray hits aabb by compute t's overlap
inline bool AABB::hit(const ray &r, double t_min, double t_max,
                      record &rec) const {
  vec3 dir = r.direction();
  vec3 ori = r.origin();
  for (int i = 0; i < 3; i++) {
    float inv_b = 1. / dir[i];
    float t0 = (pMin[i] - ori[i]) * inv_b;
    float t1 = (pMax[i] - ori[i]) * inv_b;
    // When dir < 0 then swap max,min
    if (inv_b < 0.f) {
      std::swap(t0, t1);
    }
    // find the closest interval
    t_min = t0 > t_min ? t0 : t_min;
    t_max = t1 < t_max ? t0 : t_max;
    // no overlap
    if (t_max < t_min)
      return false;
  }
  return true;
}
END

留言