public double intersect(Ray r)
{
double t;
Vector L = r.origin.sub(pos);
double a = r.direction.dot(r.direction);
double b = 2*(r.direction.dot(L));
double c = (L.dot(L)) - (radius*radius);
double disc = b*b - 4*a*c;
if (disc < 0)
return -1;
double distSqrt = Math.sqrt(disc);
double q;
if (b < 0)
q = (-b - distSqrt)/2;
else
q = (-b + distSqrt)/2;
double t0 = q/a;
double t1 = c/q;
if (t0 > t1)
{
double temp = t0;
t0 = t1;
t1 = temp;
}
if (t1 < 0)
return -1;
if (t0 < 0)
t = t1;
else
t = t0;
return t;
}
没有交叉时应该返回-1。
在(5,0,0)处有一个半径为2的球体。 当我传递一条带有原点(0,0,0)和方向(5,0,0).unit的光线时,它会返回3。 当我传递一条带有原点(0,0,0)和方向(5,2,0).unit的光线时,它会返回3.9。 当我传入具有原点(0,0,0)和方向(5,0,1).unit的光线时,即使光线相交,它也会返回-1。 当方向是(5,0,-1).unit时,它返回2.73,即使t不可能小于3并且它应该返回与(5,0,1)相同的东西.unit返回
答案 0 :(得分:1)
我认为用于计算q
的条件不正确:
if (b < 0)
q = (-b - distSqrt)/2;
else
q = (-b + distSqrt)/2;
在这里,你决定b
的标志。你应该计算两个值。很明显,第一个(-b - distSqrt)/2
总是会给出较小的q
值,因为distSqrt
始终是非负的。仅当(-b - distSqrt)/2
为否定时,您应该检查(-b + distSqrt)/2
,在某些情况下可能是肯定的。当光线的原点位于球体内时,将出现这种情况。
t1 = c/q
是必要的吗?当您使用q
的正值较小时,您就完成了(因为a
必须为正数,如果方向是单位向量,则为1
。)
在我的实现中,我以这种方式进行了计算:
double Sphere::getIntersection(Ray ray)
{
Vector v = ray.origin - center;
double b = 2 * dot(ray.dir, v);
double c = dot(v, v) - radius * radius;
double d = b * b - 4 * c;
if(d > 0)
{
double x1 = (-b - sqrt(d)) / 2;
double x2 = (-b + sqrt(d)) / 2;
if(x1 >= 0 && x2 >= 0) return x1;
if(x1 < 0 && x2 >= 0) return x2;
}
return -1;
}
并且运作良好。
答案 1 :(得分:0)
当我使用&#34; ray with origin(0,0,0)和direction(5,0,1).unit&#34;运行该代码时例如,它为我返回3.15979。据我所知,您发布的所有代码都是正确的。我认为这是导致失败的其他实现之一。它可能是你的单位向量计算,你的Vector.sub()方法,Vector.dot()方法等等。
尝试在整个过程中添加打印语句以查看出错的位置。这就是我经常调试这样的事情。
此外,我还将您的代码快速翻译成C ++(因为我不懂Java),如果您愿意,可以将其与之进行比较。它似乎运行良好,这意味着它可能不是你的交叉函数是问题。
我的代码在这里:http://codepad.org/xldbJRKo
我希望这有点帮助!