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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With