Question

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

It should return -1 when there is no intersection.

There is a sphere at (5,0,0) with a radius of 2. When I pass a ray with origin (0,0,0) and direction (5,0,0).unit, it returns 3 as it should. When I pass a ray with origin (0,0,0) and direction (5,2,0).unit, it returns 3.9 as it should. When I pass a ray with origin (0,0,0) and direction (5,0,1).unit, it returns -1, even though the ray intersects. When the direction is (5,0,-1).unit, it returns 2.73, even though it is not possible for t to be less than 3 and it should return the same thing as (5,0,1).unit returns.

Was it helpful?

Solution 2

When I run that code with your "ray with origin (0,0,0) and direction (5,0,1).unit" example, it returns 3.15979 for me. From what I can tell all the code you posted is correct. I imagine it's one of your other implementations that's causing the failure. It could be your unit vector calculation, your Vector.sub() method, Vector.dot() method, etc.

Try adding print statements throughout to see where it goes wrong. That's how I usually debug something like this.

Also I did a quick translation of your code into C++ (because I don't know java) that you can compare with if you like. It seems to function fine, which means that it's likely not your intersection function that is the problem.

My code is here: http://codepad.org/xldbJRKo

I hope this helps a little bit!

OTHER TIPS

I think the condition used to calculate q is not right:

if (b < 0)
    q = (-b - distSqrt)/2;
else
    q = (-b + distSqrt)/2;

Here, you're deciding upon the sign of b. You should calculate both the values. It's clear that the first one, (-b - distSqrt)/2 would always give the smaller value of q, because distSqrt is always non-negative. Only if (-b - distSqrt)/2 is negative, you should check (-b + distSqrt)/2 which might be positive in some cases. This case will appear when the origin of the ray is located inside the sphere.

And is the t1 = c/q thing necessary? When you have the smaller positive value of q, you are done (because a must be positive, and 1 if the direction is an unit vector).

In my implementation, I did the calculation this way:

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

and it worked well.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top