Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >射线盒相交理论

射线盒相交理论
EN

Stack Overflow用户
提问于 2010-04-01 21:35:31
回答 5查看 12.1K关注 0票数 22

我想确定光线和长方体的交点。长方体由其最小三维坐标和最大三维坐标定义,射线由其原点和它所指向的方向定义。

目前,我正在为长方体的每个面形成一个平面,并且我正在使光线与平面相交。如果光线与平面相交,则检查交点是否实际上在长方体的表面上。如果是,我检查它是否是该光线最近的交叉点,并返回最近的交叉点。

我检查平面交点是否在盒子表面上的方法是通过一个函数

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
bool PointOnBoxFace(R3Point point, R3Point corner1, R3Point corner2)
{
  double min_x = min(corner1.X(), corner2.X());
  double max_x = max(corner1.X(), corner2.X());
  double min_y = min(corner1.Y(), corner2.Y());
  double max_y = max(corner1.Y(), corner2.Y());
  double min_z = min(corner1.Z(), corner2.Z());
  double max_z = max(corner1.Z(), corner2.Z());
  if(point.X() >= min_x && point.X() <= max_x && 
     point.Y() >= min_y && point.Y() <= max_y &&
     point.Z() >= min_z && point.Z() <= max_z)
     return true;

  return false;
}

其中,corner1是该长方体表面的矩形的一个角,corner2是另一个角。我的实现在大多数情况下都可以工作,但有时它会给我错误的交叉点。如图所示:

该图像显示了来自相机眼睛的光线照射到盒子表面。其他光线是长方体曲面的法线。可以看到,特定的一条光线(实际上是看到的法线)从盒子的“背面”出来,而法线应该从盒子的顶部出来。这似乎很奇怪,因为有多条其他光线正确地击中了长方体的顶部。

我想知道我检查交点在盒子上的方式是否正确,或者我是否应该使用其他算法。

谢谢。

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2010-04-01 23:24:18

通过epsilon增加对象实际上并不是一个很好的方法,因为现在在长方体的边缘有一个epsilon大小的边界,光线可以通过它。因此,您将摆脱这组(相对常见的)奇怪的错误,并最终得到另一组(更罕见的)奇怪的错误。

我假设你已经想象你的光线沿着它的向量以一定的速度移动,并找到与每个平面相交的时间。因此,例如,如果在x=x0处与平面相交,并且光线从(0,0,0)(rx,ry,rz)方向移动,则相交时间为t = x0/rx。如果t是负的,忽略它--你走的是另一条路。如果t为0,您必须决定如何处理这种特殊情况--如果您已经在飞机上,是从飞机上反弹,还是穿过它?您可能还希望将rx==0作为特殊情况处理(这样您就可以命中盒子的边缘)。

不管怎样,现在你有了你击中飞机的确切坐标:它们是(t*rx , t*ry , t*rz)。现在你可以读出t*ryt*rz是否在它们需要的矩形内(即沿着这些轴的立方体的最小和最大之间)。你不测试x坐标,因为你已经知道你再次击中它,你必须决定是否/如何处理击中角作为特殊情况。此外,现在您可以按时间对与各种曲面的碰撞进行排序,并选择第一个曲面作为您的碰撞点。

这允许您在不求助于任意ε因子的情况下,计算光线是否以及在何处与立方体相交,达到浮点算法所能达到的精度。

因此,您只需要三个函数:一个函数用于测试在yz中是否命中(假设您命中x ),而对应的xzxy函数(假设您分别命中yz )。

编辑:添加到中的代码(详细地)显示了如何对每个轴进行不同的测试:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#define X_FACE 0
#define Y_FACE 1
#define Z_FACE 2
#define MAX_FACE 4

// true if we hit a box face, false otherwise
bool hit_face(double uhit,double vhit,
                 double umin,double umax,double vmin,double vmax)
{
  return (umin <= uhit && uhit <= umax && vmin <= vhit && vhit <= vmax);
}

// 0.0 if we missed, the time of impact otherwise
double hit_box(double rx,double ry, double rz,
                double min_x,double min_y,double min_z,
                double max_x,double max_y,double max_z)
{
  double times[6];
  bool hits[6];
  int faces[6];
  double t;
  if (rx==0) { times[0] = times[1] = 0.0; }
  else {
    t = min_x/rx;
    times[0] = t; faces[0] = X_FACE; 
    hits[0] = hit_box(t*ry , t*rz , min_y , max_y , min_z , max_z);
    t = max_x/rx;
    times[1] = t; faces[1] = X_FACE + MAX_FACE;
    hits[1] = hit_box(t*ry , t*rz , min_y , max_y , min_z , max_z);
  }
  if (ry==0) { times[2] = times[3] = 0.0; }
  else {
    t = min_y/ry;
    times[2] = t; faces[2] = Y_FACE;
    hits[2] = hit_box(t*rx , t*rz , min_x , max_x , min_z , max_z);
    t = max_y/ry;
    times[3] = t; faces[3] = Y_FACE + MAX_FACE;
    hits[3] = hit_box(t*rx , t*rz , min_x , max_x , min_z , max_z);
  }
  if (rz==0) { times[4] = times[5] = 0.0; }
  else {
    t = min_z/rz;
    times[4] = t; faces[4] = Z_FACE;
    hits[4] = hit_box(t*rx , t*ry , min_x , max_x , min_y , max_y);
    t = max_z/rz;
    times[5] = t; faces[5] = Z_FACE + MAX_FACE;
    hits[5] = hit_box(t*rx , t*ry , min_x , max_x , min_y , max_y);
  }
  int first = 6;
  t = 0.0;
  for (int i=0 ; i<6 ; i++) {
    if (times[i] > 0.0 && (times[i]<t || t==0.0)) {
      first = i;
      t = times[i];
    }
  }
  if (first>5) return 0.0;  // Found nothing
  else return times[first];  // Probably want hits[first] and faces[first] also....
}

(我只是输入了这段代码,并没有编译它,所以要小心bug。)(编辑:刚刚更正了i -> first。)

无论如何,重点是分别处理这三个方向,并测试是否在(u,v)坐标中的右侧框内发生了碰撞,其中(u,v)是(x,y)、(x,z)或(y,z),这取决于您击中的是哪个平面。

票数 17
EN

Stack Overflow用户

发布于 2010-04-01 23:57:36

PointOnBoxFace应该是二维检查,而不是三维检查。例如,如果您正在针对z = z_min平面进行测试,那么您应该只需要将xy与它们各自的边界进行比较。您已经知道z坐标是正确的。当你“重新检查”第三个坐标时,浮点精度可能会给你带来麻烦。

例如,如果z_min为1.0,则首先针对该平面进行测试。找到(xy,0.999999999)的交点。现在,即使xy在界限之内,z也不是很正确。

票数 2
EN

Stack Overflow用户

发布于 2010-04-01 21:47:30

代码看起来没问题。尝试找到这条特定的射线并对其进行调试。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2563849

复制
相关文章

相似问题

添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文