光线与球体相交的方法不起作用

3
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返回相同的结果。

2个回答

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;
}

而且它运行良好。


0
当我使用您提供的“以原点(0,0,0)和方向(5,0,1)的光线”示例运行该代码时,它对我返回3.15979。据我所知,您发布的所有代码都是正确的。我想这可能是您其他实现中导致失败的原因。这可能是您的单位向量计算、Vector.sub()方法、Vector.dot()方法等。
尝试在整个代码中添加打印语句,以查看出错的位置。这就是我通常调试此类问题的方式。
此外,我快速将您的代码翻译成了C++(因为我不懂Java),您可以进行比较。它似乎能够正常运行,这意味着您的交点函数可能不是问题所在。
我的代码在这里:http://codepad.org/xldbJRKo 希望这能有所帮助!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接